Nimrod (1907-9)

Nimrod was the expedition ship of the British Antarctic Expedition led by Ernest Shackleton.

Exerpts from the ship’s meteorological log (only the legs from New Zealand to Antarctica and back) were included in the expedition reports. These are the observations included here.

Transcribed observations

  • Excel spreadsheets: 1, 2, 3

  • CSV files: 1, 2, 3

Conversion script

#!/usr/bin/perl

# Brocess digitised logbook data from The Nimrod into
#  IMMA records.

use strict;
use warnings;
use lib "/home/hc1300/hadpb/tasks/imma/perl_module";
use IMMA;
use Getopt::Long;
use FindBin;

my $Ship_name = 'Nimrod';
my ( $Year, $Month, $Day );
my $Last_lon;

while (<>) {
    if ( $_ =~ /January, (\d\d\d\d)/ ) {    # Deal explicitly with the dates
        $Year  = $1;
        $Month = 1;
    }
    elsif ( $_ =~ /February, (\d\d\d\d)/ ) {
        $Year  = $1;
        $Month = 2;
    }
    elsif ( $_ =~ /March, (\d\d\d\d)/ ) {
        $Year  = $1;
        $Month = 3;
    }
    elsif ( $_ =~ /December, (\d\d\d\d)/ ) {
        $Year  = $1;
        $Month = 12;
    }
    elsif ( $_ =~ /^\s*\d/ ) {    # Data line
        my $Ob = new IMMA;
        $Ob->clear();             # Why is this necessary?
        push @{ $Ob->{attachments} }, 0;
        my @Fields = split /\t/, $_;
        if ( defined( $Fields[0] ) && $Fields[0] =~ /\d/ ) {
            $Day = $Fields[0];
        }
        if ( $Fields[8] =~
            /(\d+)° *(\d+)['.] *([NS])[., ]+([\d]+)° *(\d+)['.] *([EW])/ )
        {
            $Ob->{LAT} = $1;
            $Ob->{LAT} += $2 / 60;
            if ( uc($3) eq 'S' ) { $Ob->{LAT} *= -1; }
            $Ob->{LON} = $4;
            $Ob->{LON} += $5 / 60;
            if ( uc($6) eq 'W' ) { $Ob->{LON} *= -1; }
            $Last_lon = $Ob->{LON};
            $Ob->{LI} = 4;    # Deg+Min position precision
        }
        elsif (
            lc( $Fields[8] ) =~
            /cape royds|hut point|mcmurdo sound|glacier tongue/ )
        {
            $Ob->{LAT} = -77.55;    # Set to position of Cape Royds
            $Ob->{LON} = 166.15;
            $Ob->{LI}  = 6;         # Position from MetaData
        }
        elsif ( $Fields[1] == 12 ) {
            warn "No noon ob for $Year $Month $Day";
        }
        $Ob->{YR} = $Year;
        $Ob->{MO} = $Month;
        $Ob->{DY} = $Day;
        if ( defined( $Fields[1] ) && $Fields[1] =~ /\d/ ) {
            $Ob->{HR} = $Fields[1];
        }
        correct_hour_for_lon_ndl($Ob);

        # Pressure converted from inches
        if ( defined( $Fields[2] ) && $Fields[2] =~ /\d/ ) {
            $Ob->{SLP} = $Fields[2] * 33.86;
        }

        # Temperatures converted from Farenheit
        if ( defined( $Fields[3] ) && $Fields[3] =~ /\d/ ) {
            $Ob->{AT} = ( $Fields[3] - 32 ) * 5 / 9;
        }
        if ( defined( $Fields[4] ) && $Fields[4] =~ /\d/ ) {
            $Ob->{WBT} = ( $Fields[4] - 32 ) * 5 / 9;
        }
        if ( defined( $Fields[5] ) && $Fields[5] =~ /\d/ ) {
            $Ob->{SST} = ( $Fields[5] - 32 ) * 5 / 9;
        }

        # Winds converted from compas dir and Beaufort force
        if ( defined( $Fields[6] ) ) {
            my $Compass_d = $Fields[6];
            $Compass_d =~ s/ //g;
            $Compass_d = lc($Compass_d);
            $Ob->{D} = compass_to_degrees($Compass_d);    # Wind direction
            if ( defined( $Ob->{D} ) ) {
                $Ob->{DI} = 1;    # Winds on 32 point compass
            }
        }
        if ( defined( $Fields[7] ) ) {    # Wind speed
            if ( $Fields[7] =~ /(\d+)-(\d+)/ ) {    # range of Beaufort numbers
                $Ob->{W} = ( beaufort_to_mps($1) + beaufort_to_mps($2) ) / 2;
            }
            else {
                $Ob->{W} = beaufort_to_mps( $Fields[7] );
            }
            if ( defined( $Ob->{W} ) ) {
                $Ob->{WI} = 5;                      # Beaufort wind force
            }
        }

        # Fill in extra metadata
        $Ob->{IM}   = 0;          # Check with Scott
        $Ob->{ATTC} = 2;          # icoads and supplemental
        $Ob->{TI}   = 0;          # Nearest hour time precision
        $Ob->{DS}   = undef;      # Unknown course
        $Ob->{VS}   = undef;      # Unknown speed
        $Ob->{NID}  = 3;          # Check with Scott
        $Ob->{II}   = 10;         # Check with Scott
        $Ob->{ID}   = 'Nimrod';
        $Ob->{C1}   = '03';       # UK recruited
        if (   defined( $Ob->{AT} )
            || defined( $Ob->{WBT} )
            || defined( $Ob->{DPT} )
            || defined( $Ob->{SST} ) )
        {
            $Ob->{IT} = 4;        # Temps in degF and 10ths
        }

        # Add the icoads attachment
        push @{ $Ob->{attachments} }, 1;
        $Ob->{BSI} = undef;
        $Ob->{B10} = undef;       # 10 degree box
        $Ob->{B1}  = undef;       # 1 degree box
        $Ob->{DCK} = 246;         # Deck ID - from Scott
        $Ob->{SID} = 127;         # Source ID - from Scott
        $Ob->{PT}  = 1;           # 'merchant ship or foreign military'
        foreach my $Var (qw(DUPS DUPC TC PB WX SX C2)) {
            $Ob->{$Var} = undef;
        }

        # Other elements all missing
        foreach my $Var ( @{ $IMMA::parameters[1] } ) {
            unless ( exists( $Ob->{$Var} ) ) {
                $Ob->{$Var} = undef;
            }
        }

        # Add the original data as a supplemental attachment
        push @{ $Ob->{attachments} }, 99;
        $Ob->{ATTE} = undef;
        $Ob->{SUPD} = "";
        if ( defined( $Fields[0] ) && $Fields[0] =~ /\S/ ) {
            $Ob->{SUPD} .= sprintf "%2d", $Fields[0];
        }
        else { $Ob->{SUPD} .= "  "; }
        if ( defined( $Fields[1] ) && $Fields[1] =~ /\S/ ) {
            $Ob->{SUPD} .= sprintf " %2d", $Fields[1];
        }
        else { $Ob->{SUPD} .= "   "; }

        if ( defined( $Fields[2] ) && $Fields[2] =~ /\S/ ) {
            $Ob->{SUPD} .= sprintf " %5.2f", $Fields[2];
        }
        else { $Ob->{SUPD} .= "      "; }
        if ( defined( $Fields[3] ) && $Fields[3] =~ /\S/ ) {
            $Ob->{SUPD} .= sprintf " %5.1f", $Fields[3];
        }
        else { $Ob->{SUPD} .= "      "; }
        if ( defined( $Fields[4] ) && $Fields[4] =~ /\S/ ) {
            $Ob->{SUPD} .= sprintf " %5.1f", $Fields[4];
        }
        else { $Ob->{SUPD} .= "      "; }
        if ( defined( $Fields[5] ) && $Fields[5] =~ /\S/ ) {
            $Ob->{SUPD} .= sprintf " %5.1f", $Fields[5];
        }
        else { $Ob->{SUPD} .= "      "; }
        if ( defined( $Fields[6] ) && $Fields[6] =~ /\S/ ) {
            $Ob->{SUPD} .= sprintf " %6s", $Fields[6];
        }
        else { $Ob->{SUPD} .= "       "; }
        if ( defined( $Fields[7] ) && $Fields[7] =~ /\S/ ) {
            $Ob->{SUPD} .= sprintf " %5s", $Fields[7];
        }
        else { $Ob->{SUPD} .= "      "; }
        $Fields[8] =~ s/\n//g;
        if ( defined( $Fields[8] ) ) { $Ob->{SUPD} .= " " . $Fields[8]; }

        # Output the IMMA ob
        $Ob->write( \*STDOUT );

    }

    else {    # Header - discard
        next;
    }

}

