package picard.analysis;
import htsjdk.samtools.util.CollectionUtil;
import picard.cmdline.CommandLineProgram;
import picard.cmdline.CommandLineProgramProperties;
import picard.cmdline.Option;
import picard.cmdline.programgroups.Metrics;
import picard.cmdline.StandardOptionDefinitions;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
/**
* Class that is designed to instantiate and execute multiple metrics programs that extend
* SinglePassSamProgram while making only a single pass through the SAM file and supplying
* each program with the records as it goes.
*
* @author Tim Fennell
*/
@CommandLineProgramProperties(
usage = "Takes an input BAM and reference sequence and runs one or more Picard " +
"metrics modules at the same time to cut down on I/O. Currently all programs are run with " +
"default options and fixed output extesions, but this may become more flexible in future.",
usageShort = "A \"meta-metrics\" calculating program that produces multiple metrics for the provided SAM/BAM",
programGroup = Metrics.class
)
public class CollectMultipleMetrics extends CommandLineProgram {
/**
* This interface allows developers to create Programs to run in addition to the ones defined in the Program enum.
*/
public static interface ProgramInterface {
SinglePassSamProgram makeInstance(final String outbase);
}
public static enum Program implements ProgramInterface {
CollectAlignmentSummaryMetrics {
@Override public SinglePassSamProgram makeInstance(final String outbase) {
final CollectAlignmentSummaryMetrics program = new CollectAlignmentSummaryMetrics();
program.OUTPUT = new File(outbase + ".alignment_summary_metrics");
return program;
}
},
CollectInsertSizeMetrics {
@Override
public SinglePassSamProgram makeInstance(final String outbase) {
final CollectInsertSizeMetrics program = new CollectInsertSizeMetrics();
program.OUTPUT = new File(outbase + ".insert_size_metrics");
program.Histogram_FILE = new File(outbase + ".insert_size_Histogram.pdf");
return program;
}
},
QualityScoreDistribution {
public SinglePassSamProgram makeInstance(final String outbase) {
final QualityScoreDistribution program = new QualityScoreDistribution();
program.OUTPUT = new File(outbase + ".quality_distribution_metrics");
program.CHART_OUTPUT = new File(outbase + ".quality_distribution.pdf");
return program;
}
},
MeanQualityByCycle {
public SinglePassSamProgram makeInstance(final String outbase) {
final MeanQualityByCycle program = new MeanQualityByCycle();
program.OUTPUT = new File(outbase + ".quality_by_cycle_metrics");
program.CHART_OUTPUT = new File(outbase + ".quality_by_cycle.pdf");
return program;
}
},
CollectBaseDistributionByCycle {
public SinglePassSamProgram makeInstance(final String outbase) {
final CollectBaseDistributionByCycle program = new CollectBaseDistributionByCycle();
program.OUTPUT = new File(outbase + ".base_distribution_by_cycle_metrics");
program.CHART_OUTPUT = new File(outbase + ".base_distribution_by_cycle.pdf");
return program;
}
};
}
@Option(shortName= StandardOptionDefinitions.INPUT_SHORT_NAME, doc="Input SAM or BAM file.")
public File INPUT;
@Option(shortName=StandardOptionDefinitions.REFERENCE_SHORT_NAME, doc="Reference sequence fasta.", optional=true)
public File REFERENCE_SEQUENCE;
@Option(doc="If true (default), then the sort order in the header file will be ignored.",
shortName = StandardOptionDefinitions.ASSUME_SORTED_SHORT_NAME)
public boolean ASSUME_SORTED = true;
@Option(doc="Stop after processing N reads, mainly for debugging.")
public int STOP_AFTER = 0;
@Option(shortName=StandardOptionDefinitions.OUTPUT_SHORT_NAME, doc="Base name of output files.")
public String OUTPUT;
@Option(doc="List of metrics programs to apply during the pass through the SAM file.")
public List<Program> PROGRAM = CollectionUtil.makeList(Program.values());
/**
* Contents of PROGRAM list is transferred to this list during command-line validation, so that an outside
* developer can invoke this class programmatically and provide alternative Programs to run by calling
* setProgramsToRun().
*/
private List<ProgramInterface> programsToRun;
// Stock main method
public static void main(final String[] args) {
new CollectMultipleMetrics().instanceMainWithExit(args);
}
@Override
protected String[] customCommandLineValidation() {
programsToRun = new ArrayList<ProgramInterface>(PROGRAM);
return super.customCommandLineValidation();
}
/**
* Use this method when invoking CollectMultipleMetrics programmatically to run programs other than the ones
* available via enum. This must be called before doWork().
*/
public void setProgramsToRun(List<ProgramInterface> programsToRun) {
this.programsToRun = programsToRun;
}
@Override public int doWork() {
if (OUTPUT.endsWith(".")) {
OUTPUT = OUTPUT.substring(0, OUTPUT.length()-1);
}
final List<SinglePassSamProgram> programs = new ArrayList<SinglePassSamProgram>();
for (ProgramInterface program : new HashSet<ProgramInterface>(programsToRun)) {
SinglePassSamProgram instance = program.makeInstance(OUTPUT);
// Generally programs should not be accessing these directly but it might make things smoother
// to just set them anyway
instance.INPUT = INPUT;
instance.REFERENCE_SEQUENCE = REFERENCE_SEQUENCE;
instance.setDefaultHeaders(getDefaultHeaders());
programs.add(instance);
}
SinglePassSamProgram.makeItSo(INPUT, REFERENCE_SEQUENCE, ASSUME_SORTED, STOP_AFTER, programs);
return 0;
}
}