Commit b9cb7c04 authored by Peter van 't Hof's avatar Peter van 't Hof Committed by GitHub

Merge branch 'develop' into fix-BIOPET-650

parents a12237bd 02292fea
/**
* Biopet is built on top of GATK Queue for building bioinformatic
* pipelines. It is mainly intended to support LUMC SHARK cluster which is running
* SGE. But other types of HPC that are supported by GATK Queue (such as PBS)
* should also be able to execute Biopet tools and pipelines.
*
* Copyright 2014 Sequencing Analysis Support Core - Leiden University Medical Center
*
* Contact us at: sasc@lumc.nl
*
* A dual licensing mode is applied. The source code within this project is freely available for non-commercial use under an AGPL
* license; For commercial users or users who do not want to follow the AGPL
* license, please contact us to obtain a separate license.
*/
package nl.lumc.sasc.biopet.extensions.tools
import java.io.File
import nl.lumc.sasc.biopet.core.summary.Summarizable
import nl.lumc.sasc.biopet.core.ToolCommandFunction
import nl.lumc.sasc.biopet.utils.config.Configurable
import nl.lumc.sasc.biopet.utils.ConfigUtils
import org.broadinstitute.gatk.utils.commandline.{ Argument, Input, Output }
class VcfStatsForSv(val parent: Configurable) extends ToolCommandFunction with Summarizable {
def toolObject = nl.lumc.sasc.biopet.tools.vcfstats.VcfStatsForSv
mainFunction = false
@Input(required = true)
var inputFile: File = _
@Argument(required = true)
var histogramBinBoundaries: Array[Int] = _
@Output(required = true)
var outputFile: File = _
override def defaultCoreMemory = 1.0
override def cmdLine = super.cmdLine +
required("-i", inputFile) +
required("-o", outputFile) +
repeat("--histBinBoundaries", histogramBinBoundaries)
def summaryStats: Map[String, Any] = ConfigUtils.fileToConfigMap(outputFile)
def summaryFiles: Map[String, File] = Map.empty
}
package nl.lumc.sasc.biopet.tools.vcfstats
import java.io.File
import htsjdk.variant.vcf.VCFFileReader
import nl.lumc.sasc.biopet.utils.{ ConfigUtils, ToolCommand }
import scala.collection.JavaConversions._
object VcfStatsForSv extends ToolCommand {
/** Commandline arguments */
case class Args(inputFile: File = null, outputFile: File = null, histBinBoundaries: Array[Int] = Array()) extends AbstractArgs
/** Parsing commandline arguments */
class OptParser extends AbstractOptParser {
opt[File]('i', "inputFile") required () maxOccurs 1 valueName "<file>" action { (x, c) =>
c.copy(inputFile = x)
} validate {
x => if (x.exists) success else failure("Input VCF required")
} text "Input VCF file (required)"
opt[File]('o', "outputFile") required () maxOccurs 1 valueName "<file>" action { (x, c) =>
c.copy(outputFile = x)
} text "Output file (required)"
opt[Int]("histBinBoundaries") required () unbounded () action { (x, c) =>
c.copy(histBinBoundaries = c.histBinBoundaries :+ x)
} text "When counting the records, sv-s are divided to different size classes, this parameter should give the boundaries between these classes."
}
protected var cmdArgs: Args = _
def main(args: Array[String]): Unit = {
val argsParser = new OptParser
cmdArgs = argsParser.parse(args, Args()) getOrElse (throw new IllegalArgumentException)
logger.info(s"Parsing file: ${cmdArgs.inputFile}")
val stats: Map[String, Any] = getVariantCounts(cmdArgs.inputFile, cmdArgs.histBinBoundaries)
ConfigUtils.mapToYamlFile(stats, cmdArgs.outputFile)
}
/** Parses a vcf-file and counts sv-s by type and size. Sv-s are divided to different size classes, the parameter histogramBinBoundaries gives the boundaries between these classes. */
def getVariantCounts(vcfFile: File, histogramBinBoundaries: Array[Int]): Map[String, Any] = {
val delCounts, insCounts, dupCounts, invCounts = Array.fill(histogramBinBoundaries.size + 1) { 0 }
var traCount = 0
val reader = new VCFFileReader(vcfFile, false)
for (record <- reader) {
record.getAttributeAsString("SVTYPE", "") match {
case "TRA" | "CTX" | "ITX" => traCount += 1
case svType => {
val size = record.getEnd - record.getStart
var i = 0
while (i < histogramBinBoundaries.size && size > histogramBinBoundaries(i)) i += 1
svType match {
case "DEL" => delCounts(i) += 1
case "INS" => insCounts(i) += 1
case "DUP" => dupCounts(i) += 1
case "INV" => invCounts(i) += 1
case _ => logger.warn(s"Vcf file contains a record of unknown type: file-$vcfFile, type-$svType")
}
}
}
}
reader.close()
Map("DEL" -> delCounts, "INS" -> insCounts, "DUP" -> dupCounts, "INV" -> invCounts, "TRA" -> traCount)
}
}
......@@ -13,6 +13,11 @@ parser$add_argument('--llabel', dest='llabel', type='character')
parser$add_argument('--title', dest='title', type='character')
parser$add_argument('--hideLegend', dest='hideLegend', type='character', default="false")
parser$add_argument('--removeZero', dest='removeZero', type='character', default="false")
parser$add_argument('--xLog10', dest='xLog10', type='character', default="false")
parser$add_argument('--yLog10', dest='yLog10', type='character', default="false")
parser$add_argument('--xLog10Breaks', dest='xLog10Breaks', nargs='+', type='integer')
parser$add_argument('--xLog10Labels', dest='xLog10Labels', nargs='+', type='character')
arguments <- parser$parse_args()
......@@ -31,14 +36,29 @@ DF1 <- melt(DF, id.var="Rank")
if (arguments$removeZero == "true") DF1 <- DF1[DF1$value > 0, ]
if (arguments$removeZero == "true") print("Removed 0 values")
ggplot(DF1, aes(x = Rank, y = value, group = variable, color = variable)) +
plot = ggplot(DF1, aes(x = Rank, y = value, group = variable, color = variable)) +
xlab(xlab) +
ylab(arguments$ylabel) +
guides(fill=guide_legend(title=arguments$llabel)) +
guides(color=guide_legend(title=arguments$llabel)) +
theme(axis.text.x = element_text(angle = 90, hjust = 1, size = 8)) +
ggtitle(arguments$title) +
theme_bw() +
theme(legend.position = legendPosition) +
geom_line()
if (arguments$xLog10 == "true") {
if (!is.null(arguments$xLog10Labels)) {
scale_x <- scale_x_log10(breaks = arguments$xLog10Breaks, labels=arguments$xLog10Labels)
} else {
scale_x <- scale_x_log10()
}
plot <- plot + scale_x
}
if (arguments$yLog10 == "true") {
plot <- plot + scale_y_log10()
}
plot
dev.off()
......@@ -39,6 +39,13 @@ class LinePlot(val parent: Configurable) extends Rscript {
var hideLegend: Boolean = config("hide_legend", default = false)
var removeZero: Boolean = config("removeZero", default = false)
// whether to use log scale for x and y axis
var xLog10: Boolean = false
var yLog10: Boolean = false
var xLog10AxisTicks: Seq[String] = Seq.empty
var xLog10AxisLabels: Seq[String] = Seq.empty
override def cmd = super.cmd ++
Seq("--input", input.getAbsolutePath) ++
Seq("--output", output.getAbsolutePath) ++
......@@ -49,7 +56,11 @@ class LinePlot(val parent: Configurable) extends Rscript {
llabel.map(Seq("--llabel", _)).getOrElse(Seq()) ++
title.map(Seq("--title", _)).getOrElse(Seq()) ++
(if (hideLegend) Seq("--hideLegend", "true") else Seq()) ++
(if (removeZero) Seq("--removeZero", "true") else Seq())
(if (removeZero) Seq("--removeZero", "true") else Seq()) ++
(if (xLog10) Seq("--xLog10", "true") else Seq()) ++
(if (yLog10) Seq("--yLog10", "true") else Seq()) ++
(if (xLog10AxisTicks.nonEmpty) xLog10AxisTicks.+:("--xLog10Breaks") else Seq()) ++
(if (xLog10AxisLabels.nonEmpty) xLog10AxisLabels.+:("--xLog10Labels") else Seq())
}
object LinePlot {
......
#import(nl.lumc.sasc.biopet.utils.summary.db.SummaryDb)
#import(nl.lumc.sasc.biopet.utils.summary.db.Schema.Sample)
#import(java.io.File)
<%@ var summary: SummaryDb %>
<%@ var allSamples: Seq[Sample]%>
<%@ var rootPath: String %>
<%@ var outputDir: File %>
<%@ var runId: Int %>
<%@ var sampleId: Option[Int] = None %>
<%@ var showPlot: Boolean = false %>
<%@ var showTable: Boolean = true %>
<%@ var showIntro: Boolean = true %>
#{
val sampleNames: Seq[String] = sampleId match {
case Some(sampleId) => Seq(allSamples.filter(s => s.id == sampleId).head.name)
case _ => allSamples.collect({case s: Sample => s.name}).sorted
}
val counts: Map[String, Map[String, Array[Long]]] = ShivaSvCallingReport.parseSummaryForSvCounts(summary, runId, sampleNames)
val traCounts: Map[String, Long] = ShivaSvCallingReport.parseSummaryForTranslocations(summary, runId, sampleNames)
var svTypes = List(
SvTypeForReport("DEL", "Deletions", "svSummaryDeletions.tsv", "svSummaryDeletions.png"),
SvTypeForReport("DUP", "Duplications", "svSummaryDuplications.tsv", "svSummaryDuplications.png"),
SvTypeForReport("INS", "Insertions", "svSummaryInsertions.tsv", "svSummaryInsertions.png"),
SvTypeForReport("INV", "Inversions", "svSummaryInversions.tsv", "svSummaryInversions.png"))
svTypes = svTypes.filter(sv => counts.contains(sv.svType))
val tsvAllTypes = "svSummary.tsv"
ShivaSvCallingReport.writeTsvFiles(sampleNames, counts, svTypes, tsvAllTypes, outputDir)
ShivaSvCallingReport.createPlots(svTypes, outputDir)
}#
#if (showPlot)
<div class="panel-body">
#for (sv <- svTypes)
<img src="${sv.pngFileName}" />
#end
</div>
#if (traCounts.nonEmpty)
<div class="panel-body">
<h5>Number of translocation events detected:</h5>
<table class="table table-condensed" style="width:auto">
<thead><tr>
#for (sampleName <- sampleNames)
<th>${sampleName}</th>
#end
</tr></thead>
<tbody><tr>
#for (sampleName <- sampleNames)
#{
val sampleCount: String = traCounts.get(sampleName) match {
case Some(c) => c.toString()
case None => "-"
}
}#
<td>${sampleCount}</td>
#end
</tr></tbody>
</table>
</div>
#end
<div class="panel-footer">
<button type="button" class="btn btn-info" data-toggle="collapse" data-target="#svSummaryTable">
#if (showTable)
<i class="glyphicon glyphicon-eye-close"></i> Hide tables
#else
<i class="glyphicon glyphicon-eye-open"></i> Show tables
#end
</button>
<a href="${tsvAllTypes}"><button type="button" class="btn btn-info"><i class="glyphicon glyphicon-cloud-download"></i> TSV file</button></a>
</div>
#end
<div class="panel-body collapse #if (showTable)in#end" id="svSummaryTable">
#for (sv <- svTypes)
#{
val countsForSvType: Map[String, Array[Long]] = counts(sv.svType)
val missingCounts: Array[String] = Array.fill(ShivaSvCallingReport.histogramText.size) { "-" }
}#
<h3>${sv.displayText}</h3>
<table class="table sortable-theme-bootstrap" data-sortable>
<thead><tr><th data-sorted="true" data-sorted-direction="ascending">Sample</th>
#for (text <- ShivaSvCallingReport.histogramText)
<th>${text}</th>
#end
</tr></thead>
<tbody>
#for (sampleName <- sampleNames)
<tr>
<td><a href="${rootPath}Samples/${sampleName}/index.html">${sampleName}</a></td>
#{
val sampleCounts: Array[String] = countsForSvType.get(sampleName) match {
case Some(c: Array[_]) => c.collect({case x => x.toString()})
case None => missingCounts
}
}#
#for (countForSize <- sampleCounts)
<td>${countForSize}</td>
#end
</tr>
#end
</tbody>
</table>
#end
</div>
......@@ -48,13 +48,22 @@ trait ShivaReportTrait extends MultisampleMappingReportTrait {
case _ => false
}
def svCallingExecuted = summary.getSettingKeys(runId, "shiva", NoModule, keyValues = Map("sv_calling" -> List("sv_calling"))).get("sv_calling")
.flatten match {
case Some(true) => true
case _ => false
}
override def frontSection = ReportSection("/nl/lumc/sasc/biopet/pipelines/shiva/shivaFront.ssp")
override def pipelineName = "shiva"
override def additionalSections = super.additionalSections ++ (if (variantcallingExecuted) List("Variantcalling" -> ReportSection("/nl/lumc/sasc/biopet/pipelines/shiva/sampleVariants.ssp",
Map("showPlot" -> true, "showTable" -> false)))
else Nil)
override def additionalSections = {
val params = Map("showPlot" -> true, "showTable" -> false)
super.additionalSections ++
(if (variantcallingExecuted) List("SNV Calling" -> ReportSection("/nl/lumc/sasc/biopet/pipelines/shiva/sampleVariants.ssp", params)) else Nil) ++
(if (svCallingExecuted) List("SV Calling" -> ReportSection("/nl/lumc/sasc/biopet/pipelines/shiva/sampleVariantsSv.ssp", params)) else Nil)
}
/** Root page for the shiva report */
override def indexPage: Future[ReportPage] = Future {
......@@ -107,9 +116,10 @@ trait ShivaReportTrait extends MultisampleMappingReportTrait {
/** Single sample page */
override def samplePage(sampleId: Int, args: Map[String, Any]): Future[ReportPage] = Future {
val variantcallingSection = if (variantcallingExecuted) List("Variantcalling" -> ReportSection("/nl/lumc/sasc/biopet/pipelines/shiva/sampleVariants.ssp")) else Nil
val variantcallingSection = if (variantcallingExecuted) List("SNV Calling" -> ReportSection("/nl/lumc/sasc/biopet/pipelines/shiva/sampleVariants.ssp")) else Nil
val svSection = if (svCallingExecuted) List("SV Calling" -> ReportSection("/nl/lumc/sasc/biopet/pipelines/shiva/sampleVariantsSv.ssp")) else Nil
val oldPage: ReportPage = super.samplePage(sampleId, args)
oldPage.copy(sections = variantcallingSection ++ oldPage.sections)
oldPage.copy(sections = variantcallingSection ++ svSection ++ oldPage.sections)
}
/** Name of the report */
......@@ -163,4 +173,5 @@ trait ShivaReportTrait extends MultisampleMappingReportTrait {
plot.width = Some(200 + (samples.count(s => sampleId.getOrElse(s) == s) * 10))
plot.runLocal()
}
}
......@@ -14,9 +14,10 @@
*/
package nl.lumc.sasc.biopet.pipelines.shiva
import nl.lumc.sasc.biopet.core.summary.SummaryQScript
import nl.lumc.sasc.biopet.core.{ PipelineCommand, Reference, SampleLibraryTag }
import nl.lumc.sasc.biopet.core.summary.{ Summarizable, SummaryQScript }
import nl.lumc.sasc.biopet.core.{ PipelineCommand, Reference }
import nl.lumc.sasc.biopet.extensions.Pysvtools
import nl.lumc.sasc.biopet.extensions.tools.VcfStatsForSv
import nl.lumc.sasc.biopet.pipelines.shiva.svcallers._
import nl.lumc.sasc.biopet.utils.config.Configurable
import nl.lumc.sasc.biopet.utils.{ BamUtils, Logging }
......@@ -27,7 +28,7 @@ import org.broadinstitute.gatk.queue.QScript
*
* Created by pjvan_thof on 2/26/15.
*/
class ShivaSvCalling(val parent: Configurable) extends QScript with SummaryQScript with SampleLibraryTag with Reference {
class ShivaSvCalling(val parent: Configurable) extends QScript with SummaryQScript with Reference {
qscript =>
def this() = this(null)
......@@ -96,6 +97,21 @@ class ShivaSvCalling(val parent: Configurable) extends QScript with SummaryQScri
// group by "tags"
// sample tagging is however not available within this pipeline
for ((sample, mergedResultFile) <- outputMergedVCFbySample) {
val vcfStats = new VcfStatsForSv(qscript)
vcfStats.inputFile = mergedResultFile
vcfStats.outputFile = new File(outputDir, s".$sample.merged.stats")
vcfStats.histogramBinBoundaries = ShivaSvCallingReport.histogramBinBoundaries
add(vcfStats)
addSummarizable(vcfStats, "vcfstats-sv", Some(sample))
addSummarizable(new Summarizable {
def summaryFiles = Map("output_vcf" -> mergedResultFile)
def summaryStats = Map.empty
}, "merge_variants", Some(sample))
}
addSummaryJobs()
}
......@@ -103,10 +119,11 @@ class ShivaSvCalling(val parent: Configurable) extends QScript with SummaryQScri
protected def callersList: List[SvCaller] = List(new Breakdancer(this), new Clever(this), new Delly(this), new Pindel(this))
/** Settings for the summary */
def summarySettings = Map("sv_callers" -> configCallers.toList)
def summarySettings = Map("sv_callers" -> configCallers.toList, "hist_bin_boundaries" -> ShivaSvCallingReport.histogramBinBoundaries)
/** Files for the summary */
def summaryFiles: Map[String, File] = Map("final_mergedvcf" -> (if (inputBams.size > 1) outputMergedVCF else outputMergedVCFbySample.values.head))
def summaryFiles: Map[String, File] = if (inputBams.size > 1) Map("final_mergedvcf" -> outputMergedVCF) else Map.empty
}
object ShivaSvCalling extends PipelineCommand
\ No newline at end of file
package nl.lumc.sasc.biopet.pipelines.shiva
import java.io.{ File, PrintWriter }
import nl.lumc.sasc.biopet.core.report.ReportBuilder
import nl.lumc.sasc.biopet.utils.Logging
import nl.lumc.sasc.biopet.utils.rscript.LinePlot
import nl.lumc.sasc.biopet.utils.summary.db.SummaryDb
import nl.lumc.sasc.biopet.utils.summary.db.SummaryDb.{ ModuleName, PipelineName, SampleName }
import scala.concurrent.Await
import scala.concurrent.duration.Duration
object ShivaSvCallingReport extends Logging {
implicit lazy val ec = ReportBuilder.ec
val histogramBinBoundaries: Array[Int] = Array(100, 1000, 10000, 100000, 1000000, 10000000)
val histogramPlotTicks: Array[Int] = Array(100, 1000, 10000, 100000, 1000000, 10000000, 100000000)
val histogramText: List[String] = List("<=100bp", "0.1-1kb", "1-10kb", "10-100kb", "0.1-1Mb", "1-10Mb", ">10Mb")
def parseSummaryForSvCounts(summary: SummaryDb, runId: Int, sampleNames: Seq[String]): Map[String, Map[String, Array[Long]]] = {
var delCounts, insCounts, dupCounts, invCounts: Map[String, Array[Long]] = Map()
for (sampleName <- sampleNames) {
val sampleCounts: Map[String, Any] = Await.result(summary.getStat(runId, PipelineName("shivasvcalling"), ModuleName("vcfstats-sv"), SampleName(sampleName)), Duration.Inf).get
for ((svType, counts) <- sampleCounts.collect({ case (k, v: List[_]) => (k, v.toArray[Any]) })) {
val elem: Tuple2[String, Array[Long]] = (sampleName, counts.collect({ case x: Long => x }))
svType match {
case "DEL" => delCounts += elem
case "INS" => insCounts += elem
case "DUP" => dupCounts += elem
case "INV" => invCounts += elem
}
}
}
var result: Map[String, Map[String, Array[Long]]] = Map()
if (delCounts.exists(elem => (elem._2.sum > 0))) result = Map("DEL" -> delCounts)
if (insCounts.exists(elem => (elem._2.sum > 0))) result += ("INS" -> insCounts)
if (dupCounts.exists(elem => (elem._2.sum > 0))) result += ("DUP" -> dupCounts)
if (invCounts.exists(elem => (elem._2.sum > 0))) result += ("INV" -> invCounts)
result
}
def parseSummaryForTranslocations(summary: SummaryDb, runId: Int, sampleNames: Seq[String]): Map[String, Long] = {
var traCounts: Map[String, Long] = Map()
for (sampleName <- sampleNames) {
val counts: Map[String, Any] = Await.result(summary.getStat(runId, PipelineName("shivasvcalling"), ModuleName("vcfstats-sv"), SampleName(sampleName)), Duration.Inf).get
counts.get("TRA") match {
case Some(c: Long) => traCounts += (sampleName -> c)
case Some(c) => logger.error(s"Unable to parse translocation counts from summary db for sample $sampleName (type mismatch, type in the db: ${c.getClass})")
case _ => logger.error(s"Summary db doesn't have translocation counts for sample $sampleName")
}
}
if (traCounts.exists(elem => elem._2 > 0)) traCounts else Map.empty
}
def writeTsvFiles(sampleNames: Seq[String], counts: Map[String, Map[String, Array[Long]]], svTypes: List[SvTypeForReport], outFileAllTypes: String, outDir: File): Unit = {
val tsvWriter = new PrintWriter(new File(outDir, outFileAllTypes))
tsvWriter.print("sv_type\tsample")
histogramText.foreach(bin => tsvWriter.print("\t" + bin))
tsvWriter.println()
val missingCounts: Array[String] = Array.fill(ShivaSvCallingReport.histogramText.size) { "-" }
for (sv <- svTypes) {
val countsForSvType: Map[String, Array[Long]] = counts.getOrElse(sv.svType, Map.empty)
if (countsForSvType.nonEmpty) {
writeTsvFileForSvType(sv, countsForSvType, sampleNames, outDir)
for (sampleName <- sampleNames) {
val sampleCounts: Array[String] = countsForSvType.get(sampleName) match {
case Some(c) => c.collect({ case x => x.toString() })
case None => {
logger.error(s"Internal error, missing sv counts, sample-$sampleName, sv type-${sv.svType}")
missingCounts
}
}
tsvWriter.print(sv.svType + "\t" + sampleName + "\t")
tsvWriter.println(sampleCounts.mkString("\t"))
}
} else {
logger.error(s"Internal error, skipping writing the tsv-file for sv type ${sv.svType}")
}
}
tsvWriter.close()
}
def writeTsvFileForSvType(svType: SvTypeForReport, counts: Map[String, Array[Long]], sampleNames: Seq[String], outDir: File): Unit = {
val tsvWriter = new PrintWriter(new File(outDir, svType.tsvFileName))
tsvWriter.print("histogramBin")
val samplesWithCounts: Seq[String] = sampleNames.filter(x => counts.contains(x))
samplesWithCounts.foreach(sampleName => tsvWriter.print("\t" + sampleName))
tsvWriter.println()
for (i <- histogramPlotTicks.indices) {
tsvWriter.print(histogramPlotTicks(i))
samplesWithCounts.foreach(sampleName => tsvWriter.print("\t" + counts.get(sampleName).get(i)))
tsvWriter.println()
}
tsvWriter.close()
}
def createPlots(svTypes: List[SvTypeForReport], outDir: File): Unit = {
for (sv <- svTypes) {
val tsvFile = new File(outDir, sv.tsvFileName)
val pngFile: File = new File(outDir, sv.pngFileName)
val plot = LinePlot(tsvFile, pngFile,
xlabel = Some(s"${sv.displayText.substring(0, sv.displayText.length - 1)} size"),
ylabel = Some("Number of loci"),
title = Some(sv.displayText),
width = 400,
removeZero = false)
plot.height = Some(300)
plot.llabel = Some("Sample")
plot.xLog10 = true
plot.yLog10 = true
plot.xLog10AxisTicks = histogramPlotTicks.collect({ case x => x.toString() })
plot.xLog10AxisLabels = histogramText
plot.runLocal()
}
}
}
case class SvTypeForReport(svType: String, displayText: String, tsvFileName: String, pngFileName: String)
\ No newline at end of file
......@@ -90,7 +90,7 @@ class ShivaSvCallingTest extends TestNGSuite with Matchers {
pipeline.init()
pipeline.script()
val summaryCallers = pipeline.summarySettings("sv_callers")
val summaryCallers = pipeline.summarySettings.get("sv_callers").get.asInstanceOf[List[String]]
if (delly) assert(summaryCallers.contains("delly"))
else assert(!summaryCallers.contains("delly"))
if (clever) assert(summaryCallers.contains("clever"))
......@@ -182,7 +182,7 @@ class ShivaSvCallingTest extends TestNGSuite with Matchers {
pipeline.init()
pipeline.script()
val summaryCallers = pipeline.summarySettings("sv_callers")
val summaryCallers: List[String] = pipeline.summarySettings.get("sv_callers").get.asInstanceOf[List[String]]
assert(summaryCallers.contains("delly"))
assert(summaryCallers.contains("clever"))
assert(summaryCallers.contains("breakdancer"))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment