MultiSampleQScript.scala 6.01 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
26
27
/**
 * This trait creates a structured way of use multisample pipelines
 */
28
29
30
trait MultiSampleQScript extends SummaryQScript {
  qscript =>

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

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

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

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

52
53
54
55
56
57
58
59
60
      /**
       * Name overules the one from qscript
       * @param summarizable
       * @param name
       */
      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
61
      /** Adds the library jobs */
Peter van 't Hof's avatar
Peter van 't Hof committed
62
      final def addAndTrackJobs(): Unit = {
63
        currentSample = Some(sampleId)
64
        currentLib = Some(libId)
Peter van 't Hof's avatar
Peter van 't Hof committed
65
        addJobs()
66
        qscript.addSummarizable(this, "pipeline", Some(sampleId), Some(libId))
Peter van 't Hof's avatar
Peter van 't Hof committed
67
        currentLib = None
68
69
70
        currentSample = None
      }

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

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

Peter van 't Hof's avatar
Peter van 't Hof committed
77
      /** Function that add library jobs */
Peter van 't Hof's avatar
Peter van 't Hof committed
78
      protected def addJobs()
79
    }
Peter van 't Hof's avatar
Peter van 't Hof committed
80

Peter van 't Hof's avatar
Peter van 't Hof committed
81
    /** Library type, need implementation in pipeline */
82
    type Library <: AbstractLibrary
Peter van 't Hof's avatar
Peter van 't Hof committed
83

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

Peter van 't Hof's avatar
Peter van 't Hof committed
87
88
89
90
91
    /**
     * Factory method for Library class
     * @param id SampleId
     * @return Sample class
     */
Peter van 't Hof's avatar
Peter van 't Hof committed
92
    def makeLibrary(id: String): Library
Peter van 't Hof's avatar
Peter van 't Hof committed
93

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

99
100
101
102
103
104
105
106
107
    /**
     * 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
108
    /** Adds sample jobs */
Peter van 't Hof's avatar
Peter van 't Hof committed
109
    final def addAndTrackJobs(): Unit = {
110
      currentSample = Some(sampleId)
Peter van 't Hof's avatar
Peter van 't Hof committed
111
      addJobs()
112
      qscript.addSummarizable(this, "pipeline", Some(sampleId))
113
114
      currentSample = None
    }
Peter van 't Hof's avatar
Peter van 't Hof committed
115

Peter van 't Hof's avatar
Peter van 't Hof committed
116
    /** Function to add sample jobs */
Peter van 't Hof's avatar
Peter van 't Hof committed
117
    protected def addJobs()
Peter van 't Hof's avatar
Peter van 't Hof committed
118

Peter van 't Hof's avatar
Peter van 't Hof committed
119
    /** function add all libraries in one call */
120
    protected final def addPerLibJobs(): Unit = {
121
      for ((libId, library) <- libraries) {
Peter van 't Hof's avatar
Peter van 't Hof committed
122
        library.addAndTrackJobs()
123
      }
bow's avatar
bow committed
124
125
    }

Peter van 't Hof's avatar
Peter van 't Hof committed
126
127
128
129
130
131
132
133
    /**
     * 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
134
    def sampleDir = new File(outputDir, "samples" + File.separator + sampleId)
135
136
  }

Peter van 't Hof's avatar
Peter van 't Hof committed
137
  /** Sample type, need implementation in pipeline */
Peter van 't Hof's avatar
Peter van 't Hof committed
138
139
  type Sample <: AbstractSample

Peter van 't Hof's avatar
Peter van 't Hof committed
140
141
  /**
   * Factory method for Sample class
142
   * @param id SampleId
Peter van 't Hof's avatar
Peter van 't Hof committed
143
144
   * @return Sample class
   */
145
  def makeSample(id: String): Sample
Peter van 't Hof's avatar
Peter van 't Hof committed
146

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

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

Peter van 't Hof's avatar
Peter van 't Hof committed
153
  /** Runs addAndTrackJobs method for each sample */
Peter van 't Hof's avatar
Peter van 't Hof committed
154
  final def addSamplesJobs() {
155
156
157
158
    if (onlySamples.isEmpty) {
      samples.foreach { case (sampleId, sample) => sample.addAndTrackJobs() }
      addMultiSampleJobs()
    } else onlySamples.foreach(sampleId => samples.get(sampleId) match {
159
160
161
      case Some(sample) => sample.addAndTrackJobs()
      case None         => logger.warn("sampleId '" + sampleId + "' not found")
    })
162
163
  }

164
165
166
167
168
  /**
   * Method where the multisample jobs should be added, this will be executed only when running the -sample argument is not given
   */
  def addMultiSampleJobs()

Peter van 't Hof's avatar
Peter van 't Hof committed
169
  /** Stores sample state */
170
171
  private var currentSample: Option[String] = None

Peter van 't Hof's avatar
Peter van 't Hof committed
172
173
174
175
  /** 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 */
176
  override protected[core] def configFullPath: List[String] = {
Peter van 't Hof's avatar
Peter van 't Hof committed
177
178
179
180
    val s = currentSample match {
      case Some(s) => "samples" :: s :: Nil
      case _       => Nil
    }
Peter van 't Hof's avatar
Peter van 't Hof committed
181
    val l = currentLib match {
Peter van 't Hof's avatar
Peter van 't Hof committed
182
183
184
185
      case Some(l) => "libraries" :: l :: Nil
      case _       => Nil
    }
    s ::: l ::: super.configFullPath
186
  }
187
}