/*
* Copyright (c) 2012 The 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.broadinstitute.gatk.engine.datasources.providers;
import htsjdk.samtools.reference.ReferenceSequence;
import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
import org.broadinstitute.gatk.engine.walkers.Reference;
import org.broadinstitute.gatk.engine.walkers.Walker;
import org.broadinstitute.gatk.engine.walkers.Window;
import org.broadinstitute.gatk.utils.GenomeLoc;
import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
/*
* Copyright (c) 2009 The 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.
*/
/**
* Provides access to the portion of the reference covering a single locus.
*/
public class LocusReferenceView extends ReferenceView {
/**
* Bound the reference view to make sure all accesses are within the shard.
*/
private GenomeLoc bounds;
/**
* Start of the expanded window for which the reference context should be provided,
* relative to the locus in question.
*/
private final int windowStart;
/**
* Start of the expanded window for which the reference context should be provided,
* relative to the locus in question.
*/
private final int windowStop;
/**
* Track the reference sequence and the last point accessed. Used to
* track state when traversing over the reference.
*/
private ReferenceSequence referenceSequence;
/**
* Create a LocusReferenceView given no other contextual information about
* the walkers, etc.
* @param provider source for locus data.
*/
public LocusReferenceView( LocusShardDataProvider provider ) {
super(provider);
initializeBounds(provider);
windowStart = windowStop = 0;
initializeReferenceSequence(bounds);
}
/**
* Create a new locus reference view.
* @param provider source for locus data.
*/
public LocusReferenceView( Walker walker, LocusShardDataProvider provider ) {
super( provider );
initializeBounds(provider);
// Retrieve information about the window being accessed.
if( walker.getClass().isAnnotationPresent(Reference.class) ) {
Window window = walker.getClass().getAnnotation(Reference.class).window();
if( window.start() > 0 ) throw new ReviewedGATKException( "Reference window starts after current locus" );
if( window.stop() < 0 ) throw new ReviewedGATKException( "Reference window ends before current locus" );
windowStart = window.start();
windowStop = window.stop();
}
else {
windowStart = 0;
windowStop = 0;
}
if(bounds != null) {
int expandedStart = getWindowStart( bounds );
int expandedStop = getWindowStop( bounds );
initializeReferenceSequence(genomeLocParser.createGenomeLoc(bounds.getContig(), bounds.getContigIndex(), expandedStart, expandedStop));
}
}
/**
* Initialize the bounds of this shard, trimming the bounds so that they match the reference.
* @param provider Provider covering the appropriate locus.
*/
private void initializeBounds(LocusShardDataProvider provider) {
if(provider.getLocus() != null) {
int sequenceLength = reference.getSequenceDictionary().getSequence(provider.getLocus().getContig()).getSequenceLength();
bounds = genomeLocParser.createGenomeLoc(provider.getLocus().getContig(),
Math.max(provider.getLocus().getStart(),1),
Math.min(provider.getLocus().getStop(),sequenceLength));
}
else
bounds = null;
}
/**
* Initialize reference sequence data using the given locus.
* @param locus
*/
private void initializeReferenceSequence( GenomeLoc locus ) {
this.referenceSequence = reference.getSubsequenceAt( locus.getContig(), locus.getStart(), locus.getStop() );
}
protected GenomeLoc trimToBounds(GenomeLoc l) {
int expandedStart = getWindowStart( bounds );
int expandedStop = getWindowStop( bounds );
if ( l.getStart() < expandedStart ) l = genomeLocParser.setStart(l, expandedStart);
if ( l.getStop() > expandedStop ) l = genomeLocParser.setStop(l, expandedStop);
return l;
}
public class Provider implements ReferenceContext.ReferenceContextRefProvider {
int refStart, len;
public Provider( int refStart, int len ) {
this.refStart = refStart;
this.len = len;
}
public byte[] getBases() {
//System.out.printf("Getting bases for location%n");
byte[] bases = new byte[len];
System.arraycopy(referenceSequence.getBases(), refStart, bases, 0, len);
return bases;
}
}
/**
* Gets the reference context associated with this particular point or extended interval on the genome.
* @param genomeLoc Region for which to retrieve the base(s). If region spans beyond contig end or beyond current bounds, it will be trimmed down.
* @return The base at the position represented by this genomeLoc.
*/
public ReferenceContext getReferenceContext( GenomeLoc genomeLoc ) {
//validateLocation( genomeLoc );
GenomeLoc window = genomeLocParser.createGenomeLoc( genomeLoc.getContig(), genomeLoc.getContigIndex(),
getWindowStart(genomeLoc), getWindowStop(genomeLoc) );
int refStart = -1;
if (bounds != null) {
window = trimToBounds(window);
refStart = (int)(window.getStart() - getWindowStart(bounds));
}
else {
if(referenceSequence == null || referenceSequence.getContigIndex() != genomeLoc.getContigIndex())
referenceSequence = reference.getSequence(genomeLoc.getContig());
refStart = (int)window.getStart()-1;
}
int len = (int)window.size();
return new ReferenceContext( genomeLocParser, genomeLoc, window, new Provider(refStart, len));
}
/**
* Allow the user to pull reference info from any arbitrary region of the reference.
* @param genomeLoc The locus.
* @return A list of the bases starting at the start of the locus (inclusive) and ending
* at the end of the locus (inclusive).
*/
public byte[] getReferenceBases( GenomeLoc genomeLoc ) {
return super.getReferenceBases(genomeLoc);
}
/**
* Gets the start of the expanded window, bounded if necessary by the contig.
* @param locus The locus to expand.
* @return The expanded window.
*/
private int getWindowStart( GenomeLoc locus ) {
// If the locus is not within the bounds of the contig it allegedly maps to, expand only as much as we can.
if(locus.getStart() < 1) return 1;
// if(locus.getStart() < 1) return locus.getStart();
return Math.max( locus.getStart() + windowStart, 1 );
}
/**
* Gets the stop of the expanded window, bounded if necessary by the contig.
* @param locus The locus to expand.
* @return The expanded window.
*/
private int getWindowStop( GenomeLoc locus ) {
// If the locus is not within the bounds of the contig it allegedly maps to, expand only as much as we can.
int sequenceLength = reference.getSequenceDictionary().getSequence(locus.getContig()).getSequenceLength();
if(locus.getStop() > sequenceLength) return sequenceLength;
return Math.min( locus.getStop() + windowStop, sequenceLength );
}
}