Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2019 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 htsjdk.samtools.cram.structure;
import htsjdk.samtools.SAMRecord;
import htsjdk.samtools.cram.CRAMException;
import htsjdk.samtools.cram.build.CramIO;
import htsjdk.samtools.cram.ref.ReferenceContext;
import htsjdk.samtools.util.Log;
import java.util.Objects;
/**
* An AlignmentContext represents mapping information related to a collection of reads, or a single
* {@link CRAMCompressionRecord}, {@link Slice}, or {@link Container}.
*
* It contains a {@link ReferenceContext}, and if that context is of type SINGLE_REFERENCE_TYPE
* then it also contains Alignment Start and Alignment Span values.
*/
public class AlignmentContext {
private static final Log log = Log.getInstance(AlignmentContext.class);
public static final int NO_ALIGNMENT_START = 0;
public static final int NO_ALIGNMENT_SPAN = 0;
public static final int NO_ALIGNMENT_END = SAMRecord.NO_ALIGNMENT_START; // SAMRecord uses this for alignmentEnd...
public static final AlignmentContext MULTIPLE_REFERENCE_CONTEXT =
new AlignmentContext(
ReferenceContext.MULTIPLE_REFERENCE_CONTEXT,
NO_ALIGNMENT_START,
NO_ALIGNMENT_SPAN);
public static final AlignmentContext UNMAPPED_UNPLACED_CONTEXT =
new AlignmentContext(
ReferenceContext.UNMAPPED_UNPLACED_CONTEXT,
NO_ALIGNMENT_START,
NO_ALIGNMENT_SPAN);
public static final AlignmentContext EOF_CONTAINER_CONTEXT =
new AlignmentContext(
ReferenceContext.UNMAPPED_UNPLACED_CONTEXT,
CramIO.EOF_ALIGNMENT_START, // defined by the spec...
CramIO.EOF_ALIGNMENT_SPAN); // defined by the spec...
private final ReferenceContext referenceContext;
// minimum alignment start of the reads represented here, using a 1-based coordinate system
// or NO_ALIGNMENT_START (0) if the ReferenceContext is not SINGLE_REFERENCE_TYPE
private final int alignmentStart;
private final int alignmentSpan;
/**
* Create an AlignmentContext from a reference context, start, and span.
*
* Unfortunately, this can't enforce that the values are valid alignment values, or even warn about such
* values here, because there are too many cases where the spec doesn't or didn't originally prescribe
* valid values for cases like MULTIPLE_REF containers/slices, or unmapped slices, or SAMFileHeader
* containers. As a result, there are many files floating around that use various out-of-spec values
* that were created with old htsjdk or other implementations that were based based on older spec versions.
*
* @param referenceContext the reference context for this alignment context
* @param alignmentStart the 1-based alignment start
* @param alignmentSpan the alignment span
*/
public AlignmentContext(final ReferenceContext referenceContext,
final int alignmentStart,
final int alignmentSpan) {
this.referenceContext = referenceContext;
this.alignmentStart = alignmentStart;
this.alignmentSpan = alignmentSpan;
}
public ReferenceContext getReferenceContext() {
return referenceContext;
}
public int getAlignmentStart() {
return alignmentStart;
}
public int getAlignmentSpan() {
return alignmentSpan;
}
/**
* Determine if the provided values would result in a valid alignment context.
*
* Note: The spec does not prescribe what the alignment start/span for a SAMFileHeader container
* should be, and only recently prescribed what they should be for multi-ref slices, so there are
* many files out their with various out-of-band values in those cases, so we can't validate or
* throw in the general case.
*
* @param isStrict throw if the values do not represent a valid alignmentContext
* @param referenceContext reference context to validate
* @param alignmentStart alignment start to validate
* @param alignmentSpan alignment span to validate
*/
public static void validateAlignmentContext(
final boolean isStrict,
final ReferenceContext referenceContext,
final int alignmentStart,
final int alignmentSpan) {
switch (referenceContext.getType()) {
case SINGLE_REFERENCE_TYPE:
// Note that it is technically possible to have an alignment span == 0, i.e., for a slice
// with a single record where the sequence is SAMRecord.NULL_SEQUENCE, so we only check
// alignment start
if (alignmentStart < 0) {
final String errorString = String.format(
"Single-reference alignment context with an invalid start detected (index %d/start %d/span %d)",
referenceContext.getReferenceSequenceID(),
alignmentStart,
alignmentSpan);
if (isStrict) {
throw new CRAMException(errorString);
} else {
log.warn(errorString);
}
}
break;
case UNMAPPED_UNPLACED_TYPE:
// the spec requires start==0 and span==0 for unmapped, but also make a special exception
// for EOF Containers
if (!(alignmentStart == NO_ALIGNMENT_START && alignmentSpan == NO_ALIGNMENT_SPAN) &&
!(alignmentStart == CramIO.EOF_ALIGNMENT_START && alignmentSpan == CramIO.EOF_ALIGNMENT_SPAN)) {
final String errorString = String.format(
"Unmapped/unplaced alignment context with invalid start/span detected (%d/%d)",
alignmentStart,
alignmentSpan);
if (isStrict) {
throw new CRAMException(errorString);
} else {
log.warn(errorString);
}
}
break;
case MULTIPLE_REFERENCE_TYPE:
if (alignmentStart != NO_ALIGNMENT_START || alignmentSpan != NO_ALIGNMENT_SPAN) {
final String errorString = String.format(
"Multi-reference alignment context with invalid start/span detected (%d/%d)",
alignmentStart,
alignmentSpan);
if (isStrict) {
throw new CRAMException(errorString);
} else {
log.warn(errorString);
}
}
break;
default:
throw new IllegalArgumentException(
String.format(
"Alignment context with unknown reference context type: %s",
referenceContext.getType()));
}
}
@Override
public String toString() {
return String.format(
"sequenceId=%s, start=%d, span=%d",
referenceContext,
alignmentStart,
alignmentSpan);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AlignmentContext that = (AlignmentContext) o;
return alignmentStart == that.alignmentStart &&
alignmentSpan == that.alignmentSpan &&
Objects.equals(referenceContext, that.referenceContext);
}
@Override
public int hashCode() {
return Objects.hash(referenceContext, alignmentStart, alignmentSpan);
}
}