package org.seqcode.data.readdb; import java.io.*; import java.nio.channels.*; import java.util.Arrays; /** * Represents the list of sorted reads on disk. * Some alignments store the standard SingleHits and "type 2" SingleHits separately. * Type 2 SingleHits are used in alignments where the read 2 hits represent something different from read 1 hits. * For example, in paired-end ChIP-exo, where only read 1 is affected by exonuclease. */ public class SingleHits extends Hits { /** * Initializes a Hits object from a file */ public SingleHits (String prefix, int chrom, boolean type2) throws FileNotFoundException, SecurityException, IOException { super(chrom, getPositionsFname(prefix,chrom, type2), getWeightsFname(prefix,chrom, type2), getLaSFname(prefix,chrom, type2)); } public static void writeSingleHits(IntBP positions, FloatBP weights, IntBP las, String prefix, int chrom, boolean type2 ) throws IOException { String postmp = getPositionsFname(prefix,chrom, type2) + ".tmp"; String weightstmp = getWeightsFname(prefix,chrom, type2) + ".tmp"; String lastmp = getLaSFname(prefix,chrom, type2) + ".tmp"; RandomAccessFile positionsRAF = new RandomAccessFile(postmp,"rw"); RandomAccessFile weightsRAF = new RandomAccessFile(weightstmp,"rw"); RandomAccessFile lasRAF = new RandomAccessFile(lastmp,"rw"); Bits.sendBytes(positions.bb, 0, positions.bb.limit(), positionsRAF.getChannel()); Bits.sendBytes(weights.bb, 0, weights.bb.limit(), weightsRAF.getChannel()); Bits.sendBytes(las.bb, 0, las.bb.limit(), lasRAF.getChannel()); positionsRAF.close(); weightsRAF.close(); lasRAF.close(); /* ideally this part with the renames would atomic... */ (new File(postmp)).renameTo(new File(getPositionsFname(prefix,chrom, type2))); (new File(weightstmp)).renameTo(new File(getWeightsFname(prefix,chrom, type2))); (new File(lastmp)).renameTo(new File(getLaSFname(prefix,chrom, type2))); } public static void writeSingleHits(SingleHit[] hits, String prefix, int chrom, boolean type2) throws IOException { IntBP p = new IntBP(hits.length); FloatBP w = new FloatBP(hits.length); IntBP l = new IntBP(hits.length); for (int i = 0; i < hits.length; i++) { SingleHit h = hits[i]; p.put(i, h.pos); w.put(i, h.weight); l.put(i, makeLAS(h.length, h.strand)); } writeSingleHits(p,w,l,prefix,chrom, type2); } /** appends a sorted list of hits to an existing set of hits. */ public void appendSingleHits(SingleHit[] hits, String prefix, int chrom, boolean type2) throws IOException { if (hits.length == 0) { return; } int s = getPositionsBuffer().limit() - 1; SingleHit last = new SingleHit(chrom, getPositionsBuffer().get(s), getWeightsBuffer().get(s), Hits.getStrandOne(getLASBuffer().get(s)), Hits.getLengthOne(getLASBuffer().get(s))); if (hits[0].compareTo(last) > 0 ) { append(hits,prefix,chrom, type2); } else { merge(hits,prefix,chrom, type2); } } private void append(SingleHit[] hits, String prefix, int chrom, boolean type2) throws IOException { RandomAccessFile positionsRAF = new RandomAccessFile(getPositionsFname(prefix,chrom, type2),"rw"); RandomAccessFile weightsRAF = new RandomAccessFile(getWeightsFname(prefix,chrom, type2),"rw"); RandomAccessFile lasRAF = new RandomAccessFile(getLaSFname(prefix,chrom, type2),"rw"); positionsRAF.seek(positionsRAF.length()); weightsRAF.seek(weightsRAF.length()); lasRAF.seek(lasRAF.length()); for (int i = 0; i < hits.length; i++) { SingleHit h = hits[i]; positionsRAF.writeInt(h.pos); weightsRAF.writeFloat(h.weight); lasRAF.writeInt(makeLAS(h.length, h.strand)); } positionsRAF.close(); weightsRAF.close(); lasRAF.close(); } private void merge(SingleHit[] hits, String prefix, int chrom, boolean type2) throws IOException { String postmp = getPositionsFname(prefix,chrom, type2) + ".tmp"; String weightstmp = getWeightsFname(prefix,chrom, type2) + ".tmp"; String lastmp = getLaSFname(prefix,chrom, type2) + ".tmp"; RandomAccessFile positionsRAF = new RandomAccessFile(postmp,"rw"); RandomAccessFile weightsRAF = new RandomAccessFile(weightstmp,"rw"); RandomAccessFile lasRAF = new RandomAccessFile(lastmp,"rw"); int newsize = getPositionsBuffer().limit() + hits.length; IntBP posfile = new IntBP(positionsRAF.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, newsize * 4)); FloatBP weightfile = new FloatBP(weightsRAF.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, newsize * 4)); IntBP lasfile = new IntBP(lasRAF.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, newsize * 4)); int oldp = 0; int newp = 0; int pos = 0; IntBP oldpositions = getPositionsBuffer(); FloatBP oldweights = getWeightsBuffer(); IntBP oldlas = getLASBuffer(); while (oldp < oldpositions.limit() || newp < hits.length) { while (newp < hits.length && (oldp == oldpositions.limit() || hits[newp].pos <= oldpositions.get(oldp))) { posfile.put(pos, hits[newp].pos); weightfile.put(pos, hits[newp].weight); lasfile.put(pos, Hits.makeLAS(hits[newp].length, hits[newp].strand)); newp++; pos++; } while (oldp < oldpositions.limit() && (newp == hits.length || oldpositions.get(oldp) <= hits[newp].pos)) { posfile.put(pos,oldpositions.get(oldp)); weightfile.put(pos,oldweights.get(oldp)); lasfile.put(pos,oldlas.get(oldp)); oldp++; pos++; } // System.err.println(String.format("%d %d %d", pos, newp, oldp)); } posfile = null; weightfile = null; lasfile = null; oldpositions = null; oldweights =null; oldlas = null; positionsRAF.close(); weightsRAF.close(); lasRAF.close(); /* ideally this part with the renames would atomic... */ (new File(postmp)).renameTo(new File(getPositionsFname(prefix,chrom, type2))); (new File(weightstmp)).renameTo(new File(getWeightsFname(prefix,chrom, type2))); (new File(lastmp)).renameTo(new File(getLaSFname(prefix,chrom, type2))); } public void resort(String prefix, int chrom, boolean type2) throws IOException { IntBP positions = getPositionsBuffer(); FloatBP weights = getWeightsBuffer(); IntBP las = getLASBuffer(); long indices[] = new long[positions.limit()]; for (int i = 0; i < indices.length; i++) { long v = positions.get(i); v <<= 32; v |= i; indices[i] = v; } Arrays.sort(indices); String postmp = getPositionsFname(prefix,chrom, type2) + ".tmp"; String weightstmp = getWeightsFname(prefix,chrom, type2) + ".tmp"; String lastmp = getLaSFname(prefix,chrom, type2) + ".tmp"; RandomAccessFile positionsRAF = new RandomAccessFile(postmp,"rw"); RandomAccessFile weightsRAF = new RandomAccessFile(weightstmp,"rw"); RandomAccessFile lasRAF = new RandomAccessFile(lastmp,"rw"); int newsize = getPositionsBuffer().limit(); IntBP posfile = new IntBP(positionsRAF.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, newsize * 4)); FloatBP weightfile = new FloatBP(weightsRAF.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, newsize * 4)); IntBP lasfile = new IntBP(lasRAF.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, newsize * 4)); for (int i = 0; i < indices.length; i++) { int index = (int)(indices[i] & 0xffffffffL); int pos = (int)(indices[i] >> 32); posfile.put(i, pos); weightfile.put(i, weights.get(index)); lasfile.put(i, las.get(index)); } posfile = null; weightfile = null; lasfile = null; positionsRAF.close(); weightsRAF.close(); lasRAF.close(); /* ideally this part with the renames would atomic... */ (new File(postmp)).renameTo(new File(getPositionsFname(prefix,chrom, type2))); (new File(weightstmp)).renameTo(new File(getWeightsFname(prefix,chrom, type2))); (new File(lastmp)).renameTo(new File(getLaSFname(prefix,chrom, type2))); } private static String getPositionsFname(String prefix, int chrom, boolean type2) { if(!type2) return prefix + chrom + ".spositions"; else return prefix + chrom + ".st2positions"; } private static String getWeightsFname(String prefix, int chrom, boolean type2) { if(!type2) return prefix + chrom + ".sweights"; else return prefix + chrom + ".st2weights"; } private static String getLaSFname(String prefix, int chrom, boolean type2) { if(!type2) return prefix + chrom + ".slas"; else return prefix + chrom + ".st2las"; } }