MultiSampleQScript.scala 5.92 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * 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 that are
 * not part of GATK Queue 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.
 */
16
17
package nl.lumc.sasc.biopet.core

18
19
import java.io.File

20
import nl.lumc.sasc.biopet.core.config.{ Config }
21
import nl.lumc.sasc.biopet.core.summary.{ SummaryQScript, Summarizable }
22
import nl.lumc.sasc.biopet.utils.ConfigUtils
Peter van 't Hof's avatar
Peter van 't Hof committed
23
import org.broadinstitute.gatk.utils.commandline.{ Argument }
24

Peter van 't Hof's avatar
Peter van 't Hof committed
25
/** This trait creates a structured way of use multisample pipelines */
26
27
28
trait MultiSampleQScript extends SummaryQScript {
  qscript =>

Peter van 't Hof's avatar
Peter van 't Hof committed
29
  @Argument(doc = "Only Sample", shortName = "sample", required = false)
30
  private val onlySamples: List[String] = Nil
Peter van 't Hof's avatar
Peter van 't Hof committed
31

32
  require(globalConfig.map.contains("samples"), "No Samples found in config")
Peter van 't Hof's avatar
Peter van 't Hof committed
33

Peter van 't Hof's avatar
Peter van 't Hof committed
34
35
36
37
  /**
   * Sample class with basic functions build in
   * @param sampleId
   */
38
  abstract class AbstractSample(val sampleId: String) extends Summarizable {
Peter van 't Hof's avatar
Peter van 't Hof committed
39
    /** Overrules config of qscript with default sample */
Peter van 't Hof's avatar
Peter van 't Hof committed
40
    val config = new ConfigFunctions(defaultSample = sampleId)
Peter van 't Hof's avatar
Peter van 't Hof committed
41

Peter van 't Hof's avatar
Peter van 't Hof committed
42
    /** Library class with basic functions build in */
43
    abstract class AbstractLibrary(val libId: String) extends Summarizable {
Peter van 't Hof's avatar
Peter van 't Hof committed
44
      /** Overrules config of qscript with default sample and default library */
45
      val config = new ConfigFunctions(defaultSample = sampleId, defaultLibrary = libId)
46

Peter van 't Hof's avatar
Peter van 't Hof committed
47
      /** Name overules the one from qscript */
48
49
50
51
      def addSummarizable(summarizable: Summarizable, name: String): Unit = {
        qscript.addSummarizable(summarizable, name, Some(sampleId), Some(libId))
      }

Peter van 't Hof's avatar
Peter van 't Hof committed
52
      /** Adds the library jobs */
Peter van 't Hof's avatar
Peter van 't Hof committed
53
      final def addAndTrackJobs(): Unit = {
54
        currentSample = Some(sampleId)
55
        currentLib = Some(libId)
Peter van 't Hof's avatar
Peter van 't Hof committed
56
        addJobs()
57
        qscript.addSummarizable(this, "pipeline", Some(sampleId), Some(libId))
Peter van 't Hof's avatar
Peter van 't Hof committed
58
        currentLib = None
59
60
61
        currentSample = None
      }

Peter van 't Hof's avatar
Peter van 't Hof committed
62
      /** Creates a library file with given suffix */
63
      def createFile(suffix: String): File = new File(libDir, sampleId + "-" + libId + suffix)
Peter van 't Hof's avatar
Peter van 't Hof committed
64
65