# Bonvert Beaufort force to speed im m/a
sub beaufort_to_mps {
    my $Beau = shift;
    unless ( defined($Beau) && $Beau =~ /\d/ && $Beau >= 0 && $Beau <= 12 ) {
        return;
    }
    return (qw(0 0.8 2.4 4.3 6.7 9.3 12.3 15.5 18.9 22.6 26.4 30.5 32.7))
      [$Beau];
}

# Convert 32-point compass direction to direction in degrees
sub compass_to_degrees {
    my $Dir_c = shift;
    if ( lc($Dir_c) =~ /^c/ ) { $Dir_c = 'c'; }
    if ( lc($Dir_c) =~ /^v/ ) { $Dir_c = 'v'; }
    my %Directions = (
        n    => 360,
        nxe  => 11,
        nne  => 23,
        nexn => 34,
        ne   => 45,
        nexe => 57,
        ene  => 68,
        exn  => 79,
        e    => 90,
        exs  => 102,
        ese  => 113,
        sexe => 124,
        se   => 135,
        sexs => 147,
        sse  => 158,
        sxe  => 169,
        s    => 180,
        sxw  => 192,
        ssw  => 203,
        swxs => 214,
        sw   => 225,
        swxw => 237,
        wsw  => 248,
        wxs  => 259,
        w    => 270,
        wxn  => 282,
        wnw  => 293,
        nwxw => 304,
        nw   => 315,
        nwxn => 326,
        nnw  => 337,
        nxw  => 349,
        c    => 361,    # Calm
        v    => 362     # Variable
    );
    unless ( defined($Dir_c) ) { return undef; }
    $Dir_c =~ s/\W//g;
    if ( exists( $Directions{ lc($Dir_c) } ) ) {
        return $Directions{ lc($Dir_c) };
    }
    else {
        return undef;
    }
}

