@@ -1108,6 +1108,10 @@ class get_readpairs:
11081108 # Used in place of a real read in incomplete pairs before they are completed
11091109 PendingMate = object ()
11101110
1111+ # Read key. To allow for multi-mapping, we also use the mapping position
1112+ def get_pair_key (self , read ):
1113+ return (read .qname , read .reference_start if not read .is_read2 == 0 else read .next_reference_start )
1114+
11111115 def drain_queue_forcibly (self ):
11121116 # Forcibly convert incomplete queued pairs into singletons.
11131117 # These necessarily contains only a read1, but not read2, since we
@@ -1117,15 +1121,15 @@ def drain_queue_forcibly(self):
11171121 if pair [1 ] is get_readpairs .PendingMate :
11181122 pair [1 ] = None
11191123 U .warn ("inconsistent BAM file: only read1 of proper pair %s found on chromosome %s, treating as unpaired" %
1120- (pair [0 ]. qname , pair [0 ].reference_name ))
1124+ (str ( self . get_pair_key ( pair [0 ])) , pair [0 ].reference_name ))
11211125 yield pair
11221126 # Forcibly convert also incomplete unqueued pairs into singletons.
11231127 # These are the ones that contain only a read2 but no read1
11241128 for pair in self .incomplete_pairs .values ():
11251129 if pair [0 ] is get_readpairs .PendingMate :
11261130 pair [0 ] = None
11271131 U .warn ("inconsistent BAM file: only read2 of proper pair %s found on chromosome %s, treating as unpaired" %
1128- (pair [1 ]. qname , pair [1 ].reference_name ))
1132+ (str ( self . get_pair_key ( pair [1 ])) , pair [1 ].reference_name ))
11291133 yield pair
11301134 self .incomplete_pairs .clear ()
11311135
@@ -1135,35 +1139,42 @@ def __call__(self, inreads):
11351139 self .current_chr = None
11361140
11371141 for read in inreads :
1138- read_i = int (read .is_read2 )
11391142 read_chr = read .reference_name
1143+ # Read index. 0 for read1 and 1 for read2
1144+ read_i = int (read .is_read2 )
1145+ pair_key = self .get_pair_key (read )
11401146
11411147 # Output leftover incomplete read pairs if the chrosomome changes
11421148 if self .current_chr is not None and self .current_chr != read_chr :
11431149 for queue_entry in self .drain_queue_forcibly ():
11441150 yield queue_entry
11451151 self .current_chr = read_chr
11461152
1147- # Queue read, either as a singleton, or as part of a read pair
1148- if read .is_unmapped or read .mate_is_unmapped or not read .is_proper_pair :
1153+ # Queue read, either as a singleton, or as part of a read pair.
1154+ # Proper pairs should always have both mates mapped to the same chromosome,
1155+ # but to avoid weird behaviour for broken BAM file, we re-check.
1156+ if ((not read .is_proper_pair ) or
1157+ read .is_unmapped or
1158+ read .mate_is_unmapped or
1159+ (read .reference_id != read .next_reference_id )):
11491160 # Read is not part of a proper pair. Enqueue as singleton
11501161 pair = [None , None ]
11511162 pair [read_i ] = read
11521163 self .queue .append (pair )
11531164 else :
1154- if read . qname in self .incomplete_pairs :
1165+ if pair_key in self .incomplete_pairs :
11551166 # Read is part of an already queued (incomplete) read pair. Complete it.
1156- pair = self .incomplete_pairs .pop (read . qname )
1167+ pair = self .incomplete_pairs .pop (pair_key )
11571168 if pair [read_i ] is not get_readpairs .PendingMate :
1158- U .warn ("inconsistent BAM file: both mates %s flagged to be read%d" %
1159- (read . qname , read_i + 1 ))
1169+ U .warn ("inconsistent BAM file: both mates of %s flagged to be read%d" %
1170+ (str ( pair_key ) , read_i + 1 ))
11601171 read_i = 1 - read_i
11611172 pair [read_i ] = read
11621173 else :
11631174 # Read is part of a new read pair. Create incomplete pair
11641175 pair = [get_readpairs .PendingMate , get_readpairs .PendingMate ]
11651176 pair [read_i ] = read
1166- self .incomplete_pairs [read . qname ] = pair
1177+ self .incomplete_pairs [pair_key ] = pair
11671178 # Enqueue pair in the correct place for its 1st read
11681179 if read_i == 0 :
11691180 self .queue .append (pair )
0 commit comments