/* * The MIT License (MIT) * * Copyright (c) 2007-2015 Broad Institute * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.broad.igv.bbfile; import org.apache.log4j.Logger; import org.broad.igv.util.LittleEndianInputStream; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; /** * Created by IntelliJ IDEA. * User: Owner * Date: May 3, 2010 * Time: 12:32:17 AM * To change this template use File | Settings | File Templates. */ public class BigWigSection { private static Logger log = Logger.getLogger(BigWigSection.class); private boolean isLowToHigh; // byte order is low to high if true; else high to low private LittleEndianInputStream lbdis; // input stream reader for low to high byte ordered data private DataInputStream dis; // input stream reader for high to low byte ordered data private RPTreeLeafNodeItem leafHitItem; // leaf item defines chromosome region and file data location private int sectionDataSize; // byte size of decompressed data for this section private HashMap<Integer, String> chromosomeMap; // map of chromosome ID's and corresponding names private BigWigSectionHeader wigSectionHeader; // wig section header /* * Constructor for a BigWig data section which includes the section header * and Wig data items. * * Parameters: * sectionBuffer - buffer contains decompressed Wig section header + data * sectionIndex - wig section index for leaf data block * chromIDTree - B+ chromosome index tree returns chromosome names for ID's * isLowToHigh - if true, data byte order is low to high ; else is high to low * leafHitItem - contains leaf node information for testing against selection region * * */ public BigWigSection(byte[] sectionBuffer, HashMap<Integer, String> chromosomeMap, boolean isLowToHigh, RPTreeLeafNodeItem leafHitItem){ this.chromosomeMap = chromosomeMap; this.isLowToHigh = isLowToHigh; this.leafHitItem = leafHitItem; // wrap the Wig section buffer as an input stream and get the section header // Note: A RuntimeException is thrown if header is not read properly if(this.isLowToHigh) { lbdis = new LittleEndianInputStream(new ByteArrayInputStream(sectionBuffer)); wigSectionHeader = new BigWigSectionHeader(lbdis); } else { dis = new DataInputStream(new ByteArrayInputStream(sectionBuffer)); wigSectionHeader = new BigWigSectionHeader(dis); } // check for valid Wig item type if(wigSectionHeader.getItemType() == BigWigSectionHeader.WigItemType.Unknown){ throw new RuntimeException("Read error on wig section leaf index "); } // include header in data segment size accounting sectionDataSize = wigSectionHeader.SECTION_HEADER_SIZE; // use method getSectionData to extract section data } /* * Method returns the if the Wig items defined in this section are valid. * * Note: Use BigWigSectionHeader to obtain more information on * Wig section data specifications. * * Returns: * Specifies if Wig section has a valid data item type. * */ public boolean isValidSectionType(){ return wigSectionHeader.IsValidType(); } /* * Method returns the Wig Section Header * * Returns: * Wig section header * */ public int getItemCount() { return wigSectionHeader.getItemCount(); } /* * Method returns the Wig Section Header * * Returns: * Wig section header * */ public BigWigSectionHeader getSectionHeader() { return wigSectionHeader; } /* * Method returns the number bytes of decompressed data in this section. * * Returns: * Number of uncompressed bytes read for the Wig data section * */ public int getSectionDataSize() { return sectionDataSize; } /* * Method reads Wig data items within the decompressed block buffer for the selection region. * * Parameters: * selectionRegion - chromosome selection region for item extraction * contained - indicates select region must be contained in value region * if true, else may intersect selection region for extraction * * Returns: * Size in bytes for the wig data section. * Items read in the wig segment data block are added to the wig item list . * * Note: Unlike ZoomLevel and BigBed formats, the Wig Section data block header contains * an item count used to determine the end of data read. * */ public int getSectionData(RPChromosomeRegion selectionRegion, boolean contained, ArrayList<WigItem> wigItemList) { // get the section's data item specifications // Note: A RuntimeException is thrown if wig section header is not read properly int chromID = wigSectionHeader.getChromID(); String chromosome = chromosomeMap.get(chromID); int itemCount = wigSectionHeader.getItemCount(); int chromStart = wigSectionHeader.getChromosomeStart(); int chromEnd = wigSectionHeader.getChromosomeEnd(); int itemStep = wigSectionHeader.getItemStep(); int itemSpan = wigSectionHeader.getItemSpan(); int itemIndex = 0; int startBase = 0; int endBase = 0; float value = 0.0f; // find Wig data type - BBFile Table J item type BigWigSectionHeader.WigItemType itemType = wigSectionHeader.getItemType(); // check if all leaf items are selection hits RPChromosomeRegion itemRegion = new RPChromosomeRegion(chromID, chromStart, chromID, chromEnd); int leafHitValue = itemRegion.compareRegions(selectionRegion); // extract Wig data records // Note: the buffer input stream is positioned past section header try { for(int index = 0; index < itemCount; ++index) { ++itemIndex; if(isLowToHigh){ if(itemType == BigWigSectionHeader.WigItemType.FixedStep){ startBase = chromStart; endBase = startBase + itemSpan; value = lbdis.readFloat(); chromStart = startBase + itemStep; sectionDataSize += BigWigSectionHeader.FIXEDSTEP_ITEM_SIZE; } else if(itemType == BigWigSectionHeader.WigItemType.VarStep){ startBase = lbdis.readInt(); endBase = startBase + itemSpan; value = lbdis.readFloat(); sectionDataSize += BigWigSectionHeader.VARSTEP_ITEM_SIZE; } else if(itemType == BigWigSectionHeader.WigItemType.BedGraph){ startBase = lbdis.readInt(); endBase = lbdis.readInt(); value = lbdis.readFloat(); sectionDataSize += BigWigSectionHeader.BEDGRAPH_ITEM_SIZE; } } else { // byte order is high to low if(itemType == BigWigSectionHeader.WigItemType.FixedStep){ startBase = chromStart; endBase = startBase + itemSpan; value = dis.readFloat(); chromStart = startBase + itemStep; sectionDataSize += BigWigSectionHeader.FIXEDSTEP_ITEM_SIZE; } else if(itemType == BigWigSectionHeader.WigItemType.VarStep){ startBase = dis.readInt(); endBase = startBase + itemSpan; value = dis.readFloat(); sectionDataSize += BigWigSectionHeader.VARSTEP_ITEM_SIZE; } else if(itemType == BigWigSectionHeader.WigItemType.BedGraph){ startBase = dis.readInt(); endBase = dis.readInt(); value = dis.readFloat(); sectionDataSize += BigWigSectionHeader.BEDGRAPH_ITEM_SIZE; } } // contained leaf region items are always added - otherwise test conditions if(leafHitValue == 0) { WigItem bbItem = new WigItem(itemIndex, chromosome, startBase, endBase, value); wigItemList.add(bbItem); } else { itemRegion = new RPChromosomeRegion(chromID, startBase, chromID, endBase); int itemHitValue = itemRegion.compareRegions(selectionRegion); // hitValue < 2 needed for intersection; hitValue < 1 needed for contained = true if(itemHitValue == 0 || !contained && Math.abs(itemHitValue) < 2) { WigItem bbItem = new WigItem(itemIndex, chromosome, startBase, endBase, value); wigItemList.add(bbItem); } } } }catch(IOException ex) { log.error("Read error for Wig section item " + itemIndex); throw new RuntimeException("Read error for Wig section item " + itemIndex); } return sectionDataSize; } /* * Method prints out the data items for this Wig section. * */ public void print() { log.debug("Wig section for leaf item has a data size = " + sectionDataSize); wigSectionHeader.print(); } }