/******************************************************************************* * GenPlay, Einstein Genome Analyzer * Copyright (C) 2009, 2014 Albert Einstein College of Medicine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * Authors: Julien Lajugie <julien.lajugie@einstein.yu.edu> * Nicolas Fourel <nicolas.fourel@einstein.yu.edu> * Eric Bouhassira <eric.bouhassira@einstein.yu.edu> * * Website: <http://genplay.einstein.yu.edu> ******************************************************************************/ package edu.yu.einstein.genplay.core.operation.geneList; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.Callable; import edu.yu.einstein.genplay.core.manager.project.ProjectManager; import edu.yu.einstein.genplay.core.operation.Operation; import edu.yu.einstein.genplay.core.operationPool.OperationPool; import edu.yu.einstein.genplay.dataStructure.chromosome.Chromosome; import edu.yu.einstein.genplay.dataStructure.enums.ScoreOperation; import edu.yu.einstein.genplay.dataStructure.enums.Strand; import edu.yu.einstein.genplay.dataStructure.gene.Gene; import edu.yu.einstein.genplay.dataStructure.list.genomeWideList.SCWList.binList.BinList; import edu.yu.einstein.genplay.dataStructure.list.genomeWideList.geneList.GeneList; import edu.yu.einstein.genplay.dataStructure.list.listView.ListView; import edu.yu.einstein.genplay.util.ListView.SCWListViews; /** * Shows the distribution of the scores around the start position of each gene. * @author Julien Lajugie */ public class GLOScoreDistributionAroundStart implements Operation<double[][]> { private boolean stopped = false; // true if the operation must be stopped private final GeneList geneList; // input gene list private final BinList binList; // input bin list private final boolean[] selectedChromosomes; // selected chromosomes private final int binSize; // size of the bins of scores private final int binCount; // number of bins each side of the zero position private final ScoreOperation scoreOperation; // method for the calculation of the bin of scores /** * Creates an instance of {@link GLOScoreDistributionAroundStart}. * Shows the distribution of the scores around the start position of each gene. * @param geneList input gene list * @param binList list containing the scores * @param selectedChromosomes chromosome on which we show the distribution * @param binSize size of the bins of score * @param binCount count of bins each side of the promoter * @param scoreCalculationMethod {@link ScoreOperation} to compute the score of the bins */ public GLOScoreDistributionAroundStart(GeneList geneList, BinList binList, boolean[] selectedChromosomes, int binSize, int binCount, ScoreOperation scoreCalculationMethod) { this.geneList = geneList; this.binList = binList; this.selectedChromosomes = selectedChromosomes; this.binSize = binSize; this.binCount = binCount; scoreOperation = scoreCalculationMethod; } @Override public double[][] compute() throws Exception { final int totalBinCount = (binCount * 2) + 1; double result[][] = new double[totalBinCount][2]; for (int i = -binCount; i <= binCount; i++) { result[i + binCount][0] = i * binSize; } // if the method to compute the score is max // we need to initialize all the score to negative infinity if (scoreOperation == ScoreOperation.MAXIMUM) { for (int i = 0; i < totalBinCount; i++) { result[i][1] = Double.NEGATIVE_INFINITY; } } final OperationPool op = OperationPool.getInstance(); final Collection<Callable<double[]>> threadList = new ArrayList<Callable<double[]>>(); for (int i = 0; (i < geneList.size()) && !stopped; i++) { final Chromosome currentChromo = ProjectManager.getInstance().getProjectChromosomes().get(i); if (((selectedChromosomes == null) || ((i < selectedChromosomes.length) && (selectedChromosomes[i]))) && (geneList.get(i) != null) && (binList.get(i) != null)) { final ListView<Gene> currentGeneList = geneList.get(i); Callable<double[]> currentThread = new Callable<double[]>() { @Override public double[] call() throws Exception { double[] chromoResult = new double[totalBinCount]; // if the method to compute the score is max // we need to initialize all the score to negative infinity if (scoreOperation == ScoreOperation.MAXIMUM) { for (int j = 0; j < totalBinCount; j++) { chromoResult[j] = Double.NEGATIVE_INFINITY; } } int[] count = new int[totalBinCount]; for (Gene currentGene: currentGeneList) { int startPos; if (currentGene.getStrand().equals(Strand.FIVE)) { startPos = currentGene.getStart() - (binCount * binSize); } else { startPos = currentGene.getStop() + (binCount * binSize); } for (int j = 0; j < totalBinCount; j++) { double currentScore; if (currentGene.getStrand().equals(Strand.FIVE)) { if (startPos >= 0) { currentScore = SCWListViews.average(binList.get(currentChromo), startPos, startPos + binSize); } else { currentScore = 0; } startPos += binSize; } else { if ((startPos - binSize) >= 0) { currentScore = SCWListViews.average(binList.get(currentChromo), startPos - binSize, startPos); } else { currentScore = 0; } startPos -= binSize; } switch (scoreOperation) { case AVERAGE: if (currentScore != 0) { chromoResult[j] += currentScore; count[j]++; } break; case MAXIMUM: chromoResult[j] = Math.max(chromoResult[j], currentScore); break; case ADDITION: chromoResult[j] += currentScore; break; default: throw new InvalidParameterException("Operation " + scoreOperation + " cannot be used to compute scores"); } } } // compute the average if it's the method for the score calculation if (scoreOperation == ScoreOperation.AVERAGE) { for (int j = 0; j < totalBinCount; j++) { if (count[j] != 0) { chromoResult[j] /= count[j]; } else { chromoResult[j] = 0; } } } op.notifyDone(); return chromoResult; } }; threadList.add(currentThread); } } List<double[]> threadResult = op.startPool(threadList); if (threadResult == null) { return null; } int[] count = new int[totalBinCount]; for (double [] currentResult: threadResult) { if (currentResult != null) { for (int i = 0; i < currentResult.length; i++) { switch (scoreOperation) { case AVERAGE: if (currentResult[i] != 0) { result[i][1] += currentResult[i]; count[i]++; } break; case MAXIMUM: result[i][1] = Math.max(result[i][1], currentResult[i]); break; case ADDITION: result[i][1] += currentResult[i]; break; default: throw new InvalidParameterException("Operation " + scoreOperation + " cannot be used to compute scores"); } } } } // compute the average if it's the method for the score calculation if (scoreOperation == ScoreOperation.AVERAGE) { for (int i = 0; i < totalBinCount; i++) { if (count[i] != 0) { result[i][1] /= count[i]; } else { result[i][1] = 0; } } } return result; } @Override public String getDescription() { return "Operation: Show Score Distribution Around Gene Start"; } @Override public String getProcessingDescription() { return "Computing Score Distribution"; } @Override public int getStepCount() { return 1; } @Override public void stop() { stopped = true; } }