1 /** 2 This package holds common code for the `dentist` algorithm. 3 4 Copyright: © 2018 Arne Ludwig <arne.ludwig@posteo.de> 5 License: Subject to the terms of the MIT license, as written in the 6 included LICENSE file. 7 Authors: Arne Ludwig <arne.ludwig@posteo.de> 8 */ 9 module dentist.common; 10 11 import dentist.util.log; 12 import dentist.util.region : Region; 13 import std.algorithm : count, fold, map, max, sum; 14 import std.array : array; 15 import std.conv : to; 16 import std.format : format; 17 import std.math : floor; 18 import std.traits : TemplateOf; 19 import std.typecons : Flag; 20 21 public import dentist.common.alignments; 22 public import dentist.common.binio; 23 public import dentist.common.scaffold; 24 25 26 /// True iff building with testing commands. 27 version (DentistTesting) 28 enum isTesting = true; 29 else 30 enum isTesting = false; 31 32 /// Evaluate to `value` if building with testing command; 33 /// otherwise to `typeof(value).init`. 34 template testingOnly(alias value) 35 { 36 static if (isTesting) 37 enum testingOnly = value; 38 else 39 enum testingOnly = typeof(value).init; 40 } 41 42 /// Thrown if some runtime error in the `dentist` algorithm occurs. 43 class DentistException : Exception 44 { 45 pure nothrow @nogc @safe this(string msg, string file = __FILE__, 46 size_t line = __LINE__, Throwable nextInChain = null) 47 { 48 super(msg, file, line, nextInChain); 49 } 50 } 51 52 /// A region of the reference aka. mask. 53 alias ReferenceRegion = Region!(size_t, size_t, "contigId"); 54 /// An interval of a reference contig. 55 alias ReferenceInterval = ReferenceRegion.TaggedInterval; 56 /// A point on the reference. 57 alias ReferencePoint = ReferenceRegion.TaggedPoint; 58 /// A region of a read aka. mask. 59 alias ReadRegion = Region!(size_t, size_t, "readId"); 60 /// An interval of a read contig. 61 alias ReadInterval = ReadRegion.TaggedInterval; 62 /// A point on a read. 63 alias ReadPoint = ReadRegion.TaggedPoint; 64 65 /// A point on the output assembly. 66 struct OutputCoordinate 67 { 68 static enum OriginType : ubyte 69 { 70 global, 71 contig, 72 scaffold, 73 scaffoldContig, 74 } 75 76 id_t scaffoldId; 77 id_t contigId; 78 coord_t coord; 79 80 @property coord_t idx() const pure nothrow 81 { 82 return coord - 1; 83 } 84 85 @property OriginType originType() const pure nothrow 86 { 87 if (scaffoldId == 0 && contigId == 0) 88 return OriginType.global; 89 else if (scaffoldId == 0 && contigId > 0) 90 return OriginType.contig; 91 else if (scaffoldId > 0 && contigId == 0) 92 return OriginType.scaffold; 93 else 94 return OriginType.scaffoldContig; 95 } 96 97 string toString() const 98 { 99 final switch(originType) 100 { 101 case OriginType.global: 102 return format!`%d`(coord); 103 case OriginType.contig: 104 return format!`contig/%d/%d`(contigId, coord); 105 case OriginType.scaffold: 106 return format!`scaffold/%d/%d`(scaffoldId, coord); 107 case OriginType.scaffoldContig: 108 return format!`scaffold/%d/contig/%d/%d`(scaffoldId, contigId, coord); 109 } 110 } 111 } 112 113 /// Returns the alignment region of alignmentChain. 114 R to(R, string contig = "contigA")(in AlignmentChain alignmentChain) pure 115 if (__traits(isSame, TemplateOf!R, Region)) 116 { 117 auto contigId = mixin("alignmentChain." ~ contig ~ ".id"); 118 119 return R(alignmentChain 120 .localAlignments 121 .map!(la => R.TaggedInterval( 122 contigId, 123 mixin("la." ~ contig ~ ".begin"), 124 mixin("la." ~ contig ~ ".end"), 125 )) 126 .array 127 ); 128 }