package fr.ens.biologie.genomique.eoulsan.modules.mapping.local; import static com.google.common.base.Preconditions.checkArgument; import fr.ens.biologie.genomique.eoulsan.EoulsanLogger; import htsjdk.samtools.SAMFileHeader.SortOrder; import htsjdk.samtools.SAMFileWriter; import htsjdk.samtools.SAMFileWriterFactory; import htsjdk.samtools.SAMRecord; import htsjdk.samtools.SamInputResource; import htsjdk.samtools.SamReader; import htsjdk.samtools.SamReaderFactory; import java.io.File; import java.io.IOException; import fr.ens.biologie.genomique.eoulsan.annotations.LocalOnly; import fr.ens.biologie.genomique.eoulsan.core.TaskContext; import fr.ens.biologie.genomique.eoulsan.core.TaskResult; import fr.ens.biologie.genomique.eoulsan.core.TaskStatus; import fr.ens.biologie.genomique.eoulsan.data.Data; import fr.ens.biologie.genomique.eoulsan.data.DataFile; import fr.ens.biologie.genomique.eoulsan.data.DataFormats; import fr.ens.biologie.genomique.eoulsan.modules.mapping.AbstractSAM2BAMModule; import fr.ens.biologie.genomique.eoulsan.util.LocalReporter; import fr.ens.biologie.genomique.eoulsan.util.Reporter; /** * This class define a module for converting SAM files into BAM. * @since 2.0 * @author Laurent Jourdren */ @LocalOnly public class SAM2BAMLocalModule extends AbstractSAM2BAMModule { @Override public TaskResult execute(final TaskContext context, final TaskStatus status) { try { // Create the reporter final Reporter reporter = new LocalReporter(); // Get input SAM data final Data inData = context.getInputData(DataFormats.MAPPER_RESULTS_SAM); // Get output BAM data final Data outBAMData = context.getOutputData(DataFormats.MAPPER_RESULTS_BAM, inData); // Get output BAM data final Data outBAIData = context.getOutputData(DataFormats.MAPPER_RESULTS_INDEX_BAI, inData); final DataFile samFile = inData.getDataFile(); final DataFile bamFile = outBAMData.getDataFile(); final DataFile bamIndexFile = outBAIData.getDataFile(); convert(samFile, bamFile, bamIndexFile, getCompressionLevel(), reporter, context.getLocalTempDirectory()); // Set the description of the context status.setDescription("Convert alignments (" + inData.getName() + ", " + samFile.getName() + ", " + bamFile.getName() + "," + bamIndexFile.getName() + ")"); // Add counters for this sample to log file status.setCounters(reporter, COUNTER_GROUP); return status.createTaskResult(); } catch (final IOException e) { return status.createTaskResult(e); } } /** * Convert SAM file to sorted BAM with Picard * @param samDataFile input SAM file * @param bamDataFile output SAM file * @param bamIndexDataFile output index file * @param compressionLevel compression level * @param reporter reporter * @param tmpDir temporary directory * @throws IOException if an error occurs */ private static void convert(final DataFile samDataFile, final DataFile bamDataFile, final DataFile bamIndexDataFile, final int compressionLevel, final Reporter reporter, final File tmpDir) throws IOException { checkArgument(compressionLevel >= 0 && compressionLevel <= 9, "Invalid compression level [0-9]: " + compressionLevel); // Open sam file final SamReader samReader = SamReaderFactory.makeDefault() .open(SamInputResource.of(samDataFile.open())); // Force sort samReader.getFileHeader().setSortOrder(SortOrder.coordinate); // Get Bam file final File bamFile = bamDataFile.toFile(); // Open Bam file final SAMFileWriter samWriter = new SAMFileWriterFactory() .setCreateIndex(true).setTempDirectory(tmpDir).makeBAMWriter( samReader.getFileHeader(), false, bamFile, compressionLevel); for (final SAMRecord samRecord : samReader) { samWriter.addAlignment(samRecord); reporter.incrCounter(COUNTER_GROUP, "sorted records", 1); } // Change index bai file final String bamIndexFilename = bamDataFile.getName().substring(0, bamDataFile.getName().length() - 1) + "i"; final File bamIndexFile = new File(bamDataFile.toFile().getParentFile(), bamIndexFilename); if (!bamIndexFile.renameTo(bamIndexDataFile.toFile())) { EoulsanLogger.getLogger().warning("Unable to rename the BAI file " + bamIndexFile + " to " + bamIndexDataFile.toFile()); } // Create a symbolic link bamIndexDataFile.symlink(new DataFile(bamIndexFile), true); samReader.close(); samWriter.close(); } }