      /** Returns library directory */
Peter van 't Hof's avatar
Peter van 't Hof committed
66
      def libDir = new File(sampleDir, "lib_" + libId)
67

Peter van 't Hof's avatar
Peter van 't Hof committed
68
      /** Function that add library jobs */
Peter van 't Hof's avatar
Peter van 't Hof committed
69
      protected def addJobs()
70
    }
Peter van 't Hof's avatar
Peter van 't Hof committed
71

Peter van 't Hof's avatar
Peter van 't Hof committed
72
    /** Library type, need implementation in pipeline */
73
    type Library <: AbstractLibrary
Peter van 't Hof's avatar
Peter van 't Hof committed
74

Peter van 't Hof's avatar
Peter van 't Hof committed
75
76
    /** Stores all libraries */
    val libraries: Map[String, Library] = libIds.map(id => id -> makeLibrary(id)).toMap
77

Peter van 't Hof's avatar
Peter van 't Hof committed
78
79
80
81
82
    /**
     * Factory method for Library class
     * @param id SampleId
     * @return Sample class
     */
Peter van 't Hof's avatar
Peter van 't Hof committed
83
    def makeLibrary(id: String): Library
Peter van 't Hof's avatar
Peter van 't Hof committed
84

Peter van 't Hof's avatar
Peter van 't Hof committed
85
86
    /** returns a set with library names */
    protected def libIds: Set[String] = {
87
      ConfigUtils.getMapFromPath(globalConfig.map, List("samples", sampleId, "libraries")).getOrElse(Map()).keySet
88
    }
Peter van 't Hof's avatar
Peter van 't Hof committed
89

90
91
92
93
94
95
96
97
98
    /**
     * Name overules the one from qscript
     * @param summarizable
     * @param name
     */
    def addSummarizable(summarizable: Summarizable, name: String): Unit = {
      qscript.addSummarizable(summarizable, name, Some(sampleId))
    }

Peter van 't Hof's avatar
Peter van 't Hof committed
99
    /** Adds sample jobs */
Peter van 't Hof's avatar
Peter van 't Hof committed
100
    final def addAndTrackJobs(): Unit = {
101
      currentSample = Some(sampleId)
Peter van 't Hof's avatar
Peter van 't Hof committed
102
      addJobs()
103
      qscript.addSummarizable(this, "pipeline", Some(sampleId))
104
105
      currentSample = None
    }
Peter van 't Hof's avatar
Peter van 't Hof committed
106

Peter van 't Hof's avatar
Peter van 't Hof committed
107
    /** Function to add sample jobs */
Peter van 't Hof's avatar
Peter van 't Hof committed
108
    protected def addJobs()
Peter van 't Hof's avatar
Peter van 't Hof committed
109

Peter van 't Hof's avatar
Peter van 't Hof committed
110
    /** function add all libraries in one call */
111
    protected final def addPerLibJobs(): Unit = {
112
      for ((libId, library) <- libraries) {
Peter van 't Hof's avatar
Peter van 't Hof committed
113
        library.addAndTrackJobs()
114
      }
bow's avatar
bow committed
115
116
    }

Peter van 't Hof's avatar
Peter van 't Hof committed
117
118
119
120
121
122
123
124
    /**
     * Creates a sample file with given suffix
     * @param suffix
     * @return
     */
    def createFile(suffix: String) = new File(sampleDir, sampleId + suffix)

    /** Returns sample directory */
Peter van 't Hof's avatar
Peter van 't Hof committed
125
    def sampleDir = new File(outputDir, "samples" + File.separator + sampleId)
126
127
  }

Peter van 't Hof's avatar
Peter van 't Hof committed
128
  /** Sample type, need implementation in pipeline */
Peter van 't Hof's avatar
Peter van 't Hof committed
129
130
  type Sample <: AbstractSample

Peter van 't Hof's avatar
Peter van 't Hof committed
131
132
  /**
   * Factory method for Sample class
133
   * @param id SampleId
Peter van 't Hof's avatar
Peter van 't Hof committed
134
135
   * @return Sample class
   */
136
  def makeSample(id: String): Sample
Peter van 't Hof's avatar
Peter van 't Hof committed
137

Peter van 't Hof's avatar
Peter van 't Hof committed
138
139
  /** Stores all samples */
  val samples: Map[String, Sample] = sampleIds.map(id => id -> makeSample(id)).toMap
140

141
  /** Returns a list of all sampleIDs */
142
  protected def sampleIds: Set[String] = ConfigUtils.any2map(globalConfig.map("samples")).keySet
143

Peter van 't Hof's avatar
Peter van 't Hof committed
144
  /** Runs addAndTrackJobs method for each sample */
Peter van 't Hof's avatar
Peter van 't Hof committed
145
  final def addSamplesJobs() {
146
147
148
149
    if (onlySamples.isEmpty) {
      samples.foreach { case (sampleId, sample) => sample.addAndTrackJobs() }
      addMultiSampleJobs()
    } else onlySamples.foreach(sampleId => samples.get(sampleId) match {
150
151
152
      case Some(sample) => sample.addAndTrackJobs()
      case None         => logger.warn("sampleId '" + sampleId + "' not found")
    })
153
154
  }

155
  /**
Peter van 't Hof's avatar
Peter van 't Hof committed
156
   * Method where the multisample jobs should be added, this will be executed only when running the -sample argument is not given.
157
158
159
   */
  def addMultiSampleJobs()

Peter van 't Hof's avatar
Peter van 't Hof committed
160
  /** Stores sample state */
161
162
  private var currentSample: Option[String] = None

Peter van 't Hof's avatar
Peter van 't Hof committed
163
164
165
166
  /** Stores library state */
  private var currentLib: Option[String] = None

  /** Prefix full path with sample and library for jobs that's are created in current state */
167
  override protected[core] def configFullPath: List[String] = {
Peter van 't Hof's avatar
Peter van 't Hof committed
168
169
170
171
    val s = currentSample match {
      case Some(s) => "samples" :: s :: Nil
      case _       => Nil
    }
Peter van 't Hof's avatar
Peter van 't Hof committed
172
    val l = currentLib match {
Peter van 't Hof's avatar
Peter van 't Hof committed
173
174
175
176
      case Some(l) => "libraries" :: l :: Nil
      case _       => Nil
    }
    s ::: l ::: super.configFullPath
177
  }
178
}