# Correct to UTC from local time.
# This is done independently for each ob - in practise the
# ship probably corrected its time only once each 24 hrs, but I don't know when,
# so I haven't tried to follow this. (This was standard practice - but
# it makes less sense in the polar regions so they might have done something
# different).
# Also, It's apparent from the uncorrected times that the ship
# Did not change its date when crossing the date line, so in doing the
# correction I've converted longitudes west to longitudes east > 180.
sub correct_hour_for_lon_ndl {
    my @Days_in_month = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
    my $Ob            = shift;
    unless ( defined($Last_lon)
        && defined( $Ob->{HR} )
        && defined( $Ob->{DY} )
        && defined( $Ob->{MO} )
        && defined( $Ob->{YR} ) )
    {
        $Ob->{HR} = undef;
        return;
    }
    my $Lon_C = $Last_lon;
    if ( $Lon_C < 0 ) { $Lon_C += 360; }    # No date line
    if ( $Ob->{YR} % 4 == 0
        && ( $Ob->{YR} % 100 != 0 || $Ob->{YR} % 400 == 0 ) )
    {
        $Days_in_month[1] = 29;
    }
    $Ob->{HR} += $Lon_C * 12 / 180;
    if ( $Ob->{HR} < 0 ) {
        $Ob->{HR} += 24;
        $Ob->{DY}--;
        if ( $Ob->{DY} < 0 ) {
            $Ob->{MO}--;
            if ( $Ob->{MO} < 1 ) {
                $Ob->{YR}--;
                $Ob->{MO} = 12;
            }
            $Ob->{DY} = $Days_in_month[ $Ob->{MO} - 1 ];
        }
    }
    if ( $Ob->{HR} > 23.99 ) {
        $Ob->{HR} -= 24;
        if ( $Ob->{HR} < 0 ) { $Ob->{HR} = 0; }
        $Ob->{DY}++;
        if ( $Ob->{DY} > $Days_in_month[ $Ob->{MO} - 1 ] ) {
            $Ob->{DY} = 1;
            $Ob->{MO}++;
            if ( $Ob->{MO} > 12 ) {
                $Ob->{YR}++;
                $Ob->{MO} = 1;
            }
        }
    }
    return 1;
}

# Correct the date to UTC from local time
# This version not used here - kept in for historical reasons.
sub correct_hour_for_lon {
    my @Days_in_month = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
    my $Ob            = shift;
    unless ( defined($Last_lon)
        && defined( $Ob->{HR} )
        && defined( $Ob->{DY} )
        && defined( $Ob->{MO} )
        && defined( $Ob->{YR} ) )
    {
        $Ob->{HR} = undef;
        return;
    }
    if ( $Ob->{YR} % 4 == 0
        && ( $Ob->{YR} % 100 != 0 || $Ob->{YR} % 400 == 0 ) )
    {
        $Days_in_month[1] = 29;
    }
    $Ob->{HR} += $Last_lon * 12 / 180;
    if ( $Ob->{HR} < 0 ) {
        $Ob->{HR} += 24;
        $Ob->{DY}--;
        if ( $Ob->{DY} < 0 ) {
            $Ob->{MO}--;
            if ( $Ob->{MO} < 1 ) {
                $Ob->{YR}--;
                $Ob->{MO} = 12;
            }
            $Ob->{DY} = $Days_in_month[ $Ob->{MO} - 1 ];
        }
    }
    if ( $Ob->{HR} > 23.99 ) {
        $Ob->{HR} -= 24;
        if ( $Ob->{HR} < 0 ) { $Ob->{HR} = 0; }
        $Ob->{DY}++;
        if ( $Ob->{DY} > $Days_in_month[ $Ob->{MO} - 1 ] ) {
            $Ob->{DY} = 1;
            $Ob->{MO}++;
            if ( $Ob->{MO} > 12 ) {
                $Ob->{YR}++;
                $Ob->{MO} = 1;
            }
        }
    }
    return 1;
}

Converted observations