The launchpad for ProTECT. The DAG for ProTECT can be viewed in Flowchart.txt.

    :param dict patient_data: Dict of information regarding the input sequences for the patient
    :param dict univ_options: Dict of universal options used by almost all tools
    :param dict tool_options: Options for the various tools

def launch_protect(job, patient_data, univ_options, tool_options):
    """
    The launchpad for ProTECT. The DAG for ProTECT can be viewed in Flowchart.txt.

    :param dict patient_data: Dict of information regarding the input sequences for the patient
    :param dict univ_options: Dict of universal options used by almost all tools
    :param dict tool_options: Options for the various tools
    """
    # Add Patient id to univ_options as is is passed to every major node in the DAG and can be used
    # as a prefix for the logfile.
    univ_options['patient'] = patient_data['patient_id']
    univ_options['tumor_type'] = patient_data['tumor_type']
    # Ascertain number of cpus to use per job
    for tool in tool_options:
        tool_options[tool]['n'] = ascertain_cpu_share(univ_options['max_cores'])
    # Define the various nodes in the DAG
    # Need a logfile and a way to send it around
    sample_prep = job.wrapJobFn(prepare_samples, patient_data, univ_options, disk='40G')
    job.addChild(sample_prep)
    # Define the fastq deletion step
    fastq_deletion_1 = job.wrapJobFn(delete_fastqs, sample_prep.rv(), disk='100M', memory='100M')
    sample_prep.addChild(fastq_deletion_1)
    # Get all the input files
    haplotype_patient = get_mutations = None
    fastq_files = defaultdict(lambda: None)
    bam_files = defaultdict(lambda: None)
    delete_bam_files = defaultdict(lambda: None)
    phlat_files = defaultdict(lambda: None)
    for sample_type in 'tumor_dna', 'normal_dna', 'tumor_rna':
        if sample_type + '_fastq_1' in patient_data:
            fastq_files[sample_type] = job.wrapJobFn(get_patient_fastqs, sample_prep.rv(),
                                                     sample_type, disk='10M')
            sample_prep.addChild(fastq_files[sample_type])
            fastq_files[sample_type].addChild(fastq_deletion_1)
        elif sample_type + '_bam' in patient_data:
            bam_files[sample_type] = job.wrapJobFn(get_patient_bams, sample_prep.rv(), sample_type,
                                                   univ_options, tool_options['bwa'],
                                                   tool_options['mutect'],
                                                   disk='10M').encapsulate()
            sample_prep.addChild(bam_files[sample_type])

    # define the haplotyping subgraph of the DAG
    if 'hla_haplotype_files' in patient_data:
        haplotype_patient = job.wrapJobFn(get_patient_mhc_haplotype, sample_prep.rv())
        sample_prep.addChild(haplotype_patient)
    else:
        assert None not in fastq_files.values()
        # We are guaranteed to have fastqs here
        for sample_type in 'tumor_dna', 'normal_dna', 'tumor_rna':
            phlat_files[sample_type] = job.wrapJobFn(
                run_phlat, fastq_files[sample_type].rv(), sample_type, univ_options,
                tool_options['phlat'], cores=tool_options['phlat']['n'],
                disk=PromisedRequirement(phlat_disk, fastq_files[sample_type].rv()))
            fastq_files[sample_type].addChild(phlat_files[sample_type])
            phlat_files[sample_type].addChild(fastq_deletion_1)
        haplotype_patient = job.wrapJobFn(merge_phlat_calls,
                                          phlat_files['tumor_dna'].rv(),
                                          phlat_files['normal_dna'].rv(),
                                          phlat_files['tumor_rna'].rv(),
                                          univ_options, disk='100M', memory='100M', cores=1)
        phlat_files['tumor_dna'].addChild(haplotype_patient)
        phlat_files['normal_dna'].addChild(haplotype_patient)
        phlat_files['tumor_rna'].addChild(haplotype_patient)

    # Define the RNA-Seq Alignment subgraph if needed
    if bam_files['tumor_rna'] is None:
        if ('fusion_bedpe' in patient_data and 'expression_files' in patient_data and
                'mutation_vcf' not in patient_data):
            # If we are processing only fusions, and we have precomputed expression values, we don't
            # need to align the rna
            fusions = job.wrapJobFn(get_patient_bedpe, sample_prep.rv())
            sample_prep.addChild(fusions)
            bam_files['tumor_rna'] = job.wrapJobFn(dummy_job, {}, disk='1M', memory='1M', cores=1)
            sample_prep.addChild(bam_files['tumor_rna'])
        else:
            assert fastq_files['tumor_rna'] is not None
            cutadapt = job.wrapJobFn(run_cutadapt, fastq_files['tumor_rna'].rv(), univ_options,
                                     tool_options['cutadapt'], cores=1,
                                     disk=PromisedRequirement(cutadapt_disk,
                                                              fastq_files['tumor_rna'].rv()))
            bam_files['tumor_rna'] = job.wrapJobFn(align_rna, cutadapt.rv(), univ_options,
                                                   tool_options['star'], cores=1,
                                                   disk='100M').encapsulate()
            fastq_deletion_2 = job.wrapJobFn(delete_fastqs, {'cutadapted_rnas': cutadapt.rv()},
                                             disk='100M', memory='100M')
            fastq_files['tumor_rna'].addChild(cutadapt)
            cutadapt.addChild(fastq_deletion_1)
            cutadapt.addChild(fastq_deletion_2)
            cutadapt.addChild(bam_files['tumor_rna'])
            bam_files['tumor_rna'].addChild(fastq_deletion_2)
            # Define the fusion calling node
            if 'fusion_bedpe' not in patient_data:
                tool_options['star_fusion']['index'] = tool_options['star']['index']
                tool_options['fusion_inspector']['index'] = tool_options['star']['index']
                fusions = job.wrapJobFn(wrap_fusion,
                                        cutadapt.rv(),
                                        bam_files['tumor_rna'].rv(),
                                        univ_options,
                                        tool_options['star_fusion'],
                                        tool_options['fusion_inspector'],
                                        disk='100M', memory='100M', cores=1).encapsulate()
            else:
                fusions = job.wrapJobFn(get_patient_bedpe, sample_prep.rv())
                sample_prep.addChild(fusions)
            bam_files['tumor_rna'].addChild(fusions)
            fusions.addChild(fastq_deletion_1)
            fusions.addChild(fastq_deletion_2)
    else:
        # Define the fusion calling node
        if 'fusion_bedpe' in patient_data:
            fusions = job.wrapJobFn(get_patient_bedpe, sample_prep.rv())
            sample_prep.addChild(fusions)
        else:
            if tool_options['star_fusion']['run'] is True:
                job.fileStore.logToMaster('Input RNA bams were provided for sample %s. Fusion '
                                          'detection can only be run with input '
                                          'fastqs.' % univ_options['patient'])
            fusions = None

    # Define the Expression estimation node
    if 'expression_files' in patient_data:
        rsem = job.wrapJobFn(get_patient_expression, sample_prep.rv())
        sample_prep.addChild(rsem)
    else:
        rsem = job.wrapJobFn(wrap_rsem, bam_files['tumor_rna'].rv(), univ_options,
                             tool_options['rsem'], cores=1, disk='100M').encapsulate()
        bam_files['tumor_rna'].addChild(rsem)
    # Define the bam deletion node
    delete_bam_files['tumor_rna'] = job.wrapJobFn(delete_bams,
                                                  bam_files['tumor_rna'].rv(),
                                                  univ_options['patient'],
                                                  disk='100M',
                                                  memory='100M')
    bam_files['tumor_rna'].addChild(delete_bam_files['tumor_rna'])
    rsem.addChild(delete_bam_files['tumor_rna'])
    if fusions:
        fusions.addChild(delete_bam_files['tumor_rna'])
    # Define the reporting leaves
    if phlat_files['tumor_rna'] is not None:
        mhc_pathway_assessment = job.wrapJobFn(run_mhc_gene_assessment, rsem.rv(),
                                               phlat_files['tumor_rna'].rv(), univ_options,
                                               tool_options['reports'], disk='100M',
                                               memory='100M', cores=1)
        rsem.addChild(mhc_pathway_assessment)
        phlat_files['tumor_rna'].addChild(mhc_pathway_assessment)
    else:
        mhc_pathway_assessment = job.wrapJobFn(run_mhc_gene_assessment, rsem.rv(), None,
                                               univ_options, tool_options['reports'],
                                               disk='100M', memory='100M', cores=1)
        rsem.addChild(mhc_pathway_assessment)
    itx_resistance_assessment = job.wrapJobFn(run_itx_resistance_assessment, rsem.rv(),
                                              univ_options, tool_options['reports'],
                                              disk='100M', memory='100M', cores=1)
    rsem.addChild(itx_resistance_assessment)
    car_t_validity_assessment = job.wrapJobFn(run_car_t_validity_assessment, rsem.rv(),
                                              univ_options, tool_options['reports'],
                                              disk='100M', memory='100M', cores=1)
    rsem.addChild(car_t_validity_assessment)
    # Define the DNA-Seq alignment and mutation calling subgraphs if necessary
    if 'mutation_vcf' in patient_data:
        get_mutations = job.wrapJobFn(get_patient_vcf, sample_prep.rv())
        sample_prep.addChild(get_mutations)
    elif 'fusion_bedpe' in patient_data:
        # Fusions have been handled above, and we don't need to align DNA
        get_mutations = None
    else:
        assert (None, None) not in zip(fastq_files.values(), bam_files.values())
        for sample_type in 'tumor_dna', 'normal_dna':
            if bam_files[sample_type] is None:
                assert fastq_files[sample_type] is not None
                bam_files[sample_type] = job.wrapJobFn(align_dna, fastq_files[sample_type].rv(),
                                                       sample_type, univ_options,
                                                       tool_options['bwa'], cores=1,
                                                       disk='100M').encapsulate()
                fastq_files[sample_type].addChild(bam_files[sample_type])
                bam_files[sample_type].addChild(fastq_deletion_1)
            else:
                # We already have the bam ready to go
                pass
            delete_bam_files[sample_type] = job.wrapJobFn(delete_bams,
                                                          bam_files[sample_type].rv(),
                                                          univ_options['patient'], disk='100M',
                                                          memory='100M')
            bam_files[sample_type].addChild(delete_bam_files[sample_type])
        # Time to call mutations
        mutations = {
            'radia': job.wrapJobFn(run_radia, bam_files['tumor_rna'].rv(),
                                   bam_files['tumor_dna'].rv(), bam_files['normal_dna'].rv(),
                                   univ_options, tool_options['radia'],
                                   disk='100M').encapsulate(),
            'mutect': job.wrapJobFn(run_mutect, bam_files['tumor_dna'].rv(),
                                    bam_files['normal_dna'].rv(), univ_options,
                                    tool_options['mutect'], disk='100M').encapsulate(),
            'muse': job.wrapJobFn(run_muse, bam_files['tumor_dna'].rv(),
                                  bam_files['normal_dna'].rv(), univ_options,
                                  tool_options['muse']).encapsulate(),
            'somaticsniper': job.wrapJobFn(run_somaticsniper, bam_files['tumor_dna'].rv(),
                                           bam_files['normal_dna'].rv(), univ_options,
                                           tool_options['somaticsniper']).encapsulate(),
            'strelka': job.wrapJobFn(run_strelka, bam_files['tumor_dna'].rv(),
                                     bam_files['normal_dna'].rv(), univ_options,
                                     tool_options['strelka']).encapsulate(),
            'indels': job.wrapJobFn(run_indel_caller, bam_files['tumor_dna'].rv(),
                                    bam_files['normal_dna'].rv(), univ_options, 'indel_options',
                                    disk='100M', memory='100M', cores=1)}
        for sample_type in 'tumor_dna', 'normal_dna':
            for caller in mutations:
                bam_files[sample_type].addChild(mutations[caller])
        bam_files['tumor_rna'].addChild(mutations['radia'])
        get_mutations = job.wrapJobFn(run_mutation_aggregator,
                                      {caller: cjob.rv() for caller, cjob in mutations.items()},
                                      univ_options, disk='100M', memory='100M',
                                      cores=1).encapsulate()
        for caller in mutations:
            mutations[caller].addChild(get_mutations)
        # We don't need the normal dna bam any more
        get_mutations.addChild(delete_bam_files['normal_dna'])
        # We may need the tumor one depending on OxoG
        if not patient_data['filter_for_OxoG']:
            get_mutations.addChild(delete_bam_files['tumor_dna'])

    if get_mutations is not None:
        snpeff = job.wrapJobFn(run_snpeff, get_mutations.rv(), univ_options, tool_options['snpeff'],
                               disk=PromisedRequirement(snpeff_disk,
                                                        tool_options['snpeff']['index']))
        get_mutations.addChild(snpeff)
    else:
        snpeff = None

    # The rest of the subgraph should be unchanged
    tumor_dna_bam = bam_files['tumor_dna'].rv() if patient_data['filter_for_OxoG'] else None
    fusion_calls = fusions.rv() if fusions else None
    snpeffed_calls = snpeff.rv() if snpeff else None
    transgene = job.wrapJobFn(run_transgene, snpeffed_calls, bam_files['tumor_rna'].rv(),
                              univ_options, tool_options['transgene'],
                              disk=PromisedRequirement(transgene_disk, bam_files['tumor_rna'].rv()),
                              memory='100M', cores=1, tumor_dna_bam=tumor_dna_bam,
                              fusion_calls=fusion_calls)
    if snpeff:
        snpeff.addChild(transgene)
    bam_files['tumor_rna'].addChild(transgene)
    transgene.addChild(delete_bam_files['tumor_rna'])
    if patient_data['filter_for_OxoG']:
        bam_files['tumor_dna'].addChild(transgene)
        transgene.addChild(delete_bam_files['tumor_dna'])
    if fusions:
        fusions.addChild(transgene)

    spawn_mhc = job.wrapJobFn(spawn_antigen_predictors, transgene.rv(), haplotype_patient.rv(),
                              univ_options, (tool_options['mhci'], tool_options['mhcii']),
                              disk='100M', memory='100M', cores=1).encapsulate()
    haplotype_patient.addChild(spawn_mhc)
    transgene.addChild(spawn_mhc)

    merge_mhc = job.wrapJobFn(merge_mhc_peptide_calls, spawn_mhc.rv(), transgene.rv(), univ_options,
                              disk='100M', memory='100M', cores=1)
    spawn_mhc.addFollowOn(merge_mhc)
    transgene.addChild(merge_mhc)

    rankboost = job.wrapJobFn(wrap_rankboost, rsem.rv(), merge_mhc.rv(), transgene.rv(),
                              univ_options, tool_options['rankboost'], disk='100M', memory='100M',
                              cores=1)
    rsem.addChild(rankboost)
    merge_mhc.addChild(rankboost)
    transgene.addChild(rankboost)
    report_success = job.wrapJobFn(email_report, univ_options)
    rankboost.addChild(report_success)
    return None