MS

 view release on metacpan or  search on metacpan

lib/MS/Reader/MzXML/Spectrum.pm  view on Meta::CPAN


sub _post_load {

    my ($self) = @_;

    # Nested scans don't work with the current infrastructure (plus we never
    # use this format). Could be supported in future if there was demand.
    croak "Nested scans in mzXML not currently supported!"
        if (exists $self->{scan}->{scan});

}
sub ms_level {

    my ($self) = @_;

    croak "Invalid mzXML (missing msLevel property)"
        if (! defined $self->{msLevel});

    return $self->{msLevel};

}

sub rt {

    my ($self) = @_;

    return undef if (! defined $self->{retentionTime});

    if ($self->{retentionTime} =~ /^PT(?:([\d\.]+)M)?(?:([\d\.]+)S)?/) {
        my $s = 0;
        $s += $1*60 if (defined $1);
        $s += $2    if (defined $2);
        return $s;
    }

    croak "Unexpected retention time format: $self->{retentionTime}";

}

sub scan_number {

    my ($self) = @_;

    croak "Invalid mzXML (missing scan number property)"
        if (! defined $self->{num});

    return $self->{num};

}

sub precursor {

    my ($self) = @_;
    croak "precursor() only valid for MS2 spectra"
        if ($self->{msLevel} < 2);
    croak "precursor() only valid for single precursor spectra, use direct access.\n"
        if (scalar @{$self->{precursorMz}} != 1);

    my $pre       = $self->{precursorMz}->[0];
    my $id        = $pre->{precursorScanNum};
    my $mono_mz   = $pre->{pcdata};
    my $iso_mz    = $mono_mz;
    my $iso_lower = $iso_mz - $pre->{windowWideness}/2;
    my $iso_upper = $iso_mz + $pre->{windowWideness}/2;
    my $charge    = $pre->{precursorCharge};
    my $int       = $pre->{precursorIntensity};

    croak "missing monoisotopic m/z" if (! defined $mono_mz);
    return {
        scan_id   => $id,
        iso_mz    => $iso_mz,
        iso_lower => $iso_lower,
        iso_upper => $iso_upper,
        mono_mz   => $mono_mz,
        charge    => $charge,
        intensity => $int,
    };

}

sub mz {

    my ($self) = @_;

    return $self->{__mz} if (exists $self->{__mz});

    if (defined $self->{peaks}->{'m/z'}) {
        $self->{__mz} = $self->get_array('m/z');
    }
    elsif (defined $self->{peaks}->{'m/z-int'}) {
        my $v = $self->get_array('m/z-int');
        my $l = scalar(@$v)/2;
        croak "Odd-numbered m/z-int array" if ( ($l%2) != 0);
        $self->{__mz}  = [ map {$v->[$_]} map {$_*2}   (0..$l-1) ];
        $self->{__int} = [ map {$v->[$_]} map {$_*2+1} (0..$l-1) ];
    }
    else {
        croak "m/z array undefined";
    }

    return $self->{__mz};

}

sub int {

    my ($self) = @_;

    return $self->{__int} if (exists $self->{__int});

    if (defined $self->{peaks}->{'intensity'}) {
        $self->{__int} = $self->get_array('intensity');
    }
    elsif (defined $self->{peaks}->{'m/z-int'}) {
        my $v = $self->get_array('m/z-int');
        my $l = scalar(@$v)/2;
        croak "Odd-numbered m/z-int array" if ( ($l%2) != 0);
        $self->{__mz}  = [ map {$v->[$_]} map {$_*2}   (0..$l-1) ];
        $self->{__int} = [ map {$v->[$_]} map {$_*2+1} (0..$l-1) ];
    }
    else {
        croak "intensity array undefined";
    }

    return $self->{__int};

}

sub get_array {

    my ($self, $type) = @_;

    my $ref = $self->{peaks}->{$type};
    croak "Undefined array type $type" if (! defined $ref);

    my $data = decode_base64( $ref->{pcdata} );
    $data    = uncompress($data) if ($ref->{compressionType} eq 'zlib');
    my $code = $ref->{precision} eq '64' ? 'd>' : 'f>';
    return [ unpack "$code*", $data ];

}

sub scan_window {

    my ($self) = @_; 
    
    my $l = $self->{startMz} // $self->{lowMz};
    my $r = $self->{endMZ}   // $self->{highMz};

    return undef if (! defined $l || ! defined $r);
    return [$l, $r];

}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

MS::Reader::MzXML::Spectrum - An MzXML spectrum object

=head1 SYNOPSIS

    use MS::Reader::MzXML;

    my $run = MS::Reader::MzXML->new('run.mzXML');

    while (my $spectrum = $run->next_spectrum) {
       
        # Note that these two methods are functionally identical
        my $id        = $spectrum->id;
        my $scan_num  = $spectrum->scan_number;

        my $rt  = $spectrum->rt;
        my $mz  = $spectrum->mz;
        my $int = $spectrum->int;
        my $lvl = $spectrum->ms_level;

        # $spectrum inherits from MS::Reader::MzML::Record, so you can do:
        my $tc  = $spectrum->param(MS_TOTAL_ION_CURRENT);
        my $sn  = $spectrum->get_array(MS_CHARGE_ARRAY); # if present

        # in addition,

        my $z  = $spectrum->get_array('charge'); # if present
        my $precursor = $spectrum->precursor;
        my $pre_mz    = $precursor->{mono_mz};
        my $pre_mz    = $precursor->{mono_mz};

        # or access the guts directly (yes, it's okay!)
        my $current = $spectrum->{totIonCurrent};



( run in 0.988 second using v1.01-cache-2.11-cpan-39bf76dae61 )