/* * Eoulsan development code * * This code may be freely distributed and modified under the * terms of the GNU Lesser General Public License version 2.1 or * later and CeCILL-C. This should be distributed with the code. * If you do not have a copy, see: * * http://www.gnu.org/licenses/lgpl-2.1.txt * http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.txt * * Copyright for this code is held jointly by the Genomic platform * of the Institut de Biologie de l'École normale supérieure and * the individual authors. These should be listed in @author doc * comments. * * For more information on the Eoulsan project and its aims, * or to join the Eoulsan Google group, visit the home page * at: * * http://outils.genomique.biologie.ens.fr/eoulsan * */ package fr.ens.biologie.genomique.eoulsan.modules.diffana; import static fr.ens.biologie.genomique.eoulsan.core.InputPortsBuilder.DEFAULT_SINGLE_INPUT_PORT_NAME; import static fr.ens.biologie.genomique.eoulsan.data.DataFormats.EXPRESSION_RESULTS_TSV; import static fr.ens.biologie.genomique.eoulsan.modules.diffana.DESeq2.FitType.PARAMETRIC; import static fr.ens.biologie.genomique.eoulsan.modules.diffana.DESeq2.SizeFactorsType.RATIO; import static fr.ens.biologie.genomique.eoulsan.modules.diffana.DESeq2.StatisticTest.WALD; import static java.util.Collections.unmodifiableSet; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import fr.ens.biologie.genomique.eoulsan.EoulsanException; import fr.ens.biologie.genomique.eoulsan.Globals; import fr.ens.biologie.genomique.eoulsan.annotations.LocalOnly; import fr.ens.biologie.genomique.eoulsan.core.InputPorts; import fr.ens.biologie.genomique.eoulsan.core.InputPortsBuilder; import fr.ens.biologie.genomique.eoulsan.core.Parameter; import fr.ens.biologie.genomique.eoulsan.core.StepConfigurationContext; 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.core.Version; import fr.ens.biologie.genomique.eoulsan.data.Data; import fr.ens.biologie.genomique.eoulsan.data.DataFile; import fr.ens.biologie.genomique.eoulsan.design.Design; import fr.ens.biologie.genomique.eoulsan.design.DesignUtils; import fr.ens.biologie.genomique.eoulsan.design.Experiment; import fr.ens.biologie.genomique.eoulsan.modules.AbstractModule; import fr.ens.biologie.genomique.eoulsan.modules.diffana.DESeq2.FitType; import fr.ens.biologie.genomique.eoulsan.modules.diffana.DESeq2.SizeFactorsType; import fr.ens.biologie.genomique.eoulsan.modules.diffana.DESeq2.StatisticTest; import fr.ens.biologie.genomique.eoulsan.requirements.Requirement; import fr.ens.biologie.genomique.eoulsan.util.r.RExecutor; /** * Class to run the differential analysis with DEseq2 * @author Xavier Bauquet * @since 2.0 */ @LocalOnly public class DESeq2Module extends AbstractModule { // Module name private static final String MODULE_NAME = "deseq2"; static final String DESEQ2_DOCKER_IMAGE = "bioconductor/release_sequencing:3.1"; // DEseq2 options names private static final String NORMALIZATION_FIGURES = "norm.fig"; private static final String DIFFANA_FIGURES = "diffana.fig"; private static final String NORM_DIFFANA = "norm.diffana"; private static final String DIFFANA = "diffana"; private static final String SIZE_FACTORS_TYPE = "size.factors.type"; private static final String FIT_TYPE = "fit.type"; private static final String STATISTIC_TEST = "statistical.test"; // Default value for DEseq options private boolean normFig = true; private boolean diffanaFig = true; private boolean normDiffana = true; private boolean diffana = true; private SizeFactorsType sizeFactorsType = RATIO; private FitType fitType = PARAMETRIC; private StatisticTest statisticTest = WALD; private Set<Requirement> requirements = new HashSet<>(); private RExecutor executor; // // Module methods // @Override public String getName() { return MODULE_NAME; } @Override public Version getVersion() { return Globals.APP_VERSION; } @Override public InputPorts getInputPorts() { return new InputPortsBuilder() .addPort(DEFAULT_SINGLE_INPUT_PORT_NAME, true, EXPRESSION_RESULTS_TSV) .create(); } @Override public Set<Requirement> getRequirements() { return unmodifiableSet(this.requirements); } @Override public void configure(final StepConfigurationContext context, final Set<Parameter> stepParameters) throws EoulsanException { // Parse R executor parameters final Set<Parameter> parameters = new HashSet<>(stepParameters); this.executor = RModuleCommonConfiguration.parseRExecutorParameter(context, parameters, this.requirements, DESEQ2_DOCKER_IMAGE); for (Parameter p : parameters) { switch (p.getName()) { case NORMALIZATION_FIGURES: this.normFig = parseBoolean(p); break; case DIFFANA_FIGURES: this.diffanaFig = parseBoolean(p); break; case NORM_DIFFANA: this.normDiffana = parseBoolean(p); break; case DIFFANA: this.diffana = parseBoolean(p); break; case SIZE_FACTORS_TYPE: this.sizeFactorsType = DESeq2.SizeFactorsType.get(p); break; case FIT_TYPE: this.fitType = DESeq2.FitType.get(p.getStringValue()); break; case STATISTIC_TEST: this.statisticTest = DESeq2.StatisticTest.get(p.getStringValue()); break; default: throw new EoulsanException( "Unkown parameter for step " + getName() + " : " + p.getName()); } } } /** * Parse a boolean parameter. * @param p the parameter * @return a boolean * @throws EoulsanException if the parameter is not a boolean */ private static boolean parseBoolean(final Parameter p) throws EoulsanException { if (p == null) { throw new NullPointerException("p parameter cannot be null"); } String value = p.getLowerStringValue().trim(); if (!("true".equals(value) || "false".equals(value))) { throw new EoulsanException("Invalid boolean value for parameter " + p.getName() + ": " + p.getValue()); } return p.getBooleanValue(); } @Override public TaskResult execute(final TaskContext context, final TaskStatus status) { // Get the design final Design design = context.getWorkflow().getDesign(); // Get the experiment data final Data expressionData = context.getInputData(EXPRESSION_RESULTS_TSV); // Get the name of expression file by sample final Map<String, File> sampleFiles = new HashMap<>(); for (Data d : expressionData.getListElements()) { sampleFiles.put(d.getName(), d.getDataFile().toFile()); } String stepId = context.getCurrentStep().getId(); try { for (Experiment e : design.getExperiments()) { // Do nothing if the experiment is skipped if (DesignUtils.isSkipped(e)) { continue; } // run DEseq2 new DESeq2(this.executor, stepId, design, e, sampleFiles, this.normFig, this.diffanaFig, this.normDiffana, this.diffana, this.sizeFactorsType, this.fitType, this.statisticTest, context.getSettings().isSaveRscripts()).runDEseq2(context.getOutputDirectory()); } } catch (IOException | EoulsanException e) { return status.createTaskResult(e, "Error while analysis data: " + e.getMessage()); } // Write log file return status.createTaskResult(); } }