{"action":"created","comment":{"url":"https://api.github.com/repos/hammerlab/guacamole/pulls/comments/35270859","id":35270859,"diff_hunk":"@@ -0,0 +1,133 @@\n+package org.hammerlab.guacamole.commands\n+\n+import org.apache.spark.SparkContext\n+import org.apache.spark.util.StatCounter\n+import org.hammerlab.guacamole.{ DistributedUtil, SparkCommand, Common }\n+import org.hammerlab.guacamole.reads.{ PairedRead, Read, MappedRead }\n+import org.kohsuke.args4j.{ Option => Args4JOption }\n+\n+import scala.collection.mutable.ArrayBuffer\n+\n+/**\n+ * Structural Variant caller\n+ *\n+ * This currently looks for regions with abnormally large insert sizes. This typically indicates\n+ * that there's been a large deletion.\n+ *\n+ * It does this by finding the average insert size of all mate pairs which overlap each 25-base pair \"block\" of the\n+ * genome. If this average is significantly different than the average insert size genome-wide, then it's evidence that\n+ * there may be a structural variant.\n+ * \n+ * The output is a text file of genomic ranges where there's some evidence of an SV.\n+ */\n+object StructuralVariant {\n+\n+  val MAX_INSERT_SIZE = 25000\n+  val BLOCK_SIZE = 25\n+\n+  protected class Arguments extends Common.Arguments.Reads with DistributedUtil.Arguments {\n+    @Args4JOption(name = \"--filter-contig\", usage = \"Filter to alignments where either mate is in this contig.\")\n+    var filterContig: String = \"\"\n+\n+    @Args4JOption(name = \"--output\", usage = \"Path to output text file.\")\n+    var output: String = \"\"\n+  }\n+\n+  case class Location(\n+      contig: String,\n+      position: Long) {\n+  }\n+\n+  case class GenomeRange(\n+    contig: String,\n+    start: Long,\n+    stop: Long)\n+\n+  object Caller extends SparkCommand[Arguments] {\n+    override val name = \"structural-variant\"\n+    override val description = \"Find structural variants, i.e. large insertions or deletions, inversions and translocations.\"\n+\n+    // The sign of inferredInsertSize follows the orientation of the read. This returns\n+    // an insert size which is positive in the common case, regardless of the orientation.\n+    def orientedInsertSize(r: PairedRead[MappedRead]): Option[Int] = {\n+      val sgn = if (r.isPositiveStrand) { 1 } else { -1 }\n+      r.mateAlignmentProperties.flatMap(_.inferredInsertSize).map(x => x * sgn)\n+    }\n+\n+    // Coalesce sequences of values separated by blockSize into single ranges.\n+    // The sequence of values must be sorted.\n+    def coalesceAdjacent(xs: IndexedSeq[Long], blockSize: Long): Iterator[(Long, Long)] = {\n+      val rangeStarts = ArrayBuffer(0)\n+      for (i <- 1 until xs.length) {\n+        if (xs(i - 1) + blockSize != xs(i)) {\n+          rangeStarts += i\n+        }\n+      }\n+      rangeStarts += xs.length\n+\n+      rangeStarts.sliding(2).map(items => {\n+        val startIdx = items(0)\n+        val nextStartIdx = items(1)\n+        (xs(startIdx), xs(nextStartIdx - 1))\n+      })\n+    }\n+\n+    // Returns a sequence of all blocks which overlap the read, its mate or the insert between them.\n+    def matedReadBlocks(r: PairedRead[MappedRead]): Seq[Long] = {\n+      if (!r.isMateMapped) {\n+        Seq[Long]()\n+      } else {\n+        val mateStart = r.mateAlignmentProperties.map(mp => mp.start).getOrElse(r.read.start)\n+        val start = List(r.read.start, r.read.end, mateStart).min\n+        val roundedStart = (1.0 * start / BLOCK_SIZE).toLong * BLOCK_SIZE\n+        val insertSize = orientedInsertSize(r).getOrElse(0)\n+        (roundedStart to (roundedStart + insertSize) by BLOCK_SIZE)\n+      }\n+    }\n+\n+    override def run(args: Arguments, sc: SparkContext): Unit = {\n+      val readSet = Common.loadReadsFromArguments(args, sc, Read.InputFilters(nonDuplicate = true))\n+      val pairedMappedReads = readSet.mappedPairedReads\n+      val firstInPair = pairedMappedReads.filter(_.isFirstInPair)\n+\n+      // Pare down to mate pairs which aren't highly displaced & aren't inverted.\n+      val readsInRange = firstInPair.filter(r => {","path":"src/main/scala/org/hammerlab/guacamole/commands/StructuralVariantCaller.scala","position":94,"original_position":94,"commit_id":"86aec297b422922dae2c9c224b1e25ad7304d4f2","original_commit_id":"86aec297b422922dae2c9c224b1e25ad7304d4f2","user":{"login":"ryan-williams","id":465045,"avatar_url":"https://avatars.githubusercontent.com/u/465045?v=3","gravatar_id":"","url":"https://api.github.com/users/ryan-williams","html_url":"https://github.com/ryan-williams","followers_url":"https://api.github.com/users/ryan-williams/followers","following_url":"https://api.github.com/users/ryan-williams/following{/other_user}","gists_url":"https://api.github.com/users/ryan-williams/gists{/gist_id}","starred_url":"https://api.github.com/users/ryan-williams/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ryan-williams/subscriptions","organizations_url":"https://api.github.com/users/ryan-williams/orgs","repos_url":"https://api.github.com/users/ryan-williams/repos","events_url":"https://api.github.com/users/ryan-williams/events{/privacy}","received_events_url":"https://api.github.com/users/ryan-williams/received_events","type":"User","site_admin":false},"body":"`insertSizes.filter(_ < MAX_INSERT_SIZE)`","created_at":"2015-07-22T22:15:10Z","updated_at":"2015-07-22T22:15:10Z","html_url":"https://github.com/hammerlab/guacamole/pull/334#discussion_r35270859","pull_request_url":"https://api.github.com/repos/hammerlab/guacamole/pulls/334","_links":{"self":{"href":"https://api.github.com/repos/hammerlab/guacamole/pulls/comments/35270859"},"html":{"href":"https://github.com/hammerlab/guacamole/pull/334#discussion_r35270859"},"pull_request":{"href":"https://api.github.com/repos/hammerlab/guacamole/pulls/334"}}},"pull_request":{"url":"https://api.github.com/repos/hammerlab/guacamole/pulls/334","id":40596341,"html_url":"https://github.com/hammerlab/guacamole/pull/334","diff_url":"https://github.com/hammerlab/guacamole/pull/334.diff","patch_url":"https://github.com/hammerlab/guacamole/pull/334.patch","issue_url":"https://api.github.com/repos/hammerlab/guacamole/issues/334","number":334,"state":"open","locked":false,"title":"Find regions with abnormally large inserts.","user":{"login":"danvk","id":98301,"avatar_url":"https://avatars.githubusercontent.com/u/98301?v=3","gravatar_id":"","url":"https://api.github.com/users/danvk","html_url":"https://github.com/danvk","followers_url":"https://api.github.com/users/danvk/followers","following_url":"https://api.github.com/users/danvk/following{/other_user}","gists_url":"https://api.github.com/users/danvk/gists{/gist_id}","starred_url":"https://api.github.com/users/danvk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danvk/subscriptions","organizations_url":"https://api.github.com/users/danvk/orgs","repos_url":"https://api.github.com/users/danvk/repos","events_url":"https://api.github.com/users/danvk/events{/privacy}","received_events_url":"https://api.github.com/users/danvk/received_events","type":"User","site_admin":false},"body":"This is pretty simple and will conflict with @arahuja's #325, but it is at least able to find interesting regions  in synth4.\r\n\r\nFor example, here's one of the output lines when I run it on synth4 tumor:\r\n\r\n    GenomeRange(21,10744200,10760575)\r\n\r\nand the corresponding view in IGV:\r\n\r\n![large gaps](https://cloud.githubusercontent.com/assets/98301/8833677/1615b138-307e-11e5-8131-fd58cec3e95a.png)\r\n\r\nit's sorted by insert size, so you're just seeing the big gaps. But there does seem to be some evidence for a large, consistent deletion.\n\n<!-- Reviewable:start -->\n[<img src=\"https://reviewable.io/review_button.png\" height=40 alt=\"Review on Reviewable\"/>](https://reviewable.io/reviews/hammerlab/guacamole/334)\n<!-- Reviewable:end -->\n","created_at":"2015-07-22T18:30:47Z","updated_at":"2015-07-22T22:15:10Z","closed_at":null,"merged_at":null,"merge_commit_sha":"993fe8b62b4733cddd19511cb0b59cbcef7a3240","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/hammerlab/guacamole/pulls/334/commits","review_comments_url":"https://api.github.com/repos/hammerlab/guacamole/pulls/334/comments","review_comment_url":"https://api.github.com/repos/hammerlab/guacamole/pulls/comments{/number}","comments_url":"https://api.github.com/repos/hammerlab/guacamole/issues/334/comments","statuses_url":"https://api.github.com/repos/hammerlab/guacamole/statuses/86aec297b422922dae2c9c224b1e25ad7304d4f2","head":{"label":"hammerlab:big-inserts","ref":"big-inserts","sha":"86aec297b422922dae2c9c224b1e25ad7304d4f2","user":{"login":"hammerlab","id":6563873,"avatar_url":"https://avatars.githubusercontent.com/u/6563873?v=3","gravatar_id":"","url":"https://api.github.com/users/hammerlab","html_url":"https://github.com/hammerlab","followers_url":"https://api.github.com/users/hammerlab/followers","following_url":"https://api.github.com/users/hammerlab/following{/other_user}","gists_url":"https://api.github.com/users/hammerlab/gists{/gist_id}","starred_url":"https://api.github.com/users/hammerlab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hammerlab/subscriptions","organizations_url":"https://api.github.com/users/hammerlab/orgs","repos_url":"https://api.github.com/users/hammerlab/repos","events_url":"https://api.github.com/users/hammerlab/events{/privacy}","received_events_url":"https://api.github.com/users/hammerlab/received_events","type":"Organization","site_admin":false},"repo":{"id":18748250,"name":"guacamole","full_name":"hammerlab/guacamole","owner":{"login":"hammerlab","id":6563873,"avatar_url":"https://avatars.githubusercontent.com/u/6563873?v=3","gravatar_id":"","url":"https://api.github.com/users/hammerlab","html_url":"https://github.com/hammerlab","followers_url":"https://api.github.com/users/hammerlab/followers","following_url":"https://api.github.com/users/hammerlab/following{/other_user}","gists_url":"https://api.github.com/users/hammerlab/gists{/gist_id}","starred_url":"https://api.github.com/users/hammerlab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hammerlab/subscriptions","organizations_url":"https://api.github.com/users/hammerlab/orgs","repos_url":"https://api.github.com/users/hammerlab/repos","events_url":"https://api.github.com/users/hammerlab/events{/privacy}","received_events_url":"https://api.github.com/users/hammerlab/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/hammerlab/guacamole","description":"Simple Spark-based variant calling","fork":false,"url":"https://api.github.com/repos/hammerlab/guacamole","forks_url":"https://api.github.com/repos/hammerlab/guacamole/forks","keys_url":"https://api.github.com/repos/hammerlab/guacamole/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hammerlab/guacamole/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hammerlab/guacamole/teams","hooks_url":"https://api.github.com/repos/hammerlab/guacamole/hooks","issue_events_url":"https://api.github.com/repos/hammerlab/guacamole/issues/events{/number}","events_url":"https://api.github.com/repos/hammerlab/guacamole/events","assignees_url":"https://api.github.com/repos/hammerlab/guacamole/assignees{/user}","branches_url":"https://api.github.com/repos/hammerlab/guacamole/branches{/branch}","tags_url":"https://api.github.com/repos/hammerlab/guacamole/tags","blobs_url":"https://api.github.com/repos/hammerlab/guacamole/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hammerlab/guacamole/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hammerlab/guacamole/git/refs{/sha}","trees_url":"https://api.github.com/repos/hammerlab/guacamole/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hammerlab/guacamole/statuses/{sha}","languages_url":"https://api.github.com/repos/hammerlab/guacamole/languages","stargazers_url":"https://api.github.com/repos/hammerlab/guacamole/stargazers","contributors_url":"https://api.github.com/repos/hammerlab/guacamole/contributors","subscribers_url":"https://api.github.com/repos/hammerlab/guacamole/subscribers","subscription_url":"https://api.github.com/repos/hammerlab/guacamole/subscription","commits_url":"https://api.github.com/repos/hammerlab/guacamole/commits{/sha}","git_commits_url":"https://api.github.com/repos/hammerlab/guacamole/git/commits{/sha}","comments_url":"https://api.github.com/repos/hammerlab/guacamole/comments{/number}","issue_comment_url":"https://api.github.com/repos/hammerlab/guacamole/issues/comments{/number}","contents_url":"https://api.github.com/repos/hammerlab/guacamole/contents/{+path}","compare_url":"https://api.github.com/repos/hammerlab/guacamole/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hammerlab/guacamole/merges","archive_url":"https://api.github.com/repos/hammerlab/guacamole/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hammerlab/guacamole/downloads","issues_url":"https://api.github.com/repos/hammerlab/guacamole/issues{/number}","pulls_url":"https://api.github.com/repos/hammerlab/guacamole/pulls{/number}","milestones_url":"https://api.github.com/repos/hammerlab/guacamole/milestones{/number}","notifications_url":"https://api.github.com/repos/hammerlab/guacamole/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hammerlab/guacamole/labels{/name}","releases_url":"https://api.github.com/repos/hammerlab/guacamole/releases{/id}","created_at":"2014-04-14T04:22:46Z","updated_at":"2015-07-10T00:44:32Z","pushed_at":"2015-07-22T21:01:05Z","git_url":"git://github.com/hammerlab/guacamole.git","ssh_url":"git@github.com:hammerlab/guacamole.git","clone_url":"https://github.com/hammerlab/guacamole.git","svn_url":"https://github.com/hammerlab/guacamole","homepage":"","size":46822,"stargazers_count":42,"watchers_count":42,"language":"Scala","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":9,"mirror_url":null,"open_issues_count":35,"forks":9,"open_issues":35,"watchers":42,"default_branch":"master"}},"base":{"label":"hammerlab:master","ref":"master","sha":"7ff91c66e4dbd917dbea5bcc7f3dbe2466a2fd2b","user":{"login":"hammerlab","id":6563873,"avatar_url":"https://avatars.githubusercontent.com/u/6563873?v=3","gravatar_id":"","url":"https://api.github.com/users/hammerlab","html_url":"https://github.com/hammerlab","followers_url":"https://api.github.com/users/hammerlab/followers","following_url":"https://api.github.com/users/hammerlab/following{/other_user}","gists_url":"https://api.github.com/users/hammerlab/gists{/gist_id}","starred_url":"https://api.github.com/users/hammerlab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hammerlab/subscriptions","organizations_url":"https://api.github.com/users/hammerlab/orgs","repos_url":"https://api.github.com/users/hammerlab/repos","events_url":"https://api.github.com/users/hammerlab/events{/privacy}","received_events_url":"https://api.github.com/users/hammerlab/received_events","type":"Organization","site_admin":false},"repo":{"id":18748250,"name":"guacamole","full_name":"hammerlab/guacamole","owner":{"login":"hammerlab","id":6563873,"avatar_url":"https://avatars.githubusercontent.com/u/6563873?v=3","gravatar_id":"","url":"https://api.github.com/users/hammerlab","html_url":"https://github.com/hammerlab","followers_url":"https://api.github.com/users/hammerlab/followers","following_url":"https://api.github.com/users/hammerlab/following{/other_user}","gists_url":"https://api.github.com/users/hammerlab/gists{/gist_id}","starred_url":"https://api.github.com/users/hammerlab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hammerlab/subscriptions","organizations_url":"https://api.github.com/users/hammerlab/orgs","repos_url":"https://api.github.com/users/hammerlab/repos","events_url":"https://api.github.com/users/hammerlab/events{/privacy}","received_events_url":"https://api.github.com/users/hammerlab/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/hammerlab/guacamole","description":"Simple Spark-based variant calling","fork":false,"url":"https://api.github.com/repos/hammerlab/guacamole","forks_url":"https://api.github.com/repos/hammerlab/guacamole/forks","keys_url":"https://api.github.com/repos/hammerlab/guacamole/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hammerlab/guacamole/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hammerlab/guacamole/teams","hooks_url":"https://api.github.com/repos/hammerlab/guacamole/hooks","issue_events_url":"https://api.github.com/repos/hammerlab/guacamole/issues/events{/number}","events_url":"https://api.github.com/repos/hammerlab/guacamole/events","assignees_url":"https://api.github.com/repos/hammerlab/guacamole/assignees{/user}","branches_url":"https://api.github.com/repos/hammerlab/guacamole/branches{/branch}","tags_url":"https://api.github.com/repos/hammerlab/guacamole/tags","blobs_url":"https://api.github.com/repos/hammerlab/guacamole/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hammerlab/guacamole/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hammerlab/guacamole/git/refs{/sha}","trees_url":"https://api.github.com/repos/hammerlab/guacamole/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hammerlab/guacamole/statuses/{sha}","languages_url":"https://api.github.com/repos/hammerlab/guacamole/languages","stargazers_url":"https://api.github.com/repos/hammerlab/guacamole/stargazers","contributors_url":"https://api.github.com/repos/hammerlab/guacamole/contributors","subscribers_url":"https://api.github.com/repos/hammerlab/guacamole/subscribers","subscription_url":"https://api.github.com/repos/hammerlab/guacamole/subscription","commits_url":"https://api.github.com/repos/hammerlab/guacamole/commits{/sha}","git_commits_url":"https://api.github.com/repos/hammerlab/guacamole/git/commits{/sha}","comments_url":"https://api.github.com/repos/hammerlab/guacamole/comments{/number}","issue_comment_url":"https://api.github.com/repos/hammerlab/guacamole/issues/comments{/number}","contents_url":"https://api.github.com/repos/hammerlab/guacamole/contents/{+path}","compare_url":"https://api.github.com/repos/hammerlab/guacamole/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hammerlab/guacamole/merges","archive_url":"https://api.github.com/repos/hammerlab/guacamole/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hammerlab/guacamole/downloads","issues_url":"https://api.github.com/repos/hammerlab/guacamole/issues{/number}","pulls_url":"https://api.github.com/repos/hammerlab/guacamole/pulls{/number}","milestones_url":"https://api.github.com/repos/hammerlab/guacamole/milestones{/number}","notifications_url":"https://api.github.com/repos/hammerlab/guacamole/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hammerlab/guacamole/labels{/name}","releases_url":"https://api.github.com/repos/hammerlab/guacamole/releases{/id}","created_at":"2014-04-14T04:22:46Z","updated_at":"2015-07-10T00:44:32Z","pushed_at":"2015-07-22T21:01:05Z","git_url":"git://github.com/hammerlab/guacamole.git","ssh_url":"git@github.com:hammerlab/guacamole.git","clone_url":"https://github.com/hammerlab/guacamole.git","svn_url":"https://github.com/hammerlab/guacamole","homepage":"","size":46822,"stargazers_count":42,"watchers_count":42,"language":"Scala","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":9,"mirror_url":null,"open_issues_count":35,"forks":9,"open_issues":35,"watchers":42,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/hammerlab/guacamole/pulls/334"},"html":{"href":"https://github.com/hammerlab/guacamole/pull/334"},"issue":{"href":"https://api.github.com/repos/hammerlab/guacamole/issues/334"},"comments":{"href":"https://api.github.com/repos/hammerlab/guacamole/issues/334/comments"},"review_comments":{"href":"https://api.github.com/repos/hammerlab/guacamole/pulls/334/comments"},"review_comment":{"href":"https://api.github.com/repos/hammerlab/guacamole/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/hammerlab/guacamole/pulls/334/commits"},"statuses":{"href":"https://api.github.com/repos/hammerlab/guacamole/statuses/86aec297b422922dae2c9c224b1e25ad7304d4f2"}}}}