/** * Build paths for two partial maps if they have the following properties 1. No overlap (passing * trimOverlap) 2. passing PathBuilderFilter * * @param groupedMap * @param pbFilter * @param vmProcessor * @param maxTrim * @param ear * @return */ private List<ClusterPathNode> buildPath( List<OptMapResultNode> groupedMap, PathBuilderFilter pbFilter, VirtualMapProcessor vmProcessor) { // resulting path will not form loop (i.e. is acyclic), no A->B B->C C->A occurs at any time. // But should handle null start and null stop properly Collections.sort(groupedMap, OptMapResultNode.subfragstartstopcomparator); List<ClusterPathNode> clusterPathList = new ArrayList<ClusterPathNode>(); OptMapResultNode[][] trim1Results = new OptMapResultNode[groupedMap.size()][maxTrim + 1]; OptMapResultNode[][] trim2Results = new OptMapResultNode[groupedMap.size()][maxTrim + 1]; for (int i = 0; i < groupedMap.size(); i++) { trim1Results[i][0] = groupedMap.get(i); trim2Results[i][0] = groupedMap.get(i); } // head of the path for (OptMapResultNode map : groupedMap) clusterPathList.add(new ClusterPathNode(null, map, 0, 0, null, map)); // start building paths for map to map for (int i = 0; i < groupedMap.size(); i++) { int j = i - 1; while (j >= 0) { if (pbFilter.checkPass(groupedMap.get(j), groupedMap.get(i))) { TrimResult trimResult = trimOverlap(optrefmap, trim1Results[j], trim2Results[i], pbFilter, vmProcessor); if (trimResult.successful) { OptMapResultNode map1 = trimResult.result1; OptMapResultNode map2 = trimResult.result2; int trim1 = groupedMap.get(j).cigar.getMatch() - map1.cigar.getMatch(); int trim2 = groupedMap.get(i).cigar.getMatch() - map2.cigar.getMatch(); ClusterPathNode cp = new ClusterPathNode(groupedMap.get(j), groupedMap.get(i), trim1, trim2, map1, map2); clusterPathList.add(cp); } } j--; } } // tail of the path for (OptMapResultNode map : groupedMap) clusterPathList.add(new ClusterPathNode(map, null, 0, 0, map, null)); for (ClusterPathNode path : clusterPathList) path.updateScore(vmProcessor); return clusterPathList; }
/** * Check if two partial maps can be connected. Trimming is done on overlapping partial maps * * <p>It is essential to use trimming. Yet, there are two drawbacks using trimming 1. Trimming is * expensive. 2. Trimming may lead to inappropriate results (This is done by validation using * trimear) * * @param optrefmap * @param maxTrim * @param result1 * @param result2 * @param vmProcessor * @param ear * @return */ private TrimResult trimOverlap( LinkedHashMap<String, DataNode> optrefmap, OptMapResultNode[] trim1Result, OptMapResultNode[] trim2Result, PathBuilderFilter pbFilter, VirtualMapProcessor vmProcessor) { int penalty = vmProcessor.calcBasicPenalty(trim1Result[0], trim2Result[0]); double bestscore = Double.NEGATIVE_INFINITY; int bestTrim1 = -1; int bestTrim2 = -1; boolean[][] trimPair = new boolean[maxTrim + 1][maxTrim + 1]; // temp increasing maxTrim greatly: // 1. if the two score addition is already lower than any one of the score, discard // 2. maxTrim for (int trimmed = 0; trimmed <= maxTrim; trimmed++) { for (int trim1 = 0; trim1 <= trimmed; trim1++) { int trim2 = trimmed - trim1; if (trimPair[trim1][trim2]) // this trim pair should no longer be done continue; if ((trim1Result[0].cigar.getMatch() - trim1 >= minMatch) && (trim2Result[0].cigar.getMatch() - trim2 >= minMatch)) { OptMapResultNode tresult1 = trim1Result[trim1]; OptMapResultNode tresult2 = trim2Result[trim2]; // trim1Result[trim1 - 1] must exist if (tresult1 == null) { tresult1 = new OptMapResultNode(trim1Result[trim1 - 1]); tresult1.trimResult(-1 * trim1Result[trim1 - 1].mappedstrand, optrefmap); tresult1.updateScore(optrefmap, match, fpp, fnp); trim1Result[trim1] = tresult1; } if (tresult2 == null) { tresult2 = new OptMapResultNode(trim2Result[trim2 - 1]); tresult2.trimResult(1 * trim2Result[trim2 - 1].mappedstrand, optrefmap); tresult2.updateScore(optrefmap, match, fpp, fnp); trim2Result[trim2] = tresult2; } boolean withinTrimear = true; withinTrimear = Math.abs(tresult1.getMapScale() - 1) < trimear && Math.abs(tresult2.getMapScale() - 1) < trimear; boolean removeLaterTrim = false; if (pbFilter.checkPass(tresult1, tresult2)) { if (withinTrimear && !tresult1.overlap(tresult2)) { if (tresult1.mappedscore + tresult2.mappedscore - vmProcessor.calcPenalty(tresult1, tresult2) > bestscore) { bestscore = tresult1.mappedscore + tresult2.mappedscore - vmProcessor.calcPenalty(tresult1, tresult2); bestTrim1 = trim1; bestTrim2 = trim2; } removeLaterTrim = true; } else if (withinTrimear && tresult1.mappedscore + tresult2.mappedscore - penalty < bestscore) // We could not calcPenalty directly when // tresult1.overlap(tresult2) removeLaterTrim = true; } else removeLaterTrim = true; if (removeLaterTrim) for (int i = trim1; i <= maxTrim; i++) for (int j = trim2; j <= maxTrim; j++) trimPair[i][j] = true; } } } if (bestTrim1 == -1) return TrimResult.FailedTrimResult(); else return TrimResult.SuccessfulTrimResult(trim1Result[bestTrim1], trim2Result[bestTrim2]); }