From 12ae2c43318447f2cff8d84304f2991bc00d5df4 Mon Sep 17 00:00:00 2001 From: Joachim Wolff Date: Tue, 1 Oct 2024 16:27:33 +0200 Subject: [PATCH 1/6] New micro-c build of interaction matrix --- hicexplorer/hicBuildMatrix.py | 1381 +--------------- hicexplorer/hicBuildMatrixMicroC.py | 230 +++ hicexplorer/lib/buildMatrixMethods.py | 1405 +++++++++++++++++ .../test/general/test_hicBuildMatrixMicroC.py | 321 ++++ setup.py | 2 +- 5 files changed, 1967 insertions(+), 1372 deletions(-) create mode 100644 hicexplorer/hicBuildMatrixMicroC.py create mode 100644 hicexplorer/lib/buildMatrixMethods.py create mode 100644 hicexplorer/test/general/test_hicBuildMatrixMicroC.py diff --git a/hicexplorer/hicBuildMatrix.py b/hicexplorer/hicBuildMatrix.py index 409ce14c..2188fcfb 100644 --- a/hicexplorer/hicBuildMatrix.py +++ b/hicexplorer/hicBuildMatrix.py @@ -1,87 +1,19 @@ import argparse -import numpy as np -from scipy.sparse import coo_matrix, dia_matrix -import time -from os import unlink import os -from io import StringIO -import traceback + import warnings warnings.simplefilter(action="ignore", category=RuntimeWarning) warnings.simplefilter(action="ignore", category=PendingDeprecationWarning) -import pysam -from collections import OrderedDict - -from copy import deepcopy -from ctypes import Structure, c_uint, c_ushort -from multiprocessing import Process, Queue -from multiprocessing.sharedctypes import Array, RawArray - -from intervaltree import IntervalTree, Interval - -from Bio.Seq import Seq # own tools -from hicmatrix import HiCMatrix as hm -from hicexplorer.utilities import getUserRegion, genomicRegion +from hicexplorer.utilities import genomicRegion from hicexplorer._version import __version__ -import hicexplorer.hicPrepareQCreport as QC -from hicmatrix.lib import MatrixFileHandler - -from hicexplorer import hicMergeMatrixBins import logging log = logging.getLogger(__name__) - -class C_Interval(Structure): - """Struct to map a Interval form intervaltree as a multiprocessing.sharedctype""" - _fields_ = [("begin", c_uint), - ("end", c_uint), - ("data", c_uint)] - - -class C_Coverage(Structure): - """Struct to model the coverage as a multiprocessing.sharedctype""" - - _fields_ = [("begin", c_uint), - ("end", c_uint)] - - -class ReadPositionMatrix(object): - """A class to check for PCR duplicates. - A set storing all possible - start sites. Checks if read is already in the set. - """ - - def __init__(self): - """ - >>> rp = ReadPositionMatrix() - >>> rp.is_duplicated('1', 0, '2', 0) - False - >>> rp.is_duplicated('1', 0, '2', 0) - True - """ - - self.pos_matrix = set() - - def is_duplicated(self, chrom1, start1, chrom2, start2): - if chrom1 < chrom2: - id_string = "{}-{}".format(chrom1, chrom2) - else: - id_string = "{}-{}".format(chrom2, chrom1) - - if start1 < start2: - id_string += "-{}-{}".format(start1, start2) - else: - id_string += "-{}-{}".format(start2, start1) - - if id_string in self.pos_matrix: - return True - else: - self.pos_matrix.add(id_string) - return False +from hicexplorer.lib.buildMatrixMethods import * def parse_arguments(args=None): @@ -313,787 +245,6 @@ def parse_arguments(args=None): return parser -def intervalListToIntervalTree(interval_list): - r""" - given a dictionary containing tuples of chrom, start, end, - this is transformed to an interval trees. To each - interval an id is assigned, this id corresponds to the - position of the interval in the given array of tuples - and if needed can be used to identify - the index of a row/colum in the hic matrix. - - >>> bin_list = [('chrX', 0, 50000), ('chrX', 50000, 100000)] - >>> res = intervalListToIntervalTree(bin_list) - >>> sorted(res['chrX']) - [Interval(0, 50000, 0), Interval(50000, 100000, 1)] - """ - bin_int_tree = {} - - for intval_id, intval in enumerate(interval_list): - chrom, start, end = intval[0:3] - if chrom not in bin_int_tree: - bin_int_tree[chrom] = IntervalTree() - bin_int_tree[chrom].add(Interval(start, end, intval_id)) - - return bin_int_tree - - -def get_bins(bin_size, chrom_size, region=None): - r""" - Split the chromosomes into even sized bins - of length bin_size. - - Returns a list of tuples containing - ('chrom', start, end) - - >>> test = Tester() - >>> chrom_size = get_chrom_sizes(pysam.Samfile(test.bam_file_1)) - >>> sorted(get_bins(50000, chrom_size)) - [('contig-1', 0, 7125), ('contig-2', 0, 3345)] - >>> get_bins(50000, chrom_size, region='contig-1') - [('contig-1', 0, 7125)] - """ - bin_intvals = [] - start = 0 - if region: - chrom_size, start, _, _ = \ - getUserRegion(chrom_size, region) - - for chrom, size in chrom_size: - for interval in range(start, size, bin_size): - bin_intvals.append((chrom, interval, - min(size, interval + bin_size))) - return bin_intvals - - -def bed2interval_list(bed_file_handler, pChromosomeSize, pRegion): - r""" - reads a BED file and returns - a list of tuples containing - (chromosome name, start, end) - - >>> import tempfile, os - - Make a temporary BED file - >>> _file = tempfile.NamedTemporaryFile(delete=False) - >>> _file.close() - >>> file_tmp = open(_file.name, 'w') - >>> foo = file_tmp.write('chr1\t10\t20\tH1\t0\n') - >>> foo = file_tmp.write("chr1\t60\t70\tH2\t0\n") - >>> file_tmp.close() - >>> bed2interval_list(open(_file.name, 'r'), None, None) - [('chr1', 10, 20), ('chr1', 60, 70)] - >>> os.remove(_file.name) - """ - - if pRegion is not None: - chrom_size, start_region, end_region, _ = \ - getUserRegion(pChromosomeSize, pRegion) - - count = 0 - interval_list = [] - for line in bed_file_handler: - count += 1 - fields = line.strip().split() - try: - chrom, start, end = fields[0], int(fields[1]), int(fields[2]) - - except IndexError: - log.error("error reading BED file at line {}".format(count)) - - if pRegion is not None: - if chrom == chrom_size[0] and start_region <= start and end_region <= end: - interval_list.append((chrom, start, end)) - else: - interval_list.append((chrom, start, end)) - - return interval_list - - -def get_rf_bins(rf_cut_intervals, min_distance=200, max_distance=800): - r""" - returns a list of tuples containing a bin having the format: - ('chrom', start, end) - - The goal is to have bins containing each a restriction site close to - the center. Restriction sites that are less than 'min_distance' appart - are merged. To the left and right of the restriction site - 'max_distance' bp are added unless they clash with other bin. - Resulting bins are not immediately one after the other. - - The given cut sites list has to be ordered chr, and start site - - :param rf_cut_intervals: list of tuples containing the position of restriction fragment sites - :param min_distance: min distance between restriction fragment sites. - :param max_distance: max distance between restriction fragment and bin border. - :return: - - # two restriction sites of length 10 - >>> rf_cut_interval = [('chr1', 10, 20), ('chr1', 60, 70)] - - The following two bins are close together - and should be merged under min_distance = 20 - >>> rf_cut_interval.extend([('chr2', 20, 30), ('chr2', 40, 50), - ... ('chr2', 70, 80)]) - >>> get_rf_bins(rf_cut_interval, min_distance=10, max_distance=20) - [('chr1', 0, 40), ('chr1', 40, 90), ('chr2', 0, 60), ('chr2', 60, 100)] - """ - log.info("Minimum distance considered between " - "restriction sites is {}\nMax " - "distance: {}\n".format(min_distance, max_distance)) - - chrom, start, end = list(zip(*rf_cut_intervals)) - - rest_site_len = end[0] - start[0] - - # find sites that are less than min_distance apart - to_merge = np.flatnonzero(np.diff(start) - rest_site_len <= min_distance) - to_merge += 1 # + 1 to account for np.diff index handling - merge_idx = 0 - # add max_distance to both sides - start = np.array(start) - max_distance - end = np.array(end) + max_distance - new_start = [max(0, start[0])] - new_end = [] - new_chrom = [chrom[0]] - for idx in range(1, len(start)): - # identify end of chromosome - if chrom[idx] != chrom[idx - 1]: - new_start.append(max(0, start[idx])) - new_end.append(end[idx - 1]) - new_chrom.append(chrom[idx]) - merge_idx += 1 - continue - - if merge_idx < len(to_merge) and idx == to_merge[merge_idx]: - merge_idx += 1 - continue - - # identify overlapping bins - if chrom[idx] == chrom[idx - 1] and end[idx - 1] > start[idx]: - middle = start[idx] + int((end[idx - 1] - start[idx]) / 2) - new_start.append(middle) - new_end.append(middle) - else: - new_start.append(start[idx]) - new_end.append(end[idx - 1]) - new_chrom.append(chrom[idx]) - - new_end.append(end[-1]) - assert len(new_chrom) == len(new_start), "error" - assert len(new_end) == len(new_start), "error" - - intervals = zip(new_chrom, new_start, new_end) - intervals = [(_chrom, _start, _end) for _chrom, _start, - _end in intervals if _end - _start >= min_distance] - return intervals - - -def get_chrom_sizes(bam_handle): - """ - return the list of chromosome names and their - size from the bam file - The return value is a list of the form - [('chr1', 2343434), ('chr2', 43432432)] - - >>> test = Tester() - >>> get_chrom_sizes(pysam.Samfile(test.bam_file_1, 'rb')) - [('contig-1', 7125), ('contig-2', 3345)] - """ - - # in some cases there are repeated entries in - # the bam file. Thus, I first convert to dict, - # then to list. - list_chrom_sizes = OrderedDict(zip(bam_handle.references, - bam_handle.lengths)) - return list(list_chrom_sizes.items()) - - -def check_dangling_end(read, dangling_sequences): - """ - given a pysam read object, this function - checks if a forward read starts with - the dangling sequence or if a reverse - read ends with the dangling sequence. - """ - ds = dangling_sequences - # check if keys are existing, return false otherwise - if 'pat_forw' not in ds or 'pat_rev' not in ds: - return False - # skip forward read that stars with the restriction sequence - if not read.is_reverse and \ - read.seq.upper().startswith(ds['pat_forw']): - return True - - # skip reverse read that ends with the restriction sequence - if read.is_reverse and \ - read.seq.upper().endswith(ds['pat_rev']): - return True - - return False - - -def get_supplementary_alignment(read, pysam_obj): - """Checks if a read has a supplementary alignment - :param read pysam AlignedSegment - :param pysam_obj pysam file object - - :return pysam AlignedSegment of the supplementary aligment or None in case of no supplementary alignment - """ - - # the SA field contains a list of other alignments as a ';' delimited list in the format - # rname,pos,strand,CIGAR,mapQ,NM; - if read.has_tag('SA'): - # field always ends in ';' thus last element after split is always - # empty, hence [0:-1] - other_alignments = read.get_tag('SA').split(";")[0:-1] - supplementary_alignment = [] - for i in range(len(other_alignments)): - _sup = next(pysam_obj) - if _sup.qname == read.qname: - supplementary_alignment.append(_sup) - - return supplementary_alignment - - else: - return None - - -def get_correct_map(primary, supplement_list): - r""" - Decides which of the mappings, the primary or supplement, is correct. In the case of - long reads (eg. 150bp) the restriction enzyme site could split the read into two parts - but only the mapping corresponding to the start of the read should be considered as - the correct one. - - For example: - - Forward read: - - _ <- cut site - |======================|==========> - - - |----------------------| - correct mapping - - - reverse read: - - _ <- cut site - <======================|==========| - - - |----------| - correct mapping - - - :param primary: pysam AlignedSegment for primary mapping - :param supplement_list: list of pysam AlignedSegment for secondary mapping - - :return: pysam AlignedSegment that is mapped correctly - - Examples - -------- - >>> sam_file_name = "/tmp/test.sam" - >>> sam_file = open(sam_file_name, 'w') - >>> _ = sam_file.write('''@HD\tVN:1.0 - ... @SQ\tSN:chr1\tLN:1575\tAH:chr1:5000000-5010000 - ... read\t65\tchr1\t33\t20\t10S1D25M\t=\t200\t167\tAGCTTAGCTAGCTACCTATATCTTGGTCTTGGCCG\t<<<<<<<<<<<<<<<<<<<<<:<9/,&,22;;<<<\t - ... read\t2113\tchr1\t88\t30\t1S34M\t=\t500\t412\tACCTATATCTTGGCCTTGGCCGATGCGGCCTTGCA\t<<<<<;<<<<7;:<<<6;<<<<<<<<<<<<7<<<<\t - ... read\t2113\tchr1\t120\t30\t5S30M\t=\t500\t412\tACCTATATCTTGGCCTTGGCCGATGCGGCCTTGCA\t<<<<<;<<<<7;:<<<6;<<<<<<<<<<<<7<<<<''') - >>> sam_file.close() - >>> sam = pysam.Samfile(sam_file_name, "r") - >>> read_list = [read for read in sam] - >>> primary = read_list[0] - >>> secondary_list = read_list[1:] - >>> first_mapped = get_correct_map(primary, secondary_list) - - The first mapped read is the first secondary at position 88 (sam 1-based) = 87 (0-based) - >>> print(first_mapped.pos) - 87 - - """ - - for supplement in supplement_list: - assert primary.qname == supplement.qname, "ERROR, primary " \ - "and supplementary reads do not have the same id. The ids " \ - "are as follows\n{}\n{}".format(primary.qname, supplement.qname) - read_list = [primary] + supplement_list - first_mapped = [] - for idx, read in enumerate(read_list): - if read.is_reverse: - cigartuples = read.cigartuples[::-1] - else: - cigartuples = read.cigartuples[:] - - # For each read in read_list, calculate the position of the first match (operation M in CIGAR string) in the read sequence. - # The calculation is done by adding up the lengths of all the operations until the first match. - # CIGAR string is a list of tuples of (operation, length). Match is stored as CMATCH. - match_sum = 0 - for op, count in cigartuples: - if op == pysam.CMATCH: - break - match_sum += count - - first_mapped.append(match_sum) - # find which read has a cigar string that maps first than any of the - # others. - idx_min = first_mapped.index(min(first_mapped)) - - return read_list[idx_min] - - -def enlarge_bins(bin_intervals, chrom_sizes): - r""" - takes a list of consecutive but not - one after the other bin intervals - and joins them such that the - end and start of consecutive bins - is the same. - - >>> chrom_sizes = [('chr1', 100), ('chr2', 100)] - >>> bin_intervals = [('chr1', 10, 30), ('chr1', 50, 80), - ... ('chr2', 10, 60), ('chr2', 60, 90)] - >>> enlarge_bins(bin_intervals, chrom_sizes) - [('chr1', 0, 40), ('chr1', 40, 100), ('chr2', 0, 60), ('chr2', 60, 100)] - """ - # enlarge remaining bins - chr_start = True - chrom_sizes_dict = dict(chrom_sizes) - for idx in range(len(bin_intervals) - 1): - chrom, start, end = bin_intervals[idx] - chrom_next, start_next, end_next = bin_intervals[idx + 1] - if chr_start is True: - start = 0 - chr_start = False - if chrom == chrom_next and \ - end != start_next: - middle = start_next - int((start_next - end) / 2) - bin_intervals[idx] = (chrom, start, middle) - bin_intervals[idx + 1] = (chrom, middle, end_next) - if chrom != chrom_next: - bin_intervals[idx] = (chrom, start, chrom_sizes_dict[chrom]) - bin_intervals[idx + 1] = (chrom_next, 0, end_next) - - chrom, start, end = bin_intervals[-1] - bin_intervals[-1] = (chrom, start, chrom_sizes_dict[chrom]) - - return bin_intervals - - -def readBamFiles(pFileOneIterator, pFileTwoIterator, pNumberOfItemsPerBuffer, pSkipDuplicationCheck, pReadPosMatrix, pRefId2name, pMinMappingQuality): - """Read the two bam input files into n buffers each with pNumberOfItemsPerBuffer - with n = number of processes. The duplication check is handled here too.""" - buffer_mate1 = [] - buffer_mate2 = [] - duplicated_pairs = 0 - one_mate_unmapped = 0 - one_mate_not_unique = 0 - one_mate_low_quality = 0 - - all_data_read = False - j = 0 - iter_num = 0 - while j < pNumberOfItemsPerBuffer: - try: - mate1 = next(pFileOneIterator) - mate2 = next(pFileTwoIterator) - except StopIteration: - all_data_read = True - break - iter_num += 1 - - # skip 'not primary' alignments - while mate1.flag & 256 == 256: - try: - mate1 = next(pFileOneIterator) - except StopIteration: - all_data_read = True - break - while mate2.flag & 256 == 256: - try: - mate2 = next(pFileTwoIterator) - except StopIteration: - all_data_read = True - break - - assert mate1.qname == mate2.qname, "FATAL ERROR {} {} " \ - "Be sure that the sam files have the same read order " \ - "If using Bowtie2 or Hisat2 add " \ - "the --reorder option".format(mate1.qname, mate2.qname) - - # check for supplementary alignments - # (needs to be done before skipping any unmapped reads - # to keep the order of the two bam files in sync) - mate1_supplementary_list = get_supplementary_alignment( - mate1, pFileOneIterator) - mate2_supplementary_list = get_supplementary_alignment( - mate2, pFileTwoIterator) - - if mate1_supplementary_list: - mate1 = get_correct_map(mate1, mate1_supplementary_list) - - if mate2_supplementary_list: - mate2 = get_correct_map(mate2, mate2_supplementary_list) - - # skip if any of the reads is not mapped - if mate1.flag & 0x4 == 4 or mate2.flag & 0x4 == 4: - one_mate_unmapped += 1 - continue - - # skip if the read quality is low - if mate1.mapq < pMinMappingQuality or mate2.mapq < pMinMappingQuality: - # for bwa other way to test - # for multi-mapping reads is with a mapq = 0 - # the XS flag is not reliable. - if mate1.mapq == 0 & mate2.mapq == 0: - one_mate_not_unique += 1 - continue - - """ - # check if low quality is because of - # read being repetitive - # by reading the XS flag. - # The XS:i field is set by bowtie when a read is - # multi read and it contains the mapping score of the next - # best match - if 'XS' in dict(mate1.tags) or 'XS' in dict(mate2.tags): - one_mate_not_unique += 1 - continue - """ - - one_mate_low_quality += 1 - continue - - if pSkipDuplicationCheck is False: - if pReadPosMatrix.is_duplicated(pRefId2name[mate1.rname], - mate1.pos, - pRefId2name[mate2.rname], - mate2.pos): - duplicated_pairs += 1 - continue - buffer_mate1.append(mate1) - buffer_mate2.append(mate2) - j += 1 - - if all_data_read and len(buffer_mate1) != 0 and len(buffer_mate2) != 0: - return buffer_mate1, buffer_mate2, True, duplicated_pairs, one_mate_unmapped, one_mate_not_unique, one_mate_low_quality, iter_num - len(buffer_mate1) - if all_data_read and len(buffer_mate1) == 0 or len(buffer_mate2) == 0: - return None, None, True, duplicated_pairs, one_mate_unmapped, one_mate_not_unique, one_mate_low_quality, iter_num - len(buffer_mate1) - return buffer_mate1, buffer_mate2, False, duplicated_pairs, one_mate_unmapped, one_mate_not_unique, one_mate_low_quality, iter_num - len(buffer_mate1) - - -def process_data(pMateBuffer1, pMateBuffer2, pMinMappingQuality, - pKeepSelfCircles, pRestrictionSequence, pKeepSelfLigation, pMatrixSize, - pRfPositions, pRefId2name, - pDanglingSequences, pBinsize, pResultIndex, - pQueueOut, pTemplate, pOutputBamSet, pCounter, - pSharedBinIntvalTree, pDictBinIntervalTreeIndex, pCoverage, pCoverageIndex, - pOutputFileBufferDir, pRow, pCol, pData, - pMaxInsertSize, pQuickQCMode): - """ - This function computes for a given number of elements in pMateBuffer1 and pMaterBuffer2 a partial interaction matrix. - This function is used by multiple processes to speed up the computation. - All partial matrices are merged in the end into one interaction matrix. - - Parameters - ---------- - pMateBuffer1 : List of n reads of type 'pysam.libcalignedsegment.AlignedSegment' of sam input file 1 - pMateBuffer2 : List of n reads of type 'pysam.libcalignedsegment.AlignedSegment' of sam input file 2 - pMinMappingQuality : integer, minimum mapping quality of a read - pKeepSelfCircles : boolean, if self circles should be kept - pRestrictionSequence : List of String, the restriction sequence - pKeepSelfLigation : If self ligations should be removed - pMatrixSize : integer, the size of the interaction matrix - pRfPositions : intervalTree, only used if a restriction cut file and not a bin size was defined. - pRefId2name : Tuple, Maps a reference id to a name - pDanglingSequences : dict, dict of dangling sequences - pBinsize : integer, the size of the bins - pResultIndex : integer, number of processs, range(0, threads). Is returned via the queue to have access to the right row, col and data array after the computation. - pQueueOut : multiprocessing.Queue, queue to return the computed counting variables: - one_mate_unmapped, one_mate_low_quality, one_mate_not_unique, dangling_end, self_circle, self_ligation, same_fragment, - mate_not_close_to_rf, count_inward, count_outward, count_left, count_right, inter_chromosomal, short_range, long_range, - pair_added, len(pMateBuffer1), pResultIndex, pCounter - pTemplate : The template for the output bam file - pOutputBamSet : If a output bam file should be written. Depending on the input parameter '--outBam' - pOutputName : String, Name of the partial bam file - pCounter : integer, value which is returned to the main process. The main process can than write a pCounter.bam_done file - to signal the background process, which is merging the partial bam files into one, that this dataset can be merged. - pSharedBinIntvalTree : multiprocessing.sharedctype.RawArray of C_Interval, stores the interval tree in a 1D-RawArray. - pDictBinIntervalTreeIndex : dict, stores the information at which index position a given interval starts and ends in the 1D-array 'pSharedBinIntvalTree' - pCoverage : multiprocessing.sharedctype.Array of c_uint, Stores the coverage in a 1D-Array - pCoverageIndex : multiprocessing.sharedctype.RawArray of C_Coverage, stores the information in the 1D-array 'pCoverage' - pOutputFileBufferDir : String, the directory where the partial output bam files are buffered. Default is '/dev/shm/' - pRow : multiprocessing.sharedctype.RawArray of c_uint, Stores the row index information. It is available for all processes and does not need to be copied. - pCol : multiprocessing.sharedctype.RawArray of c_uint, stores the column index information. It is available for all processes and does not need to be copied. - pData : multiprocessing.sharedctype.RawArray of c_ushort, stores a 1 for each row - column pair. It is available for all processes and does not need to be copied. - pMaxInsertSize : maximum illumina insert size - """ - try: - - one_mate_unmapped = 0 - one_mate_low_quality = 0 - one_mate_not_unique = 0 - dangling_end = {} - if pRestrictionSequence is not None: - for restrictionSequence in pRestrictionSequence: - dangling_end[restrictionSequence] = 0 - self_circle = 0 - self_ligation = 0 - same_fragment = 0 - mate_not_close_to_rf = 0 - - count_inward = 0 - count_outward = 0 - count_left = 0 - count_right = 0 - inter_chromosomal = 0 - short_range = 0 - long_range = 0 - - pair_added = 0 - - iter_num = 0 - hic_matrix = None - - out_bam_index_buffer = [] - - if pMateBuffer1 is None or pMateBuffer2 is None: - - pQueueOut.put([hic_matrix, [one_mate_unmapped, one_mate_low_quality, one_mate_not_unique, dangling_end, self_circle, self_ligation, same_fragment, - mate_not_close_to_rf, count_inward, count_outward, - count_left, count_right, inter_chromosomal, short_range, long_range, pair_added, iter_num, pResultIndex, out_bam_index_buffer]]) - return - - while iter_num < len(pMateBuffer1) and iter_num < len(pMateBuffer2): - mate1 = pMateBuffer1[iter_num] - mate2 = pMateBuffer2[iter_num] - iter_num += 1 - - # check if reads belong to a bin - # - # pDictBinInterval stores the start and end position for each chromsome in the array 'pSharedBinIntvalTree' - # To get to the right interval a binary search is used. - mate_bins = [] - mate_is_unasigned = False - for mate in [mate1, mate2]: - mate_ref = pRefId2name[mate.rname] - # find the middle genomic position of the read. This is used to - # find the bin it belongs to. - read_middle = mate.pos + int(mate.qlen / 2) - try: - start, end = pDictBinIntervalTreeIndex[mate_ref] - middle_pos = int((start + end) / 2) - mate_bin = None - while not start > end: - if pSharedBinIntvalTree[middle_pos].begin <= read_middle and read_middle <= pSharedBinIntvalTree[middle_pos].end: - mate_bin = pSharedBinIntvalTree[middle_pos] - mate_is_unasigned = False - break - elif pSharedBinIntvalTree[middle_pos].begin > read_middle: - end = middle_pos - 1 - middle_pos = int((start + end) / 2) - mate_is_unasigned = True - else: - start = middle_pos + 1 - middle_pos = int((start + end) / 2) - mate_is_unasigned = True - - except KeyError: - # for small contigs it can happen that they are not - # in the bin_intval_tree keys if no restriction site is found - # on the contig. - mate_is_unasigned = True - break - - # report no match case - if mate_bin is None: - mate_is_unasigned = True - break - mate_bin_id = mate_bin.data - mate_bins.append(mate_bin_id) - - # if a mate is unassigned, it means it is not close - # to a restriction site - if mate_is_unasigned is True: - mate_not_close_to_rf += 1 - continue - - # check if mates are in the same chromosome - if mate1.reference_id != mate2.reference_id: - orientation = 'diff_chromosome' - else: - # to identify 'inward' and 'outward' orientations - # the order or the mates in the genome has to be - # known. - if mate1.pos < mate2.pos: - first_mate = mate1 - second_mate = mate2 - else: - first_mate = mate2 - second_mate = mate1 - - """ - outward - <--------------- ----------------> - - inward - ---------------> <---------------- - - same-strand-right - ---------------> ----------------> - - same-strand-left - <--------------- <---------------- - """ - - if not first_mate.is_reverse and second_mate.is_reverse: - orientation = 'inward' - elif first_mate.is_reverse and not second_mate.is_reverse: - orientation = 'outward' - elif first_mate.is_reverse and second_mate.is_reverse: - orientation = 'same-strand-left' - else: - orientation = 'same-strand-right' - - # check self-circles - # self circles are defined as outward pairs that do not - # have a restriction sequence in between. The distance of < 25kb is - # used to only check close outward pairs as far apart pairs can not be self-circles - if abs(mate2.pos - mate1.pos) < 25000 and orientation == 'outward': - has_rf = [] - - if pRfPositions and pRestrictionSequence: - # check if in between the two mate - # ends the restriction fragment is found. - # check for multiple restriction sequences - for restrictionSequence in pRestrictionSequence: - # the interval used is: - # start of fragment + length of restriction sequence - # end of fragment - length of restriction sequence - # the restriction sequence length is subtracted - # such that only fragments internally containing - # the restriction site are identified - frag_start = min(mate1.pos, mate2.pos) + \ - len(restrictionSequence) - frag_end = max(mate1.pos + mate1.qlen, mate2.pos + mate2.qlen) - len(restrictionSequence) - mate_ref = pRefId2name[mate1.rname] - if mate_ref in pRfPositions: - has_rf.extend(sorted( - pRfPositions[mate_ref][frag_start: frag_end])) - - if len(has_rf) == 0: - self_circle += 1 - if not pKeepSelfCircles: - continue - if abs(mate2.pos - mate1.pos) < pMaxInsertSize and orientation == 'inward': - # check for dangling ends if the restriction sequence is known and if they look - # like 'same fragment' - if pRestrictionSequence: - if pDanglingSequences: - - # check for dangling ends in sequence. Stop check with first match - one_match = False - for restrictionSequence in pRestrictionSequence: - if check_dangling_end(mate1, pDanglingSequences[restrictionSequence]) or \ - check_dangling_end(mate2, pDanglingSequences[restrictionSequence]): - dangling_end[restrictionSequence] += 1 - one_match = True - break - if one_match: - continue - has_rf = [] - - if pRfPositions and pRestrictionSequence: - # check if in between the two mate - # ends the restriction fragment is found. - - # the interval used is: - # start of fragment + length of restriction sequence - # end of fragment - length of restriction sequence - # the restriction sequence length is subtracted - # such that only fragments internally containing - # the restriction site are identified - - for restrictionSequence in pRestrictionSequence: - frag_start = min(mate1.pos, mate2.pos) + \ - len(restrictionSequence) - frag_end = max(mate1.pos + mate1.qlen, mate2.pos + mate2.qlen) - len(restrictionSequence) - mate_ref = pRefId2name[mate1.rname] - if mate_ref in pRfPositions: - has_rf.extend(sorted( - pRfPositions[mate_ref][frag_start: frag_end])) - - # case when there is no restriction fragment site between the - # mates - if len(has_rf) == 0: - same_fragment += 1 - continue - - self_ligation += 1 - - if not pKeepSelfLigation: - # skip self ligations - continue - - # set insert size to save bam - mate1.isize = mate2.pos - mate1.pos - mate2.isize = mate1.pos - mate2.pos - - # if mate_bins, which is set in the previous section - # does not have size=2, it means that one - # of the exceptions happened - if len(mate_bins) != 2: - continue - - # count type of pair (distance, orientation) - if mate1.reference_id != mate2.reference_id: - inter_chromosomal += 1 - - elif abs(mate2.pos - mate1.pos) < 20000: - short_range += 1 - else: - long_range += 1 - - if orientation == 'inward': - count_inward += 1 - elif orientation == 'outward': - count_outward += 1 - elif orientation == 'same-strand-left': - count_left += 1 - elif orientation == 'same-strand-right': - count_right += 1 - - for mate in [mate1, mate2]: - # fill in coverage vector - vec_start = int(max(0, mate.pos - mate_bin.begin) / pBinsize) - length_coverage = pCoverageIndex[mate_bin_id].end - \ - pCoverageIndex[mate_bin_id].begin - vec_end = min(length_coverage, int( - vec_start + len(mate.seq) / pBinsize)) - coverage_index = pCoverageIndex[mate_bin_id].begin + vec_start - coverage_end = pCoverageIndex[mate_bin_id].begin + vec_end - for i in range(coverage_index, coverage_end, 1): - pCoverage[i] += 1 - - if not pQuickQCMode: - pRow[pair_added] = mate_bins[0] - pCol[pair_added] = mate_bins[1] - pData[pair_added] = np.uint8(1) - - pair_added += 1 - if pOutputBamSet: - - out_bam_index_buffer.append(iter_num - 1) - - pQueueOut.put([[one_mate_unmapped, one_mate_low_quality, one_mate_not_unique, dangling_end, self_circle, self_ligation, same_fragment, - mate_not_close_to_rf, count_inward, count_outward, - count_left, count_right, inter_chromosomal, short_range, long_range, pair_added, len(pMateBuffer1), pResultIndex, pCounter, out_bam_index_buffer]]) - except Exception as exp: - pQueueOut.put('Fail: ' + str(exp) + traceback.format_exc()) - return - return - - def main(args=None): """ Reads line by line two bam files that are not sorted. @@ -1110,525 +261,13 @@ def main(args=None): """ args = parse_arguments().parse_args(args) - # args.outFileName.name = args.outFileName.name.strip() - # log.debug('args.outFileName.name: {}'.format(args.outFileName.name.endswith('.h5'))) - if not args.outFileName.name.endswith('.h5') and not args.outFileName.name.endswith('.cool'): - if '.mcool' not in args.outFileName.name: - log.error('Please define the file extension. h5 and cool are supported, or the specializations of cool, mcool. Given input {}'.format(args.outFileName.name)) - exit(1) - # for backwards compatibility - if args.maxDistance is not None: - args.maxLibraryInsertSize = args.maxDistance - try: - QC.make_sure_path_exists(args.QCfolder) - except OSError: - exit("Can't open/create QC folder path: {}. Please check".format(args.QCfolder)) - - if args.threads < 2: - args.threads = 2 - warnings.warn( - "\nAt least two threads need to be defined. Setting --threads = 2!s\n") - - if args.danglingSequence and not args.restrictionSequence: - exit("\nIf --danglingSequence is set, --restrictionSequence needs to be set too.\n") - - log.info("reading {} and {} to build hic_matrix\n".format(args.samFiles[0].name, - args.samFiles[1].name)) - str1 = pysam.Samfile(args.samFiles[0].name, 'rb') - str2 = pysam.Samfile(args.samFiles[1].name, 'rb') - - args.samFiles[0].close() - args.samFiles[1].close() - if not args.doTestRun: - if args.outBam: - args.outBam.close() - out_bam_file = pysam.Samfile(args.outBam.name, 'wb', template=str1) - - if args.chromosomeSizes is None: - chrom_sizes = get_chrom_sizes(str1) - else: - chrom_sizes = OrderedDict() - with open(args.chromosomeSizes.name, 'r') as file: - file_ = True - while file_: - file_ = file.readline().strip() - if file_ != '': - line_split = file_.split('\t') - chrom_sizes[line_split[0]] = int(line_split[1]) - chrom_sizes = list(chrom_sizes.items()) - - # log.debug('chrom_sizes {}'.format(chrom_sizes)) - read_pos_matrix = ReadPositionMatrix() - - rf_interval = [] - for restrictionCutFile in args.restrictionCutFile: - rf_interval.extend(bed2interval_list(restrictionCutFile, chrom_sizes, args.region)) - - rf_positions = intervalListToIntervalTree(rf_interval) - log.debug('rf_positions {}'.format(rf_positions.keys())) - if args.binSize: - bin_intervals = get_bins(args.binSize[0], chrom_sizes, args.region) - else: - bin_intervals = get_rf_bins(rf_interval, - min_distance=args.minDistance, - max_distance=args.maxLibraryInsertSize) - - matrix_size = len(bin_intervals) - bin_intval_tree = intervalListToIntervalTree(bin_intervals) - ref_id2name = str1.references - - # build c_type shared memory for the interval tree - shared_array_list = [] - index_dict = {} - end = -1 - for i, seq in enumerate(bin_intval_tree): - start = end + 1 - interval_list = [] - for interval in bin_intval_tree[seq]: - interval_list.append((interval.begin, interval.end, interval.data)) - end = start + len(bin_intval_tree[seq]) - 1 - index_dict[seq] = (start, end) - interval_list = sorted(interval_list) - shared_array_list.extend(interval_list) - shared_build_intval_tree = RawArray(C_Interval, shared_array_list) - bin_intval_tree = None - dangling_sequences = {} - if args.danglingSequence: - # build a list of dangling sequences - if args.restrictionSequence is not None: - for i in range(0, len(args.restrictionSequence)): - args.restrictionSequence[i] = args.restrictionSequence[i].upper() - args.danglingSequence[i] = args.danglingSequence[i].upper() - dangling_sequences[args.restrictionSequence[i]] = {} - dangling_sequences[args.restrictionSequence[i]]['pat_forw'] = args.danglingSequence[i] - dangling_sequences[args.restrictionSequence[i]]['pat_rev'] = str( - Seq(args.danglingSequence[i]).reverse_complement()) - - log.info("dangling sequences to check " - "are {}\n".format(dangling_sequences)) - - # initialize coverage vectors that - # save the number of reads that overlap - # a bin. - # To save memory, coverage is not measured by bp - # but by bins of length 10bp - binsize = 10 - number_of_elements_coverage = 0 - start_pos_coverage = [] - end_pos_coverage = [] - - for chrom, start, end in bin_intervals: - start_pos_coverage.append(number_of_elements_coverage) - - number_of_elements_coverage += (end - start) // binsize - end_pos_coverage.append(number_of_elements_coverage - 1) - pos_coverage = RawArray(C_Coverage, list(zip( - start_pos_coverage, end_pos_coverage))) - start_pos_coverage = None - end_pos_coverage = None - coverage = Array(c_uint, [0] * number_of_elements_coverage) - - # define global shared ctypes arrays for row, col and data - args.threads = args.threads - 1 - row = [None] * args.threads - col = [None] * args.threads - data = [None] * args.threads - for i in range(args.threads): - row[i] = RawArray(c_uint, args.inputBufferSize) - col[i] = RawArray(c_uint, args.inputBufferSize) - data[i] = RawArray(c_ushort, args.inputBufferSize) - - start_time = time.time() - - iter_num = 0 - # pair_added = 0 - # hic_matrix = None - - one_mate_unmapped = 0 - one_mate_low_quality = 0 - one_mate_not_unique = 0 - dangling_end = {} - if args.restrictionSequence is not None: - for restrictionSequence in args.restrictionSequence: - dangling_end[restrictionSequence] = 0 - - self_circle = 0 - self_ligation = 0 - same_fragment = 0 - mate_not_close_to_rf = 0 - duplicated_pairs = 0 - - count_inward = 0 - count_outward = 0 - count_left = 0 - count_right = 0 - inter_chromosomal = 0 - short_range = 0 - long_range = 0 - - pair_added = 0 - - # input buffer for bam files - buffer_workers1 = [None] * args.threads - buffer_workers2 = [None] * args.threads - - # output buffer to write bam with mate1 and mate2 pairs - process = [None] * args.threads - all_data_processed = False - hic_matrix = coo_matrix((matrix_size, matrix_size), dtype='uint32') - queue = [None] * args.threads - - all_threads_done = False - thread_done = [False] * args.threads - count_output = 0 - count_call_of_read_input = 0 - computed_pairs = 0 - - if args.doTestRun: - args.inputBufferSize = args.doTestRunLines - fail_flag = False - fail_message = '' - while not all_data_processed or not all_threads_done: - - for i in range(args.threads): - if queue[i] is None and not all_data_processed: - count_call_of_read_input += 1 - - buffer_workers1[i], buffer_workers2[i], all_data_processed, \ - duplicated_pairs_, one_mate_unmapped_, one_mate_not_unique_, \ - one_mate_low_quality_, iter_num_ = readBamFiles(pFileOneIterator=str1, - pFileTwoIterator=str2, - pNumberOfItemsPerBuffer=args.inputBufferSize, - pSkipDuplicationCheck=args.skipDuplicationCheck, - pReadPosMatrix=read_pos_matrix, - pRefId2name=ref_id2name, - pMinMappingQuality=args.minMappingQuality - ) - duplicated_pairs += duplicated_pairs_ - one_mate_unmapped += one_mate_unmapped_ - one_mate_not_unique += one_mate_not_unique_ - one_mate_low_quality += one_mate_low_quality_ - iter_num += iter_num_ - queue[i] = Queue() - thread_done[i] = False - computed_pairs += len(buffer_workers1[i]) - # create process to compute hic matrix for this buffer - process[i] = Process(target=process_data, kwargs=dict( - pMateBuffer1=buffer_workers1[i], - pMateBuffer2=buffer_workers2[i], - pMinMappingQuality=args.minMappingQuality, - pKeepSelfCircles=args.keepSelfCircles, - pRestrictionSequence=args.restrictionSequence, - pKeepSelfLigation=args.keepSelfLigation, - pMatrixSize=matrix_size, - pRfPositions=rf_positions, - pRefId2name=ref_id2name, - pDanglingSequences=dangling_sequences, - pBinsize=binsize, - pResultIndex=i, - pQueueOut=queue[i], - pTemplate=str1, - pOutputBamSet=args.outBam, - pCounter=count_output, - pSharedBinIntvalTree=shared_build_intval_tree, - pDictBinIntervalTreeIndex=index_dict, - pCoverage=coverage, - pCoverageIndex=pos_coverage, - pOutputFileBufferDir="", - pRow=row[i], - pCol=col[i], - pData=data[i], - pMaxInsertSize=args.maxLibraryInsertSize, - pQuickQCMode=args.doTestRun - )) - process[i].start() - count_output += 1 - - elif queue[i] is not None and not queue[i].empty(): - result = queue[i].get() - if 'Fail:' in result: - fail_flag = True - fail_message = result[6:] - else: - if result[0] is not None: - elements = result[0][15] - if hic_matrix is None: - hic_matrix = coo_matrix( - (data[i][:elements], (row[i][:elements], col[i][:elements])), shape=(matrix_size, matrix_size)) - else: - hic_matrix += coo_matrix( - (data[i][:elements], (row[i][:elements], col[i][:elements])), shape=(matrix_size, matrix_size)) - - for sequence in result[0][3]: - dangling_end[sequence] += result[0][3][sequence] - self_circle += result[0][4] - self_ligation += result[0][5] - same_fragment += result[0][6] - mate_not_close_to_rf += result[0][7] - - count_inward += result[0][8] - count_outward += result[0][9] - count_left += result[0][10] - count_right += result[0][11] - inter_chromosomal += result[0][12] - short_range += result[0][13] - long_range += result[0][14] - - pair_added += result[0][15] - iter_num += result[0][16] - - for bam_index in result[0][19]: - mate1 = buffer_workers1[i][bam_index] - mate2 = buffer_workers2[i][bam_index] - - mate1.flag |= 0x1 - mate2.flag |= 0x1 - - # set one read as the first in pair and the - # other as second - mate1.flag |= 0x40 - mate2.flag |= 0x80 - - # set chrom of mate - mate1.mrnm = mate2.rname - mate2.mrnm = mate1.rname - - # set position of mate - mate1.mpos = mate2.pos - mate2.mpos = mate1.pos - - out_bam_file.write(mate1) - out_bam_file.write(mate2) - - buffer_workers1[i] = None - buffer_workers2[i] = None - queue[i] = None - process[i].join() - process[i].terminate() - process[i] = None - thread_done[i] = True - - # caused by the architecture I try to display this output - # information after +-1e5 of 1e6 reads. - if iter_num % 1e6 < 100000: - elapsed_time = time.time() - start_time - log.info("processing {} lines took {:.2f} " - "secs ({:.1f} lines per " - "second)\n".format(iter_num, - elapsed_time, - iter_num / elapsed_time)) - log.info("{} ({:.2f}%) valid pairs added to matrix" - "\n".format(pair_added, float(100 * pair_added) / iter_num)) - if args.doTestRun and iter_num > args.doTestRunLines: - log.debug( - "\n## *WARNING*. Early exit because of --doTestRun parameter ##\n\n") - all_data_processed = True - thread_done[i] = True - break - elif all_data_processed and queue[i] is None: - thread_done[i] = True - else: - time.sleep(1) - - if all_data_processed: - all_threads_done = True - for thread in thread_done: - if not thread: - all_threads_done = False - if fail_flag: - log.error(fail_message) - exit(1) - else: - log.debug('Parallel stuff done') - if not args.doTestRun: - # the resulting matrix is only filled unevenly with some pairs - # int the upper triangle and others in the lower triangle. To construct - # the definite matrix I add the values from the upper and lower triangles - # and subtract the diagonal to avoid double counting it. - # The resulting matrix is symmetric. - if args.outBam: - out_bam_file.close() - - dia = dia_matrix(([hic_matrix.diagonal()], [0]), - shape=hic_matrix.shape) - hic_matrix = hic_matrix + hic_matrix.T - dia - # extend bins such that they are next to each other - bin_intervals = enlarge_bins(bin_intervals[:], chrom_sizes) - # compute max bin coverage - bin_max = [] - - for cover in pos_coverage: - max_element = 0 - for i in range(cover.begin, cover.end, 1): - if coverage[i] > max_element: - max_element = coverage[i] - if max_element == 0: - bin_max.append(np.nan) - else: - bin_max.append(max_element) - - chr_name_list, start_list, end_list = list(zip(*bin_intervals)) - bin_intervals = list(zip(chr_name_list, start_list, end_list, bin_max)) - hic_ma = hm.hiCMatrix() - hic_ma.setMatrix(hic_matrix, cut_intervals=bin_intervals) - - """ - if args.restrictionCutFile: - # load the matrix to mask those - # bins that most likely didn't - # have a restriction site that was cutted - - # reload the matrix as a Hi-C matrix object - hic_matrix = hm.hiCMatrix(args.outFileName.name) - - hic_matrix.maskBins(get_poor_bins(bin_max)) - hic_matrix.save(args.outFileName.name) - """ - if not args.keepSelfLigation: - msg = " (removed)" - else: - msg = " (not removed)" - - mappable_unique_high_quality_pairs = iter_num - \ - (one_mate_unmapped + one_mate_low_quality + one_mate_not_unique) - - intermediate_qc_log = StringIO() - - intermediate_qc_log.write(""" -File\t{}\t\t -Sequenced reads\t{}\t\t -Min rest. site distance\t{}\t\t -Max library insert size\t{}\t\t - -""".format(args.outFileName.name, iter_num, args.minDistance, args.maxLibraryInsertSize)) - - intermediate_qc_log.write( - "#\tcount\t(percentage w.r.t. total sequenced reads)\n") - - intermediate_qc_log.write("Pairs mappable, unique and high quality\t{}\t({:.2f})\n". - format(mappable_unique_high_quality_pairs, - 100 * float(mappable_unique_high_quality_pairs) / iter_num)) - - intermediate_qc_log.write("Hi-C contacts\t{}\t({:.2f})\n". - format(pair_added, 100 * float(pair_added) / iter_num)) - - intermediate_qc_log.write("One mate unmapped\t{}\t({:.2f})\n". - format(one_mate_unmapped, 100 * float(one_mate_unmapped) / iter_num)) - - intermediate_qc_log.write("One mate not unique\t{}\t({:.2f})\n". - format(one_mate_not_unique, 100 * float(one_mate_not_unique) / iter_num)) - - intermediate_qc_log.write("Low mapping quality\t{}\t({:.2f})\n". - format(one_mate_low_quality, 100 * float(one_mate_low_quality) / iter_num)) - - intermediate_qc_log.write( - "\n#\tcount\t(percentage w.r.t. mappable, unique and high quality pairs)\n") - - if len(dangling_end) > 0: - log.debug('dangling_sequences {}'.format(dangling_sequences.keys())) - log.debug('dangling_end {}'.format(dangling_end.keys())) - # log.debug('dangling_end {}'.format(res.keys())) - - for key in dangling_end: - # dangling_sequences[args.restrictionSequence[i]]['pat_forw'] - intermediate_qc_log.write("dangling end {} (restriction sequence {})\t{}\t({:.2f})\n". - format(dangling_sequences[key]['pat_forw'], key, dangling_end[key], 100 * float(dangling_end[key]) / mappable_unique_high_quality_pairs)) - else: - intermediate_qc_log.write("dangling end\t{}\t({:.2f})\n". - format(0, 100 * float(0) / mappable_unique_high_quality_pairs)) - intermediate_qc_log.write("self ligation{}\t{}\t({:.2f})\n". - format(msg, self_ligation, 100 * float(self_ligation) / mappable_unique_high_quality_pairs)) - - intermediate_qc_log.write("One mate not close to rest site\t{}\t({:.2f})\n". - format(mate_not_close_to_rf, 100 * float(mate_not_close_to_rf) / mappable_unique_high_quality_pairs)) - - intermediate_qc_log.write("same fragment\t{}\t({:.2f})\n". - format(same_fragment, 100 * float(same_fragment) / mappable_unique_high_quality_pairs)) - - intermediate_qc_log.write("self circle\t{}\t({:.2f})\n". - format(self_circle, 100 * float(self_circle) / mappable_unique_high_quality_pairs)) - - intermediate_qc_log.write("duplicated pairs\t{}\t({:.2f})\n". - format(duplicated_pairs, 100 * float(duplicated_pairs) / mappable_unique_high_quality_pairs)) - - if pair_added > 0: - intermediate_qc_log.write( - "\n#\tcount\t(percentage w.r.t. total valid pairs used)\n") - intermediate_qc_log.write("inter chromosomal\t{}\t({:.2f})\n". - format(inter_chromosomal, 100 * float(inter_chromosomal) / pair_added)) - - intermediate_qc_log.write("Intra short range (< 20kb)\t{}\t({:.2f})\n". - format(short_range, 100 * float(short_range) / pair_added)) - - intermediate_qc_log.write("Intra long range (>= 20kb)\t{}\t({:.2f})\n". - format(long_range, 100 * float(long_range) / pair_added)) - - intermediate_qc_log.write("Read pair type: inward pairs\t{}\t({:.2f})\n". - format(count_inward, 100 * float(count_inward) / pair_added)) - - intermediate_qc_log.write("Read pair type: outward pairs\t{}\t({:.2f})\n". - format(count_outward, 100 * float(count_outward) / pair_added)) - - intermediate_qc_log.write("Read pair type: left pairs\t{}\t({:.2f})\n". - format(count_left, 100 * float(count_left) / pair_added)) - - intermediate_qc_log.write("Read pair type: right pairs\t{}\t({:.2f})\n". - format(count_right, 100 * float(count_right) / pair_added)) - - log_file_name = os.path.join(args.QCfolder, "QC.log") - log_file = open(log_file_name, 'w') - log_file.write(intermediate_qc_log.getvalue()) - log_file.close() - log.debug('log_file_name {}'.format(log_file_name)) - log.debug('args.QCfolder {}'.format(args.QCfolder)) - - QC.main("-l {} -o {}".format(log_file_name, args.QCfolder).split()) - - args.outFileName.close() - # removing the empty file. Otherwise the save method - # will say that the file already exists. - unlink(args.outFileName.name) - - hic_metadata = {} - hic_metadata['statistics'] = intermediate_qc_log.getvalue() - hic_metadata['matrix-generated-by'] = np.string_( - 'HiCExplorer-' + __version__) - hic_metadata['matrix-generated-by-url'] = np.string_( - 'https://github.com/deeptools/HiCExplorer') - if args.genomeAssembly: - hic_metadata['genome-assembly'] = np.string_(args.genomeAssembly) - - intermediate_qc_log.close() - if args.outFileName.name.endswith('.mcool') and args.binSize is not None and len(args.binSize) > 2: - - matrixFileHandlerOutput = MatrixFileHandler( - pFileType='cool', pHiCInfo=hic_metadata) - matrixFileHandlerOutput.set_matrix_variables(hic_ma.matrix, - hic_ma.cut_intervals, - hic_ma.nan_bins, - hic_ma.correction_factors, - hic_ma.distance_counts) - matrixFileHandlerOutput.save(args.outFileName.name + '::/resolutions/' + str( - args.binSize[0]), pSymmetric=True, pApplyCorrection=False) - - for resolution in args.binSize[1:]: - hic_matrix_to_merge = deepcopy(hic_ma) - _mergeFactor = int(resolution) // args.binSize[0] - merged_matrix = hicMergeMatrixBins.merge_bins( - hic_matrix_to_merge, _mergeFactor) - matrixFileHandlerOutput = MatrixFileHandler( - pFileType='cool', pAppend=True, pHiCInfo=hic_metadata) - matrixFileHandlerOutput.set_matrix_variables(merged_matrix.matrix, - merged_matrix.cut_intervals, - merged_matrix.nan_bins, - merged_matrix.correction_factors, - merged_matrix.distance_counts) - matrixFileHandlerOutput.save(args.outFileName.name + '::/resolutions/' + str( - resolution), pSymmetric=True, pApplyCorrection=False) - - else: - if not args.doTestRun: - hic_ma.save(args.outFileName.name, pHiCInfo=hic_metadata) + + createMatrix(pOutFileName=args.outFileName, pMaxDistance=args.maxDistance, pMaxLibraryInsertSize=args.maxLibraryInsertSize, pQCfolder=args.QCfolder, + pThreads=args.threads, pDanglingSequence=args.danglingSequence, pRestrictionSequence=args.restrictionSequence, pSamFiles=args.samFiles, + pDoTestRun=args.doTestRun, pOutBam=args.outBam, pChromosomeSizes=args.chromosomeSizes, pRestrictionCutFile=args.restrictionCutFile, + pRegion=args.region, pBinSize=args.binSize, pInputBufferSize=args.inputBufferSize, pMinDistance=args.minDistance, + pDoTestRunLines=args.doTestRunLines, pSkipDuplicationCheck=args.skipDuplicationCheck, pMinMappingQuality=args.minMappingQuality, + pKeepSelfCircles=args.keepSelfCircles, pKeepSelfLigation=args.keepSelfLigation, pGenomeAssembly=args.genomeAssembly) class Tester(object): diff --git a/hicexplorer/hicBuildMatrixMicroC.py b/hicexplorer/hicBuildMatrixMicroC.py new file mode 100644 index 00000000..1e8038aa --- /dev/null +++ b/hicexplorer/hicBuildMatrixMicroC.py @@ -0,0 +1,230 @@ +import argparse +import os + +import warnings +warnings.simplefilter(action="ignore", category=RuntimeWarning) +warnings.simplefilter(action="ignore", category=PendingDeprecationWarning) + + +# own tools +from hicexplorer.utilities import genomicRegion +from hicexplorer._version import __version__ + +import logging +log = logging.getLogger(__name__) + +from hicexplorer.lib.buildMatrixMethods import * + + +def parse_arguments(args=None): + + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + add_help=False, + description=('Using an alignment from a program that supports ' + 'local alignment (eg. Bowtie2) where both ' + 'PE reads are mapped using the --local ' + 'option, this program reads such file and ' + 'creates a matrix of interactions.' + )) + + parserRequired = parser.add_argument_group('Required arguments') + + # define the arguments + parserRequired.add_argument('--samFiles', '-s', + help='The two PE alignment sam files to process', + metavar='two sam files', + nargs=2, + type=argparse.FileType('r'), + required=True) + + parserRequired.add_argument('--outFileName', '-o', + help='Output file name for the Hi-C matrix.', + metavar='FILENAME', + type=argparse.FileType('w'), + required=True) + + parserRequired.add_argument('--QCfolder', + help='Path of folder to save the quality control data for the matrix. The log files ' + 'produced this way can be loaded into `hicQC` in order to compare the quality of multiple ' + 'Hi-C libraries.', + metavar='FOLDER', + required=True) + + + parserOpt = parser.add_argument_group('Optional arguments') + + parserOpt.add_argument('--outBam', '-b', + help='Output bam file to process. Optional parameter. ' + 'A bam file containing all valid Hi-C reads can be created ' + 'using this option. This bam file could be useful to inspect ' + 'the distribution of valid Hi-C reads pairs or for other ' + 'downstream analyses, but is not used by any HiCExplorer tool. ' + 'Computation will be significantly longer if this option is set.', + metavar='bam file', + type=argparse.FileType('w'), + required=False) + + # group = parserOpt.add_mutually_exclusive_group(required=True) + + parserOpt.add_argument('--binSize', '-bs', + help='Size in bp for the bins. The bin size depends ' + 'on the depth of sequencing. Use a larger bin size for ' + 'libraries sequenced with lower depth. If not given, matrices of restriction site resolution will be built. ' + 'Optionally for mcool file format: Define multiple resolutions which are all a multiple of the first value. ' + ' Example: --binSize 10000 20000 50000 will create a mcool file formate containing the three defined resolutions.', + type=int, + nargs='+', + required=True) + + + + parserOpt.add_argument('--maxLibraryInsertSize', + help='The maximum library insert size defines different cut offs based on the maximum expected ' + 'library size. *This is not the average fragment size* but the higher end of the ' + 'the fragment size distribution (obtained using for example a Fragment Analyzer or a Bioanalyzer) ' + 'which usually is between 800 to 1500 bp. If this value is not known use the default value.' + ' The insert value is used to decide if two mates belong to the same fragment (by ' + 'checking if they are within this max insert size) and to decide if a mate is too far ' + 'away from the nearest restriction site' + ' (Default: %(default)s).', + type=int, + default=1000, + required=False) + + parserOpt.add_argument('--genomeAssembly', '-ga', + help='The genome the reads were mapped to. Used for metadata of cool file.') + + parserOpt.add_argument('--region', '-r', + help='Region of the genome to limit the operation to. ' + 'The format is chr:start-end. It is also possible to just ' + 'specify a chromosome, for example --region chr10', + metavar="CHR:START-END", + required=False, + type=genomicRegion + ) + + + parserOpt.add_argument('--keepSelfCircles', + help='If set, outward facing reads without any restriction fragment (self circles) are kept. ' + 'They will be counted and shown in the QC plots.', + required=False, + action='store_true' + ) + + parserOpt.add_argument('--minMappingQuality', + help='minimum mapping quality for reads to be accepted. ' + 'Because the restriction enzyme site could be located ' + 'on top of the read, this may reduce the ' + 'reported quality of the read. Thus, this parameter ' + 'may be adjusted if too many low quality ' + '(but otherwise perfectly valid Hi-C reads) are found. ' + 'A good strategy is to make a test run (using the --doTestRun), ' + 'then checking the results to see if too many low quality ' + 'reads are present and then using the bam file generated to ' + 'check if those low quality reads are caused by the read ' + 'not being mapped entirely' + ' (Default: %(default)s).', + required=False, + default=15, + type=int + ) + parserOpt.add_argument('--threads', + help='Number of threads. Using the python multiprocessing module. ' + 'One master process which is used to read the input file into the buffer and one process which is merging ' + 'the output bam files of the processes into one output bam file. All other threads do the actual computation. ' + 'Minimum value for the \'--thread\' parameter is 2. ' + 'The usage of 8 threads is optimal if you have an HDD. A higher number of threads is only ' + 'useful if you have a fast SSD. Have in mind that the performance of hicBuildMatrix is influenced by ' + 'the number of threads, the speed of your hard drive and the inputBufferSize. To clarify: the performance ' + 'with a higher thread number is not negative influenced but not positive too. With a slow HDD and a high number of ' + 'threads many threads will do nothing most of the time' + ' (Default: %(default)s).', + required=False, + default=4, + type=int + ) + parserOpt.add_argument('--inputBufferSize', + help='Size of the input buffer of each thread. 400,000 read pairs per input file per thread is the default value. ' + 'Reduce this value to decrease memory usage.', + required=False, + default=400000, + type=int + ) + parserOpt.add_argument('--doTestRun', + help='A test run is useful to test the quality ' + 'of a Hi-C experiment quickly. It works by ' + 'testing only 1,000,000 reads. This option ' + 'is useful to get an idea of quality control ' + 'values like inter-chromosomal interactions, ' + 'duplication rates etc.', + action='store_true' + ) + parserOpt.add_argument('--doTestRunLines', + help='Number of lines to consider for the qc test run' + ' (Default: %(default)s).', + required=False, + default=1000000, + type=int + ) + + parserOpt.add_argument('--skipDuplicationCheck', + help='Identification of duplicated read pairs is ' + 'memory consuming. Thus, in case of memory ' + 'errors this check can be skipped. However, ' + 'consider running a `--doTestRun` first to ' + 'get an estimation of the duplicated reads. ', + action='store_true' + ) + parserOpt.add_argument('--chromosomeSizes', '-cs', + help=('File with the chromosome sizes for your genome. A tab-delimited two column layout \"chr_name size\" is expected' + 'Usually the sizes can be determined from the SAM/BAM input files, however, ' + 'for cHi-C or scHi-C it can be that at the start or end no data is present. ' + 'Please consider that this option causes that only reads are considered which are on the listed chromosomes.' + 'Use this option to guarantee fixed sizes. An example file is available via UCSC: ' + 'http://hgdownload.soe.ucsc.edu/goldenPath/dm3/bigZips/dm3.chrom.sizes'), + type=argparse.FileType('r'), + metavar='txt file') + parserOpt.add_argument("--help", "-h", action="help", + help="show this help message and exit") + + parserOpt.add_argument('--version', action='version', + version='%(prog)s {}'.format(__version__)) + + return parser + + +def main(args=None): + """ + Reads line by line two bam files that are not sorted. + Each line in the two bam files should correspond + to the mapped position of the two ends of a Hi-C + fragment. + + Each mate pair is assessed to determine if it is + a valid Hi-C pair, in such case a matrix + reporting the counts of mates is constructed. + + A bam file containing the valid Hi-C reads + is also constructed. + """ + + args = parse_arguments().parse_args(args) + + createMatrix(pOutFileName=args.outFileName, pMaxDistance=None, pMaxLibraryInsertSize=args.maxLibraryInsertSize, pQCfolder=args.QCfolder, + pThreads=args.threads, pDanglingSequence=None, pRestrictionSequence=None, pSamFiles=args.samFiles, + pDoTestRun=args.doTestRun, pOutBam=args.outBam, pChromosomeSizes=args.chromosomeSizes, pRestrictionCutFile=None, + pRegion=args.region, pBinSize=args.binSize, pInputBufferSize=args.inputBufferSize, pMinDistance=None, + pDoTestRunLines=args.doTestRunLines, pSkipDuplicationCheck=args.skipDuplicationCheck, pMinMappingQuality=args.minMappingQuality, + pKeepSelfCircles=args.keepSelfCircles, pKeepSelfLigation=None, pGenomeAssembly=args.genomeAssembly) + + +class Tester(object): + def __init__(self): + hic_test_data_dir = os.environ.get('HIC_TEST_DATA_DIR', False) + if hic_test_data_dir: + self.root = hic_test_data_dir + else: + self.root = os.path.dirname( + os.path.abspath(__file__)) + "/test/test_data/" + self.bam_file_1 = os.path.join(self.root, "hic.bam") diff --git a/hicexplorer/lib/buildMatrixMethods.py b/hicexplorer/lib/buildMatrixMethods.py new file mode 100644 index 00000000..5f7e7628 --- /dev/null +++ b/hicexplorer/lib/buildMatrixMethods.py @@ -0,0 +1,1405 @@ +import logging +log = logging.getLogger(__name__) + +import argparse +import numpy as np +from scipy.sparse import coo_matrix, dia_matrix +import time +from os import unlink +import os +from io import StringIO +import traceback +import warnings +warnings.simplefilter(action="ignore", category=RuntimeWarning) +warnings.simplefilter(action="ignore", category=PendingDeprecationWarning) + +import pysam +from collections import OrderedDict + +from copy import deepcopy +from ctypes import Structure, c_uint, c_ushort +from multiprocessing import Process, Queue +from multiprocessing.sharedctypes import Array, RawArray + +from intervaltree import IntervalTree, Interval + +from Bio.Seq import Seq + +# own tools +from hicmatrix import HiCMatrix as hm +from hicexplorer.utilities import getUserRegion, genomicRegion +from hicexplorer._version import __version__ +import hicexplorer.hicPrepareQCreport as QC + +from hicmatrix.lib import MatrixFileHandler + +from hicexplorer import hicMergeMatrixBins +import logging +log = logging.getLogger(__name__) + +class C_Interval(Structure): + """Struct to map a Interval form intervaltree as a multiprocessing.sharedctype""" + _fields_ = [("begin", c_uint), + ("end", c_uint), + ("data", c_uint)] + + +class C_Coverage(Structure): + """Struct to model the coverage as a multiprocessing.sharedctype""" + + _fields_ = [("begin", c_uint), + ("end", c_uint)] + + +class ReadPositionMatrix(object): + """A class to check for PCR duplicates. + A set storing all possible + start sites. Checks if read is already in the set. + """ + + def __init__(self): + """ + >>> rp = ReadPositionMatrix() + >>> rp.is_duplicated('1', 0, '2', 0) + False + >>> rp.is_duplicated('1', 0, '2', 0) + True + """ + + self.pos_matrix = set() + + def is_duplicated(self, chrom1, start1, chrom2, start2): + if chrom1 < chrom2: + id_string = "{}-{}".format(chrom1, chrom2) + else: + id_string = "{}-{}".format(chrom2, chrom1) + + if start1 < start2: + id_string += "-{}-{}".format(start1, start2) + else: + id_string += "-{}-{}".format(start2, start1) + + if id_string in self.pos_matrix: + return True + else: + self.pos_matrix.add(id_string) + return False + +def intervalListToIntervalTree(interval_list): + r""" + given a dictionary containing tuples of chrom, start, end, + this is transformed to an interval trees. To each + interval an id is assigned, this id corresponds to the + position of the interval in the given array of tuples + and if needed can be used to identify + the index of a row/colum in the hic matrix. + + >>> bin_list = [('chrX', 0, 50000), ('chrX', 50000, 100000)] + >>> res = intervalListToIntervalTree(bin_list) + >>> sorted(res['chrX']) + [Interval(0, 50000, 0), Interval(50000, 100000, 1)] + """ + bin_int_tree = {} + + for intval_id, intval in enumerate(interval_list): + chrom, start, end = intval[0:3] + if chrom not in bin_int_tree: + bin_int_tree[chrom] = IntervalTree() + bin_int_tree[chrom].add(Interval(start, end, intval_id)) + + return bin_int_tree + + +def get_bins(bin_size, chrom_size, region=None): + r""" + Split the chromosomes into even sized bins + of length bin_size. + + Returns a list of tuples containing + ('chrom', start, end) + + >>> test = Tester() + >>> chrom_size = get_chrom_sizes(pysam.Samfile(test.bam_file_1)) + >>> sorted(get_bins(50000, chrom_size)) + [('contig-1', 0, 7125), ('contig-2', 0, 3345)] + >>> get_bins(50000, chrom_size, region='contig-1') + [('contig-1', 0, 7125)] + """ + bin_intvals = [] + start = 0 + if region: + chrom_size, start, _, _ = \ + getUserRegion(chrom_size, region) + + for chrom, size in chrom_size: + for interval in range(start, size, bin_size): + bin_intvals.append((chrom, interval, + min(size, interval + bin_size))) + return bin_intvals + + +def bed2interval_list(bed_file_handler, pChromosomeSize, pRegion): + r""" + reads a BED file and returns + a list of tuples containing + (chromosome name, start, end) + + >>> import tempfile, os + + Make a temporary BED file + >>> _file = tempfile.NamedTemporaryFile(delete=False) + >>> _file.close() + >>> file_tmp = open(_file.name, 'w') + >>> foo = file_tmp.write('chr1\t10\t20\tH1\t0\n') + >>> foo = file_tmp.write("chr1\t60\t70\tH2\t0\n") + >>> file_tmp.close() + >>> bed2interval_list(open(_file.name, 'r'), None, None) + [('chr1', 10, 20), ('chr1', 60, 70)] + >>> os.remove(_file.name) + """ + + if pRegion is not None: + chrom_size, start_region, end_region, _ = \ + getUserRegion(pChromosomeSize, pRegion) + + count = 0 + interval_list = [] + for line in bed_file_handler: + count += 1 + fields = line.strip().split() + try: + chrom, start, end = fields[0], int(fields[1]), int(fields[2]) + + except IndexError: + log.error("error reading BED file at line {}".format(count)) + + if pRegion is not None: + if chrom == chrom_size[0] and start_region <= start and end_region <= end: + interval_list.append((chrom, start, end)) + else: + interval_list.append((chrom, start, end)) + + return interval_list + + +def get_rf_bins(rf_cut_intervals, min_distance=200, max_distance=800): + r""" + returns a list of tuples containing a bin having the format: + ('chrom', start, end) + + The goal is to have bins containing each a restriction site close to + the center. Restriction sites that are less than 'min_distance' appart + are merged. To the left and right of the restriction site + 'max_distance' bp are added unless they clash with other bin. + Resulting bins are not immediately one after the other. + + The given cut sites list has to be ordered chr, and start site + + :param rf_cut_intervals: list of tuples containing the position of restriction fragment sites + :param min_distance: min distance between restriction fragment sites. + :param max_distance: max distance between restriction fragment and bin border. + :return: + + # two restriction sites of length 10 + >>> rf_cut_interval = [('chr1', 10, 20), ('chr1', 60, 70)] + + The following two bins are close together + and should be merged under min_distance = 20 + >>> rf_cut_interval.extend([('chr2', 20, 30), ('chr2', 40, 50), + ... ('chr2', 70, 80)]) + >>> get_rf_bins(rf_cut_interval, min_distance=10, max_distance=20) + [('chr1', 0, 40), ('chr1', 40, 90), ('chr2', 0, 60), ('chr2', 60, 100)] + """ + log.info("Minimum distance considered between " + "restriction sites is {}\nMax " + "distance: {}\n".format(min_distance, max_distance)) + + chrom, start, end = list(zip(*rf_cut_intervals)) + + rest_site_len = end[0] - start[0] + + # find sites that are less than min_distance apart + to_merge = np.flatnonzero(np.diff(start) - rest_site_len <= min_distance) + to_merge += 1 # + 1 to account for np.diff index handling + merge_idx = 0 + # add max_distance to both sides + start = np.array(start) - max_distance + end = np.array(end) + max_distance + new_start = [max(0, start[0])] + new_end = [] + new_chrom = [chrom[0]] + for idx in range(1, len(start)): + # identify end of chromosome + if chrom[idx] != chrom[idx - 1]: + new_start.append(max(0, start[idx])) + new_end.append(end[idx - 1]) + new_chrom.append(chrom[idx]) + merge_idx += 1 + continue + + if merge_idx < len(to_merge) and idx == to_merge[merge_idx]: + merge_idx += 1 + continue + + # identify overlapping bins + if chrom[idx] == chrom[idx - 1] and end[idx - 1] > start[idx]: + middle = start[idx] + int((end[idx - 1] - start[idx]) / 2) + new_start.append(middle) + new_end.append(middle) + else: + new_start.append(start[idx]) + new_end.append(end[idx - 1]) + new_chrom.append(chrom[idx]) + + new_end.append(end[-1]) + assert len(new_chrom) == len(new_start), "error" + assert len(new_end) == len(new_start), "error" + + intervals = zip(new_chrom, new_start, new_end) + intervals = [(_chrom, _start, _end) for _chrom, _start, + _end in intervals if _end - _start >= min_distance] + return intervals + + +def get_chrom_sizes(bam_handle): + """ + return the list of chromosome names and their + size from the bam file + The return value is a list of the form + [('chr1', 2343434), ('chr2', 43432432)] + + >>> test = Tester() + >>> get_chrom_sizes(pysam.Samfile(test.bam_file_1, 'rb')) + [('contig-1', 7125), ('contig-2', 3345)] + """ + + # in some cases there are repeated entries in + # the bam file. Thus, I first convert to dict, + # then to list. + list_chrom_sizes = OrderedDict(zip(bam_handle.references, + bam_handle.lengths)) + return list(list_chrom_sizes.items()) + + +def check_dangling_end(read, dangling_sequences): + """ + given a pysam read object, this function + checks if a forward read starts with + the dangling sequence or if a reverse + read ends with the dangling sequence. + """ + ds = dangling_sequences + # check if keys are existing, return false otherwise + if 'pat_forw' not in ds or 'pat_rev' not in ds: + return False + # skip forward read that stars with the restriction sequence + if not read.is_reverse and \ + read.seq.upper().startswith(ds['pat_forw']): + return True + + # skip reverse read that ends with the restriction sequence + if read.is_reverse and \ + read.seq.upper().endswith(ds['pat_rev']): + return True + + return False + + +def get_supplementary_alignment(read, pysam_obj): + """Checks if a read has a supplementary alignment + :param read pysam AlignedSegment + :param pysam_obj pysam file object + + :return pysam AlignedSegment of the supplementary aligment or None in case of no supplementary alignment + """ + + # the SA field contains a list of other alignments as a ';' delimited list in the format + # rname,pos,strand,CIGAR,mapQ,NM; + if read.has_tag('SA'): + # field always ends in ';' thus last element after split is always + # empty, hence [0:-1] + other_alignments = read.get_tag('SA').split(";")[0:-1] + supplementary_alignment = [] + for i in range(len(other_alignments)): + _sup = next(pysam_obj) + if _sup.qname == read.qname: + supplementary_alignment.append(_sup) + + return supplementary_alignment + + else: + return None + + +def get_correct_map(primary, supplement_list): + r""" + Decides which of the mappings, the primary or supplement, is correct. In the case of + long reads (eg. 150bp) the restriction enzyme site could split the read into two parts + but only the mapping corresponding to the start of the read should be considered as + the correct one. + + For example: + + Forward read: + + _ <- cut site + |======================|==========> + - + |----------------------| + correct mapping + + + reverse read: + + _ <- cut site + <======================|==========| + - + |----------| + correct mapping + + + :param primary: pysam AlignedSegment for primary mapping + :param supplement_list: list of pysam AlignedSegment for secondary mapping + + :return: pysam AlignedSegment that is mapped correctly + + Examples + -------- + >>> sam_file_name = "/tmp/test.sam" + >>> sam_file = open(sam_file_name, 'w') + >>> _ = sam_file.write('''@HD\tVN:1.0 + ... @SQ\tSN:chr1\tLN:1575\tAH:chr1:5000000-5010000 + ... read\t65\tchr1\t33\t20\t10S1D25M\t=\t200\t167\tAGCTTAGCTAGCTACCTATATCTTGGTCTTGGCCG\t<<<<<<<<<<<<<<<<<<<<<:<9/,&,22;;<<<\t + ... read\t2113\tchr1\t88\t30\t1S34M\t=\t500\t412\tACCTATATCTTGGCCTTGGCCGATGCGGCCTTGCA\t<<<<<;<<<<7;:<<<6;<<<<<<<<<<<<7<<<<\t + ... read\t2113\tchr1\t120\t30\t5S30M\t=\t500\t412\tACCTATATCTTGGCCTTGGCCGATGCGGCCTTGCA\t<<<<<;<<<<7;:<<<6;<<<<<<<<<<<<7<<<<''') + >>> sam_file.close() + >>> sam = pysam.Samfile(sam_file_name, "r") + >>> read_list = [read for read in sam] + >>> primary = read_list[0] + >>> secondary_list = read_list[1:] + >>> first_mapped = get_correct_map(primary, secondary_list) + + The first mapped read is the first secondary at position 88 (sam 1-based) = 87 (0-based) + >>> print(first_mapped.pos) + 87 + + """ + + for supplement in supplement_list: + assert primary.qname == supplement.qname, "ERROR, primary " \ + "and supplementary reads do not have the same id. The ids " \ + "are as follows\n{}\n{}".format(primary.qname, supplement.qname) + read_list = [primary] + supplement_list + first_mapped = [] + for idx, read in enumerate(read_list): + if read.is_reverse: + cigartuples = read.cigartuples[::-1] + else: + cigartuples = read.cigartuples[:] + + # For each read in read_list, calculate the position of the first match (operation M in CIGAR string) in the read sequence. + # The calculation is done by adding up the lengths of all the operations until the first match. + # CIGAR string is a list of tuples of (operation, length). Match is stored as CMATCH. + match_sum = 0 + for op, count in cigartuples: + if op == pysam.CMATCH: + break + match_sum += count + + first_mapped.append(match_sum) + # find which read has a cigar string that maps first than any of the + # others. + idx_min = first_mapped.index(min(first_mapped)) + + return read_list[idx_min] + + +def enlarge_bins(bin_intervals, chrom_sizes): + r""" + takes a list of consecutive but not + one after the other bin intervals + and joins them such that the + end and start of consecutive bins + is the same. + + >>> chrom_sizes = [('chr1', 100), ('chr2', 100)] + >>> bin_intervals = [('chr1', 10, 30), ('chr1', 50, 80), + ... ('chr2', 10, 60), ('chr2', 60, 90)] + >>> enlarge_bins(bin_intervals, chrom_sizes) + [('chr1', 0, 40), ('chr1', 40, 100), ('chr2', 0, 60), ('chr2', 60, 100)] + """ + # enlarge remaining bins + chr_start = True + chrom_sizes_dict = dict(chrom_sizes) + for idx in range(len(bin_intervals) - 1): + chrom, start, end = bin_intervals[idx] + chrom_next, start_next, end_next = bin_intervals[idx + 1] + if chr_start is True: + start = 0 + chr_start = False + if chrom == chrom_next and \ + end != start_next: + middle = start_next - int((start_next - end) / 2) + bin_intervals[idx] = (chrom, start, middle) + bin_intervals[idx + 1] = (chrom, middle, end_next) + if chrom != chrom_next: + bin_intervals[idx] = (chrom, start, chrom_sizes_dict[chrom]) + bin_intervals[idx + 1] = (chrom_next, 0, end_next) + + chrom, start, end = bin_intervals[-1] + bin_intervals[-1] = (chrom, start, chrom_sizes_dict[chrom]) + + return bin_intervals + + +def readBamFiles(pFileOneIterator, pFileTwoIterator, pNumberOfItemsPerBuffer, pSkipDuplicationCheck, pReadPosMatrix, pRefId2name, pMinMappingQuality): + """Read the two bam input files into n buffers each with pNumberOfItemsPerBuffer + with n = number of processes. The duplication check is handled here too.""" + buffer_mate1 = [] + buffer_mate2 = [] + duplicated_pairs = 0 + one_mate_unmapped = 0 + one_mate_not_unique = 0 + one_mate_low_quality = 0 + + all_data_read = False + j = 0 + iter_num = 0 + while j < pNumberOfItemsPerBuffer: + try: + mate1 = next(pFileOneIterator) + mate2 = next(pFileTwoIterator) + except StopIteration: + all_data_read = True + break + iter_num += 1 + + # skip 'not primary' alignments + while mate1.flag & 256 == 256: + try: + mate1 = next(pFileOneIterator) + except StopIteration: + all_data_read = True + break + while mate2.flag & 256 == 256: + try: + mate2 = next(pFileTwoIterator) + except StopIteration: + all_data_read = True + break + + assert mate1.qname == mate2.qname, "FATAL ERROR {} {} " \ + "Be sure that the sam files have the same read order " \ + "If using Bowtie2 or Hisat2 add " \ + "the --reorder option".format(mate1.qname, mate2.qname) + + # check for supplementary alignments + # (needs to be done before skipping any unmapped reads + # to keep the order of the two bam files in sync) + mate1_supplementary_list = get_supplementary_alignment( + mate1, pFileOneIterator) + mate2_supplementary_list = get_supplementary_alignment( + mate2, pFileTwoIterator) + + if mate1_supplementary_list: + mate1 = get_correct_map(mate1, mate1_supplementary_list) + + if mate2_supplementary_list: + mate2 = get_correct_map(mate2, mate2_supplementary_list) + + # skip if any of the reads is not mapped + if mate1.flag & 0x4 == 4 or mate2.flag & 0x4 == 4: + one_mate_unmapped += 1 + continue + + # skip if the read quality is low + if mate1.mapq < pMinMappingQuality or mate2.mapq < pMinMappingQuality: + # for bwa other way to test + # for multi-mapping reads is with a mapq = 0 + # the XS flag is not reliable. + if mate1.mapq == 0 & mate2.mapq == 0: + one_mate_not_unique += 1 + continue + + """ + # check if low quality is because of + # read being repetitive + # by reading the XS flag. + # The XS:i field is set by bowtie when a read is + # multi read and it contains the mapping score of the next + # best match + if 'XS' in dict(mate1.tags) or 'XS' in dict(mate2.tags): + one_mate_not_unique += 1 + continue + """ + + one_mate_low_quality += 1 + continue + + if pSkipDuplicationCheck is False: + if pReadPosMatrix.is_duplicated(pRefId2name[mate1.rname], + mate1.pos, + pRefId2name[mate2.rname], + mate2.pos): + duplicated_pairs += 1 + continue + buffer_mate1.append(mate1) + buffer_mate2.append(mate2) + j += 1 + + if all_data_read and len(buffer_mate1) != 0 and len(buffer_mate2) != 0: + return buffer_mate1, buffer_mate2, True, duplicated_pairs, one_mate_unmapped, one_mate_not_unique, one_mate_low_quality, iter_num - len(buffer_mate1) + if all_data_read and len(buffer_mate1) == 0 or len(buffer_mate2) == 0: + return None, None, True, duplicated_pairs, one_mate_unmapped, one_mate_not_unique, one_mate_low_quality, iter_num - len(buffer_mate1) + return buffer_mate1, buffer_mate2, False, duplicated_pairs, one_mate_unmapped, one_mate_not_unique, one_mate_low_quality, iter_num - len(buffer_mate1) + + + +def process_data(pMateBuffer1, pMateBuffer2, pMinMappingQuality, + pKeepSelfCircles, pRestrictionSequence, pKeepSelfLigation, pMatrixSize, + pRfPositions, pRefId2name, + pDanglingSequences, pBinsize, pResultIndex, + pQueueOut, pTemplate, pOutputBamSet, pCounter, + pSharedBinIntvalTree, pDictBinIntervalTreeIndex, pCoverage, pCoverageIndex, + pOutputFileBufferDir, pRow, pCol, pData, + pMaxInsertSize, pQuickQCMode): + """ + This function computes for a given number of elements in pMateBuffer1 and pMaterBuffer2 a partial interaction matrix. + This function is used by multiple processes to speed up the computation. + All partial matrices are merged in the end into one interaction matrix. + + Parameters + ---------- + pMateBuffer1 : List of n reads of type 'pysam.libcalignedsegment.AlignedSegment' of sam input file 1 + pMateBuffer2 : List of n reads of type 'pysam.libcalignedsegment.AlignedSegment' of sam input file 2 + pMinMappingQuality : integer, minimum mapping quality of a read + pKeepSelfCircles : boolean, if self circles should be kept + pRestrictionSequence : List of String, the restriction sequence + pKeepSelfLigation : If self ligations should be removed + pMatrixSize : integer, the size of the interaction matrix + pRfPositions : intervalTree, only used if a restriction cut file and not a bin size was defined. + pRefId2name : Tuple, Maps a reference id to a name + pDanglingSequences : dict, dict of dangling sequences + pBinsize : integer, the size of the bins + pResultIndex : integer, number of processs, range(0, threads). Is returned via the queue to have access to the right row, col and data array after the computation. + pQueueOut : multiprocessing.Queue, queue to return the computed counting variables: + one_mate_unmapped, one_mate_low_quality, one_mate_not_unique, dangling_end, self_circle, self_ligation, same_fragment, + mate_not_close_to_rf, count_inward, count_outward, count_left, count_right, inter_chromosomal, short_range, long_range, + pair_added, len(pMateBuffer1), pResultIndex, pCounter + pTemplate : The template for the output bam file + pOutputBamSet : If a output bam file should be written. Depending on the input parameter '--outBam' + pOutputName : String, Name of the partial bam file + pCounter : integer, value which is returned to the main process. The main process can than write a pCounter.bam_done file + to signal the background process, which is merging the partial bam files into one, that this dataset can be merged. + pSharedBinIntvalTree : multiprocessing.sharedctype.RawArray of C_Interval, stores the interval tree in a 1D-RawArray. + pDictBinIntervalTreeIndex : dict, stores the information at which index position a given interval starts and ends in the 1D-array 'pSharedBinIntvalTree' + pCoverage : multiprocessing.sharedctype.Array of c_uint, Stores the coverage in a 1D-Array + pCoverageIndex : multiprocessing.sharedctype.RawArray of C_Coverage, stores the information in the 1D-array 'pCoverage' + pOutputFileBufferDir : String, the directory where the partial output bam files are buffered. Default is '/dev/shm/' + pRow : multiprocessing.sharedctype.RawArray of c_uint, Stores the row index information. It is available for all processes and does not need to be copied. + pCol : multiprocessing.sharedctype.RawArray of c_uint, stores the column index information. It is available for all processes and does not need to be copied. + pData : multiprocessing.sharedctype.RawArray of c_ushort, stores a 1 for each row - column pair. It is available for all processes and does not need to be copied. + pMaxInsertSize : maximum illumina insert size + """ + try: + + one_mate_unmapped = 0 + one_mate_low_quality = 0 + one_mate_not_unique = 0 + dangling_end = {} + if pRestrictionSequence is not None: + for restrictionSequence in pRestrictionSequence: + dangling_end[restrictionSequence] = 0 + self_circle = 0 + self_ligation = 0 + same_fragment = 0 + mate_not_close_to_rf = 0 + + count_inward = 0 + count_outward = 0 + count_left = 0 + count_right = 0 + inter_chromosomal = 0 + short_range = 0 + long_range = 0 + + pair_added = 0 + + iter_num = 0 + hic_matrix = None + + out_bam_index_buffer = [] + + if pMateBuffer1 is None or pMateBuffer2 is None: + + pQueueOut.put([hic_matrix, [one_mate_unmapped, one_mate_low_quality, one_mate_not_unique, dangling_end, self_circle, self_ligation, same_fragment, + mate_not_close_to_rf, count_inward, count_outward, + count_left, count_right, inter_chromosomal, short_range, long_range, pair_added, iter_num, pResultIndex, out_bam_index_buffer]]) + return + + while iter_num < len(pMateBuffer1) and iter_num < len(pMateBuffer2): + mate1 = pMateBuffer1[iter_num] + mate2 = pMateBuffer2[iter_num] + iter_num += 1 + + # check if reads belong to a bin + # + # pDictBinInterval stores the start and end position for each chromsome in the array 'pSharedBinIntvalTree' + # To get to the right interval a binary search is used. + mate_bins = [] + mate_is_unasigned = False + for mate in [mate1, mate2]: + mate_ref = pRefId2name[mate.rname] + # find the middle genomic position of the read. This is used to + # find the bin it belongs to. + read_middle = mate.pos + int(mate.qlen / 2) + try: + start, end = pDictBinIntervalTreeIndex[mate_ref] + middle_pos = int((start + end) / 2) + mate_bin = None + while not start > end: + if pSharedBinIntvalTree[middle_pos].begin <= read_middle and read_middle <= pSharedBinIntvalTree[middle_pos].end: + mate_bin = pSharedBinIntvalTree[middle_pos] + mate_is_unasigned = False + break + elif pSharedBinIntvalTree[middle_pos].begin > read_middle: + end = middle_pos - 1 + middle_pos = int((start + end) / 2) + mate_is_unasigned = True + else: + start = middle_pos + 1 + middle_pos = int((start + end) / 2) + mate_is_unasigned = True + + except KeyError: + # for small contigs it can happen that they are not + # in the bin_intval_tree keys if no restriction site is found + # on the contig. + mate_is_unasigned = True + break + + # report no match case + if mate_bin is None: + mate_is_unasigned = True + break + mate_bin_id = mate_bin.data + mate_bins.append(mate_bin_id) + + # if a mate is unassigned, it means it is not close + # to a restriction site + if mate_is_unasigned is True: + mate_not_close_to_rf += 1 + continue + + # check if mates are in the same chromosome + if mate1.reference_id != mate2.reference_id: + orientation = 'diff_chromosome' + else: + # to identify 'inward' and 'outward' orientations + # the order or the mates in the genome has to be + # known. + if mate1.pos < mate2.pos: + first_mate = mate1 + second_mate = mate2 + else: + first_mate = mate2 + second_mate = mate1 + + """ + outward + <--------------- ----------------> + + inward + ---------------> <---------------- + + same-strand-right + ---------------> ----------------> + + same-strand-left + <--------------- <---------------- + """ + + if not first_mate.is_reverse and second_mate.is_reverse: + orientation = 'inward' + elif first_mate.is_reverse and not second_mate.is_reverse: + orientation = 'outward' + elif first_mate.is_reverse and second_mate.is_reverse: + orientation = 'same-strand-left' + else: + orientation = 'same-strand-right' + + # check self-circles + # self circles are defined as outward pairs that do not + # have a restriction sequence in between. The distance of < 25kb is + # used to only check close outward pairs as far apart pairs can not be self-circles + if abs(mate2.pos - mate1.pos) < 25000 and orientation == 'outward': + has_rf = [] + + if pRfPositions and pRestrictionSequence: + # check if in between the two mate + # ends the restriction fragment is found. + # check for multiple restriction sequences + for restrictionSequence in pRestrictionSequence: + # the interval used is: + # start of fragment + length of restriction sequence + # end of fragment - length of restriction sequence + # the restriction sequence length is subtracted + # such that only fragments internally containing + # the restriction site are identified + frag_start = min(mate1.pos, mate2.pos) + \ + len(restrictionSequence) + frag_end = max(mate1.pos + mate1.qlen, mate2.pos + mate2.qlen) - len(restrictionSequence) + mate_ref = pRefId2name[mate1.rname] + if mate_ref in pRfPositions: + has_rf.extend(sorted( + pRfPositions[mate_ref][frag_start: frag_end])) + + if len(has_rf) == 0: + self_circle += 1 + if not pKeepSelfCircles: + continue + if abs(mate2.pos - mate1.pos) < pMaxInsertSize and orientation == 'inward': + # check for dangling ends if the restriction sequence is known and if they look + # like 'same fragment' + if pRestrictionSequence: + if pDanglingSequences: + + # check for dangling ends in sequence. Stop check with first match + one_match = False + for restrictionSequence in pRestrictionSequence: + if check_dangling_end(mate1, pDanglingSequences[restrictionSequence]) or \ + check_dangling_end(mate2, pDanglingSequences[restrictionSequence]): + dangling_end[restrictionSequence] += 1 + one_match = True + break + if one_match: + continue + has_rf = [] + + if pRfPositions and pRestrictionSequence: + # check if in between the two mate + # ends the restriction fragment is found. + + # the interval used is: + # start of fragment + length of restriction sequence + # end of fragment - length of restriction sequence + # the restriction sequence length is subtracted + # such that only fragments internally containing + # the restriction site are identified + + for restrictionSequence in pRestrictionSequence: + frag_start = min(mate1.pos, mate2.pos) + \ + len(restrictionSequence) + frag_end = max(mate1.pos + mate1.qlen, mate2.pos + mate2.qlen) - len(restrictionSequence) + mate_ref = pRefId2name[mate1.rname] + if mate_ref in pRfPositions: + has_rf.extend(sorted( + pRfPositions[mate_ref][frag_start: frag_end])) + + # case when there is no restriction fragment site between the + # mates + if len(has_rf) == 0: + same_fragment += 1 + continue + + self_ligation += 1 + + if not pKeepSelfLigation: + # skip self ligations + continue + + # set insert size to save bam + mate1.isize = mate2.pos - mate1.pos + mate2.isize = mate1.pos - mate2.pos + + # if mate_bins, which is set in the previous section + # does not have size=2, it means that one + # of the exceptions happened + if len(mate_bins) != 2: + continue + + # count type of pair (distance, orientation) + if mate1.reference_id != mate2.reference_id: + inter_chromosomal += 1 + + elif abs(mate2.pos - mate1.pos) < 20000: + short_range += 1 + else: + long_range += 1 + + if orientation == 'inward': + count_inward += 1 + elif orientation == 'outward': + count_outward += 1 + elif orientation == 'same-strand-left': + count_left += 1 + elif orientation == 'same-strand-right': + count_right += 1 + + for mate in [mate1, mate2]: + # fill in coverage vector + vec_start = int(max(0, mate.pos - mate_bin.begin) / pBinsize) + length_coverage = pCoverageIndex[mate_bin_id].end - \ + pCoverageIndex[mate_bin_id].begin + vec_end = min(length_coverage, int( + vec_start + len(mate.seq) / pBinsize)) + coverage_index = pCoverageIndex[mate_bin_id].begin + vec_start + coverage_end = pCoverageIndex[mate_bin_id].begin + vec_end + for i in range(coverage_index, coverage_end, 1): + pCoverage[i] += 1 + + if not pQuickQCMode: + pRow[pair_added] = mate_bins[0] + pCol[pair_added] = mate_bins[1] + pData[pair_added] = np.uint8(1) + + pair_added += 1 + if pOutputBamSet: + + out_bam_index_buffer.append(iter_num - 1) + + pQueueOut.put([[one_mate_unmapped, one_mate_low_quality, one_mate_not_unique, dangling_end, self_circle, self_ligation, same_fragment, + mate_not_close_to_rf, count_inward, count_outward, + count_left, count_right, inter_chromosomal, short_range, long_range, pair_added, len(pMateBuffer1), pResultIndex, pCounter, out_bam_index_buffer]]) + except Exception as exp: + pQueueOut.put('Fail: ' + str(exp) + traceback.format_exc()) + return + return + +def createMatrix(pOutFileName, pMaxDistance, pMaxLibraryInsertSize, pQCfolder, + pThreads, pDanglingSequence, pRestrictionSequence, pSamFiles, + pDoTestRun, pOutBam, pChromosomeSizes, pRestrictionCutFile, + pRegion, pBinSize, pInputBufferSize, + pDoTestRunLines, pSkipDuplicationCheck, pMinMappingQuality, + pKeepSelfCircles, pKeepSelfLigation, pMinDistance, pGenomeAssembly): + # pOutFileName.name = pOutFileName.name.strip() + # log.debug('pOutFileName.name: {}'.format(pOutFileName.name.endswith('.h5'))) + if not pOutFileName.name.endswith('.h5') and not pOutFileName.name.endswith('.cool'): + if '.mcool' not in pOutFileName.name: + log.error('Please define the file extension. h5 and cool are supported, or the specializations of cool, mcool. Given input {}'.format(pOutFileName.name)) + exit(1) + # for backwards compatibility + if pMaxDistance is not None: + pMaxLibraryInsertSize = pMaxDistance + try: + QC.make_sure_path_exists(pQCfolder) + except OSError: + exit("Can't open/create QC folder path: {}. Please check".format(pQCfolder)) + + if pThreads < 2: + pThreads = 2 + warnings.warn( + "\nAt least two threads need to be defined. Setting --threads = 2!s\n") + + if pDanglingSequence and not pRestrictionSequence: + exit("\nIf --danglingSequence is set, --restrictionSequence needs to be set too.\n") + + log.info("reading {} and {} to build hic_matrix\n".format(pSamFiles[0].name, + pSamFiles[1].name)) + str1 = pysam.Samfile(pSamFiles[0].name, 'rb') + str2 = pysam.Samfile(pSamFiles[1].name, 'rb') + + pSamFiles[0].close() + pSamFiles[1].close() + if not pDoTestRun: + if pOutBam: + pOutBam.close() + out_bam_file = pysam.Samfile(pOutBam.name, 'wb', template=str1) + + if pChromosomeSizes is None: + chrom_sizes = get_chrom_sizes(str1) + else: + chrom_sizes = OrderedDict() + with open(pChromosomeSizes.name, 'r') as file: + file_ = True + while file_: + file_ = file.readline().strip() + if file_ != '': + line_split = file_.split('\t') + chrom_sizes[line_split[0]] = int(line_split[1]) + chrom_sizes = list(chrom_sizes.items()) + + # log.debug('chrom_sizes {}'.format(chrom_sizes)) + read_pos_matrix = ReadPositionMatrix() + + rf_interval = [] + if pRestrictionCutFile: + for restrictionCutFile in pRestrictionCutFile: + rf_interval.extend(bed2interval_list(restrictionCutFile, chrom_sizes, pRegion)) + + rf_positions = intervalListToIntervalTree(rf_interval) + log.debug('rf_positions {}'.format(rf_positions.keys())) + else: + rf_positions = None + + if pBinSize: + bin_intervals = get_bins(pBinSize[0], chrom_sizes, pRegion) + else: + bin_intervals = get_rf_bins(rf_interval, + min_distance=pMinDistance, + max_distance=pMaxLibraryInsertSize) + + matrix_size = len(bin_intervals) + bin_intval_tree = intervalListToIntervalTree(bin_intervals) + ref_id2name = str1.references + + # build c_type shared memory for the interval tree + shared_array_list = [] + index_dict = {} + end = -1 + for i, seq in enumerate(bin_intval_tree): + start = end + 1 + interval_list = [] + for interval in bin_intval_tree[seq]: + interval_list.append((interval.begin, interval.end, interval.data)) + end = start + len(bin_intval_tree[seq]) - 1 + index_dict[seq] = (start, end) + interval_list = sorted(interval_list) + shared_array_list.extend(interval_list) + shared_build_intval_tree = RawArray(C_Interval, shared_array_list) + bin_intval_tree = None + dangling_sequences = {} + if pDanglingSequence: + # build a list of dangling sequences + if pRestrictionSequence is not None: + for i in range(0, len(pRestrictionSequence)): + pRestrictionSequence[i] = pRestrictionSequence[i].upper() + pDanglingSequence[i] = pDanglingSequence[i].upper() + dangling_sequences[pRestrictionSequence[i]] = {} + dangling_sequences[pRestrictionSequence[i]]['pat_forw'] = pDanglingSequence[i] + dangling_sequences[pRestrictionSequence[i]]['pat_rev'] = str( + Seq(pDanglingSequence[i]).reverse_complement()) + + log.info("dangling sequences to check " + "are {}\n".format(dangling_sequences)) + + # initialize coverage vectors that + # save the number of reads that overlap + # a bin. + # To save memory, coverage is not measured by bp + # but by bins of length 10bp + binsize = 10 + number_of_elements_coverage = 0 + start_pos_coverage = [] + end_pos_coverage = [] + + for chrom, start, end in bin_intervals: + start_pos_coverage.append(number_of_elements_coverage) + + number_of_elements_coverage += (end - start) // binsize + end_pos_coverage.append(number_of_elements_coverage - 1) + pos_coverage = RawArray(C_Coverage, list(zip( + start_pos_coverage, end_pos_coverage))) + start_pos_coverage = None + end_pos_coverage = None + coverage = Array(c_uint, [0] * number_of_elements_coverage) + + # define global shared ctypes arrays for row, col and data + pThreads = pThreads - 1 + row = [None] * pThreads + col = [None] * pThreads + data = [None] * pThreads + for i in range(pThreads): + row[i] = RawArray(c_uint, pInputBufferSize) + col[i] = RawArray(c_uint, pInputBufferSize) + data[i] = RawArray(c_ushort, pInputBufferSize) + + start_time = time.time() + + iter_num = 0 + # pair_added = 0 + # hic_matrix = None + + one_mate_unmapped = 0 + one_mate_low_quality = 0 + one_mate_not_unique = 0 + dangling_end = {} + if pRestrictionSequence is not None: + for restrictionSequence in pRestrictionSequence: + dangling_end[restrictionSequence] = 0 + + self_circle = 0 + self_ligation = 0 + same_fragment = 0 + mate_not_close_to_rf = 0 + duplicated_pairs = 0 + + count_inward = 0 + count_outward = 0 + count_left = 0 + count_right = 0 + inter_chromosomal = 0 + short_range = 0 + long_range = 0 + + pair_added = 0 + + # input buffer for bam files + buffer_workers1 = [None] * pThreads + buffer_workers2 = [None] * pThreads + + # output buffer to write bam with mate1 and mate2 pairs + process = [None] * pThreads + all_data_processed = False + hic_matrix = coo_matrix((matrix_size, matrix_size), dtype='uint32') + queue = [None] * pThreads + + all_threads_done = False + thread_done = [False] * pThreads + count_output = 0 + count_call_of_read_input = 0 + computed_pairs = 0 + + if pDoTestRun: + pInputBufferSize = pDoTestRunLines + fail_flag = False + fail_message = '' + while not all_data_processed or not all_threads_done: + + for i in range(pThreads): + if queue[i] is None and not all_data_processed: + count_call_of_read_input += 1 + + buffer_workers1[i], buffer_workers2[i], all_data_processed, \ + duplicated_pairs_, one_mate_unmapped_, one_mate_not_unique_, \ + one_mate_low_quality_, iter_num_ = readBamFiles(pFileOneIterator=str1, + pFileTwoIterator=str2, + pNumberOfItemsPerBuffer=pInputBufferSize, + pSkipDuplicationCheck=pSkipDuplicationCheck, + pReadPosMatrix=read_pos_matrix, + pRefId2name=ref_id2name, + pMinMappingQuality=pMinMappingQuality + ) + duplicated_pairs += duplicated_pairs_ + one_mate_unmapped += one_mate_unmapped_ + one_mate_not_unique += one_mate_not_unique_ + one_mate_low_quality += one_mate_low_quality_ + iter_num += iter_num_ + queue[i] = Queue() + thread_done[i] = False + computed_pairs += len(buffer_workers1[i]) + # create process to compute hic matrix for this buffer + process[i] = Process(target=process_data, kwargs=dict( + pMateBuffer1=buffer_workers1[i], + pMateBuffer2=buffer_workers2[i], + pMinMappingQuality=pMinMappingQuality, + pKeepSelfCircles=pKeepSelfCircles, + pRestrictionSequence=pRestrictionSequence, + pKeepSelfLigation=pKeepSelfLigation, + pMatrixSize=matrix_size, + pRfPositions=rf_positions, + pRefId2name=ref_id2name, + pDanglingSequences=dangling_sequences, + pBinsize=binsize, + pResultIndex=i, + pQueueOut=queue[i], + pTemplate=str1, + pOutputBamSet=pOutBam, + pCounter=count_output, + pSharedBinIntvalTree=shared_build_intval_tree, + pDictBinIntervalTreeIndex=index_dict, + pCoverage=coverage, + pCoverageIndex=pos_coverage, + pOutputFileBufferDir="", + pRow=row[i], + pCol=col[i], + pData=data[i], + pMaxInsertSize=pMaxLibraryInsertSize, + pQuickQCMode=pDoTestRun + )) + process[i].start() + count_output += 1 + + elif queue[i] is not None and not queue[i].empty(): + result = queue[i].get() + if 'Fail:' in result: + fail_flag = True + fail_message = result[6:] + else: + if result[0] is not None: + elements = result[0][15] + if hic_matrix is None: + hic_matrix = coo_matrix( + (data[i][:elements], (row[i][:elements], col[i][:elements])), shape=(matrix_size, matrix_size)) + else: + hic_matrix += coo_matrix( + (data[i][:elements], (row[i][:elements], col[i][:elements])), shape=(matrix_size, matrix_size)) + + for sequence in result[0][3]: + dangling_end[sequence] += result[0][3][sequence] + self_circle += result[0][4] + self_ligation += result[0][5] + same_fragment += result[0][6] + mate_not_close_to_rf += result[0][7] + + count_inward += result[0][8] + count_outward += result[0][9] + count_left += result[0][10] + count_right += result[0][11] + inter_chromosomal += result[0][12] + short_range += result[0][13] + long_range += result[0][14] + + pair_added += result[0][15] + iter_num += result[0][16] + + for bam_index in result[0][19]: + mate1 = buffer_workers1[i][bam_index] + mate2 = buffer_workers2[i][bam_index] + + mate1.flag |= 0x1 + mate2.flag |= 0x1 + + # set one read as the first in pair and the + # other as second + mate1.flag |= 0x40 + mate2.flag |= 0x80 + + # set chrom of mate + mate1.mrnm = mate2.rname + mate2.mrnm = mate1.rname + + # set position of mate + mate1.mpos = mate2.pos + mate2.mpos = mate1.pos + + out_bam_file.write(mate1) + out_bam_file.write(mate2) + + buffer_workers1[i] = None + buffer_workers2[i] = None + queue[i] = None + process[i].join() + process[i].terminate() + process[i] = None + thread_done[i] = True + + # caused by the architecture I try to display this output + # information after +-1e5 of 1e6 reads. + if iter_num % 1e6 < 100000: + elapsed_time = time.time() - start_time + log.info("processing {} lines took {:.2f} " + "secs ({:.1f} lines per " + "second)\n".format(iter_num, + elapsed_time, + iter_num / elapsed_time)) + log.info("{} ({:.2f}%) valid pairs added to matrix" + "\n".format(pair_added, float(100 * pair_added) / iter_num)) + if pDoTestRun and iter_num > pDoTestRunLines: + log.debug( + "\n## *WARNING*. Early exit because of --doTestRun parameter ##\n\n") + all_data_processed = True + thread_done[i] = True + break + elif all_data_processed and queue[i] is None: + thread_done[i] = True + else: + time.sleep(1) + + if all_data_processed: + all_threads_done = True + for thread in thread_done: + if not thread: + all_threads_done = False + if fail_flag: + log.error(fail_message) + exit(1) + else: + log.debug('Parallel stuff done') + if not pDoTestRun: + # the resulting matrix is only filled unevenly with some pairs + # int the upper triangle and others in the lower triangle. To construct + # the definite matrix I add the values from the upper and lower triangles + # and subtract the diagonal to avoid double counting it. + # The resulting matrix is symmetric. + if pOutBam: + out_bam_file.close() + + dia = dia_matrix(([hic_matrix.diagonal()], [0]), + shape=hic_matrix.shape) + hic_matrix = hic_matrix + hic_matrix.T - dia + # extend bins such that they are next to each other + bin_intervals = enlarge_bins(bin_intervals[:], chrom_sizes) + # compute max bin coverage + bin_max = [] + + for cover in pos_coverage: + max_element = 0 + for i in range(cover.begin, cover.end, 1): + if coverage[i] > max_element: + max_element = coverage[i] + if max_element == 0: + bin_max.append(np.nan) + else: + bin_max.append(max_element) + + chr_name_list, start_list, end_list = list(zip(*bin_intervals)) + bin_intervals = list(zip(chr_name_list, start_list, end_list, bin_max)) + hic_ma = hm.hiCMatrix() + hic_ma.setMatrix(hic_matrix, cut_intervals=bin_intervals) + + """ + if pRestrictionCutFile: + # load the matrix to mask those + # bins that most likely didn't + # have a restriction site that was cutted + + # reload the matrix as a Hi-C matrix object + hic_matrix = hm.hiCMatrix(pOutFileName.name) + + hic_matrix.maskBins(get_poor_bins(bin_max)) + hic_matrix.save(pOutFileName.name) + """ + if not pKeepSelfLigation: + msg = " (removed)" + else: + msg = " (not removed)" + + mappable_unique_high_quality_pairs = iter_num - \ + (one_mate_unmapped + one_mate_low_quality + one_mate_not_unique) + + intermediate_qc_log = StringIO() + + if pMinDistance: + intermediate_qc_log.write(""" + File\t{}\t\t + Sequenced reads\t{}\t\t + Min rest. site distance\t{}\t\t + Max library insert size\t{}\t\t + + """.format(pOutFileName.name, iter_num, pMinDistance, pMaxLibraryInsertSize)) + else: + intermediate_qc_log.write(""" + File\t{}\t\t + Sequenced reads\t{}\t\t + Max library insert size\t{}\t\t + + """.format(pOutFileName.name, iter_num, pMaxLibraryInsertSize)) + + intermediate_qc_log.write( + "#\tcount\t(percentage w.r.t. total sequenced reads)\n") + + intermediate_qc_log.write("Pairs mappable, unique and high quality\t{}\t({:.2f})\n". + format(mappable_unique_high_quality_pairs, + 100 * float(mappable_unique_high_quality_pairs) / iter_num)) + + intermediate_qc_log.write("Hi-C contacts\t{}\t({:.2f})\n". + format(pair_added, 100 * float(pair_added) / iter_num)) + + intermediate_qc_log.write("One mate unmapped\t{}\t({:.2f})\n". + format(one_mate_unmapped, 100 * float(one_mate_unmapped) / iter_num)) + + intermediate_qc_log.write("One mate not unique\t{}\t({:.2f})\n". + format(one_mate_not_unique, 100 * float(one_mate_not_unique) / iter_num)) + + intermediate_qc_log.write("Low mapping quality\t{}\t({:.2f})\n". + format(one_mate_low_quality, 100 * float(one_mate_low_quality) / iter_num)) + + intermediate_qc_log.write( + "\n#\tcount\t(percentage w.r.t. mappable, unique and high quality pairs)\n") + + if len(dangling_end) > 0: + log.debug('dangling_sequences {}'.format(dangling_sequences.keys())) + log.debug('dangling_end {}'.format(dangling_end.keys())) + # log.debug('dangling_end {}'.format(res.keys())) + + for key in dangling_end: + # dangling_sequences[pRestrictionSequence[i]]['pat_forw'] + intermediate_qc_log.write("dangling end {} (restriction sequence {})\t{}\t({:.2f})\n". + format(dangling_sequences[key]['pat_forw'], key, dangling_end[key], 100 * float(dangling_end[key]) / mappable_unique_high_quality_pairs)) + else: + intermediate_qc_log.write("dangling end\t{}\t({:.2f})\n". + format(0, 100 * float(0) / mappable_unique_high_quality_pairs)) + if pRestrictionCutFile is not None: + intermediate_qc_log.write("self ligation{}\t{}\t({:.2f})\n". + format(msg, self_ligation, 100 * float(self_ligation) / mappable_unique_high_quality_pairs)) + + intermediate_qc_log.write("One mate not close to rest site\t{}\t({:.2f})\n". + format(mate_not_close_to_rf, 100 * float(mate_not_close_to_rf) / mappable_unique_high_quality_pairs)) + intermediate_qc_log.write("self circle\t{}\t({:.2f})\n". + format(self_circle, 100 * float(self_circle) / mappable_unique_high_quality_pairs)) + + intermediate_qc_log.write("same fragment\t{}\t({:.2f})\n". + format(same_fragment, 100 * float(same_fragment) / mappable_unique_high_quality_pairs)) + + intermediate_qc_log.write("duplicated pairs\t{}\t({:.2f})\n". + format(duplicated_pairs, 100 * float(duplicated_pairs) / mappable_unique_high_quality_pairs)) + + if pair_added > 0: + intermediate_qc_log.write( + "\n#\tcount\t(percentage w.r.t. total valid pairs used)\n") + intermediate_qc_log.write("inter chromosomal\t{}\t({:.2f})\n". + format(inter_chromosomal, 100 * float(inter_chromosomal) / pair_added)) + + intermediate_qc_log.write("Intra short range (< 20kb)\t{}\t({:.2f})\n". + format(short_range, 100 * float(short_range) / pair_added)) + + intermediate_qc_log.write("Intra long range (>= 20kb)\t{}\t({:.2f})\n". + format(long_range, 100 * float(long_range) / pair_added)) + + intermediate_qc_log.write("Read pair type: inward pairs\t{}\t({:.2f})\n". + format(count_inward, 100 * float(count_inward) / pair_added)) + + intermediate_qc_log.write("Read pair type: outward pairs\t{}\t({:.2f})\n". + format(count_outward, 100 * float(count_outward) / pair_added)) + + intermediate_qc_log.write("Read pair type: left pairs\t{}\t({:.2f})\n". + format(count_left, 100 * float(count_left) / pair_added)) + + intermediate_qc_log.write("Read pair type: right pairs\t{}\t({:.2f})\n". + format(count_right, 100 * float(count_right) / pair_added)) + + log_file_name = os.path.join(pQCfolder, "QC.log") + log_file = open(log_file_name, 'w') + log_file.write(intermediate_qc_log.getvalue()) + log_file.close() + log.debug('log_file_name {}'.format(log_file_name)) + log.debug('pQCfolder {}'.format(pQCfolder)) + + QC.main("-l {} -o {}".format(log_file_name, pQCfolder).split()) + + pOutFileName.close() + # removing the empty file. Otherwise the save method + # will say that the file already exists. + unlink(pOutFileName.name) + + hic_metadata = {} + hic_metadata['statistics'] = intermediate_qc_log.getvalue() + hic_metadata['matrix-generated-by'] = np.string_( + 'HiCExplorer-' + __version__) + hic_metadata['matrix-generated-by-url'] = np.string_( + 'https://github.com/deeptools/HiCExplorer') + if pGenomeAssembly: + hic_metadata['genome-assembly'] = np.string_(pGenomeAssembly) + + intermediate_qc_log.close() + if pOutFileName.name.endswith('.mcool') and pBinSize is not None and len(pBinSize) > 2: + + matrixFileHandlerOutput = MatrixFileHandler( + pFileType='cool', pHiCInfo=hic_metadata) + matrixFileHandlerOutput.set_matrix_variables(hic_ma.matrix, + hic_ma.cut_intervals, + hic_ma.nan_bins, + hic_ma.correction_factors, + hic_ma.distance_counts) + matrixFileHandlerOutput.save(pOutFileName.name + '::/resolutions/' + str( + pBinSize[0]), pSymmetric=True, pApplyCorrection=False) + + for resolution in pBinSize[1:]: + hic_matrix_to_merge = deepcopy(hic_ma) + _mergeFactor = int(resolution) // pBinSize[0] + merged_matrix = hicMergeMatrixBins.merge_bins( + hic_matrix_to_merge, _mergeFactor) + matrixFileHandlerOutput = MatrixFileHandler( + pFileType='cool', pAppend=True, pHiCInfo=hic_metadata) + matrixFileHandlerOutput.set_matrix_variables(merged_matrix.matrix, + merged_matrix.cut_intervals, + merged_matrix.nan_bins, + merged_matrix.correction_factors, + merged_matrix.distance_counts) + matrixFileHandlerOutput.save(pOutFileName.name + '::/resolutions/' + str( + resolution), pSymmetric=True, pApplyCorrection=False) + + else: + if not pDoTestRun: + hic_ma.save(pOutFileName.name, pHiCInfo=hic_metadata) diff --git a/hicexplorer/test/general/test_hicBuildMatrixMicroC.py b/hicexplorer/test/general/test_hicBuildMatrixMicroC.py new file mode 100644 index 00000000..c1fdbd0f --- /dev/null +++ b/hicexplorer/test/general/test_hicBuildMatrixMicroC.py @@ -0,0 +1,321 @@ +import warnings +warnings.simplefilter(action="ignore", category=RuntimeWarning) +warnings.simplefilter(action="ignore", category=PendingDeprecationWarning) +from hicexplorer import hicBuildMatrixMicroC, hicInfo +from hicmatrix import HiCMatrix as hm +from tempfile import NamedTemporaryFile, mkdtemp +import shutil +import os +import numpy.testing as nt +import pytest +from hicexplorer.test.test_compute_function import compute + +ROOT = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "test_data/") +sam_R1 = ROOT + "small_test_R1_unsorted.bam" +sam_R2 = ROOT + "small_test_R2_unsorted.bam" +delta = 80000 + + +def are_files_equal(file1, file2, delta=1): + equal = True + if delta: + mismatches = 0 + with open(file1) as textfile1, open(file2) as textfile2: + for x, y in zip(textfile1, textfile2): + if x.startswith('File'): + continue + if x != y: + if delta: + mismatches += 1 + if mismatches > delta: + equal = False + break + else: + equal = False + break + return equal + + +def test_build_matrix(capsys): + outfile = NamedTemporaryFile(suffix='.h5', delete=False) + outfile.close() + outfile_bam = NamedTemporaryFile(suffix='.bam', delete=False) + outfile.close() + qc_folder = mkdtemp(prefix="testQC_") + args = "-s {} {} --outFileName {} -bs 5000 -b {} --QCfolder {} --threads 4".format(sam_R1, sam_R2, + outfile.name, outfile_bam.name, + qc_folder).split() + # hicBuildMatrixMicroC.main(args) + compute(hicBuildMatrixMicroC.main, args, 5) + test = hm.hiCMatrix(ROOT + "small_test_matrix_parallel_one_rc.h5") + new = hm.hiCMatrix(outfile.name) + nt.assert_equal(test.matrix.data, new.matrix.data) + nt.assert_equal(test.cut_intervals, new.cut_intervals) + # print("MATRIX NAME:", outfile.name) + print(set(os.listdir(ROOT + "QC/"))) + assert are_files_equal(ROOT + "QC/QC.log", qc_folder + "/QC.log") + assert set(os.listdir(ROOT + "QC/")) == set(os.listdir(qc_folder)) + + # accept delta of 80 kb, file size is around 4.5 MB + assert abs(os.path.getsize(ROOT + "small_test_matrix_result.bam") - os.path.getsize(outfile_bam.name)) < delta + + os.unlink(outfile.name) + shutil.rmtree(qc_folder) + # os.unlink("/tmp/test.bam") + + +# def test_build_matrix_restriction_enzyme_region(capsys): +# outfile = NamedTemporaryFile(suffix='.h5', delete=False) +# outfile.close() +# outfile_bam = NamedTemporaryFile(suffix='.bam', delete=False) +# outfile.close() +# qc_folder = mkdtemp(prefix="testQC_") +# args = "-s {} {} --outFileName {} -bs 5000 -b {} --QCfolder {} --threads 4 --region {}".format(sam_R1, sam_R2, outfile.name, outfile_bam.name, qc_folder, 'chr3R').split() +# # hicBuildMatrixMicroC.main(args) +# compute(hicBuildMatrixMicroC.main, args, 5) + +# test = hm.hiCMatrix(ROOT + "small_test_matrix_parallel_two_rc_chr3R.h5") +# new = hm.hiCMatrix(outfile.name) + +# # print('test.cut_intervals {}'.format(test.cut_intervals)) +# # print('new.cut_intervals {}'.format(new.cut_intervals)) +# nt.assert_equal(test.matrix.data, new.matrix.data) +# nt.assert_equal(len(test.cut_intervals), len(new.cut_intervals)) + +# # print("MATRIX NAME:", outfile.name) +# print(set(os.listdir(ROOT + "QC_region/"))) +# assert are_files_equal(ROOT + "QC_region/QC.log", qc_folder + "/QC.log") +# assert set(os.listdir(ROOT + "QC_region/")) == set(os.listdir(qc_folder)) + +# # accept delta of 80 kb, file size is around 4.5 MB +# assert abs(os.path.getsize(ROOT + "build_region.bam") - os.path.getsize(outfile_bam.name)) < delta + +# os.unlink(outfile.name) +# shutil.rmtree(qc_folder) + + +# def test_build_matrix_chromosome_sizes(capsys): +# outfile = NamedTemporaryFile(suffix='.h5', delete=False) +# outfile.close() +# outfile_bam = NamedTemporaryFile(suffix='.bam', delete=False) +# outfile.close() +# qc_folder = mkdtemp(prefix="testQC_") +# args = "-s {} {} --outFileName {} -bs 5000 -b {} --QCfolder {} --threads 4 --chromosomeSizes {} \ +# --restrictionSequence GATC --danglingSequence GATC -rs {}".format(sam_R1, sam_R2, +# outfile.name, outfile_bam.name, +# qc_folder, ROOT + 'hicBuildMatrixMicroC/dm3.chrom.sizes', dpnii_file).split() +# # hicBuildMatrixMicroC.main(args) +# compute(hicBuildMatrixMicroC.main, args, 5) + +# test = hm.hiCMatrix(ROOT + "hicBuildMatrixMicroC/chromosome_sizes/small_test_chromosome_size.h5") +# new = hm.hiCMatrix(outfile.name) +# nt.assert_equal(test.matrix.data, new.matrix.data) +# nt.assert_equal(test.cut_intervals, new.cut_intervals) +# # print("MATRIX NAME:", outfile.name) +# print(set(os.listdir(ROOT + "QC/"))) +# assert are_files_equal(ROOT + "QC/QC.log", qc_folder + "/QC.log") +# assert set(os.listdir(ROOT + "QC/")) == set(os.listdir(qc_folder)) + +# # accept delta of 80 kb, file size is around 4.5 MB +# assert abs(os.path.getsize(ROOT + "hicBuildMatrixMicroC/chromosome_sizes/test.bam") - os.path.getsize(outfile_bam.name)) < delta + +# os.unlink(outfile.name) +# shutil.rmtree(qc_folder) +# # os.unlink("/tmp/test.bam") + + +# def test_build_matrix_cooler(): +# outfile = NamedTemporaryFile(suffix='.cool', delete=False) +# outfile.close() +# outfile_bam = NamedTemporaryFile(suffix='.bam', delete=False) +# outfile.close() +# qc_folder = mkdtemp(prefix="testQC_") +# args = "-s {} {} --outFileName {} -bs 5000 -b {} --QCfolder {} --threads 4 \ +# --restrictionSequence GATC --danglingSequence GATC -rs {}".format(sam_R1, sam_R2, +# outfile.name, outfile_bam.name, +# qc_folder, dpnii_file).split() +# # hicBuildMatrixMicroC.main(args) +# compute(hicBuildMatrixMicroC.main, args, 5) + +# test = hm.hiCMatrix(ROOT + "small_test_matrix_parallel.h5") +# new = hm.hiCMatrix(outfile.name) + +# nt.assert_equal(test.matrix.data, new.matrix.data) +# # nt.assert_equal(test.cut_intervals, new.cut_intervals) +# nt.assert_equal(len(new.cut_intervals), len(test.cut_intervals)) +# cut_interval_new_ = [] +# cut_interval_test_ = [] +# for x in new.cut_intervals: +# cut_interval_new_.append(x[:3]) +# for x in test.cut_intervals: +# cut_interval_test_.append(x[:3]) + +# nt.assert_equal(cut_interval_new_, cut_interval_test_) +# # print(set(os.listdir(ROOT + "QC/"))) +# assert are_files_equal(ROOT + "QC/QC.log", qc_folder + "/QC.log") +# assert set(os.listdir(ROOT + "QC/")) == set(os.listdir(qc_folder)) + +# os.unlink(outfile.name) +# shutil.rmtree(qc_folder) + + +# def test_build_matrix_cooler_metadata(): +# outfile = NamedTemporaryFile(suffix='.cool', delete=False) +# outfile.close() +# outfile_bam = NamedTemporaryFile(suffix='.bam', delete=False) +# outfile.close() +# qc_folder = mkdtemp(prefix="testQC_") +# args = "-s {} {} --outFileName {} -bs 5000 -b {} --QCfolder {} --threads 4 --genomeAssembly dm3 \ +# --restrictionSequence GATC --danglingSequence GATC -rs {}".format(sam_R1, sam_R2, +# outfile.name, outfile_bam.name, +# qc_folder, dpnii_file).split() +# # hicBuildMatrixMicroC.main(args) +# compute(hicBuildMatrixMicroC.main, args, 5) + +# test = hm.hiCMatrix(ROOT + "small_test_matrix_parallel.h5") +# new = hm.hiCMatrix(outfile.name) + +# nt.assert_equal(test.matrix.data, new.matrix.data) +# # nt.assert_equal(test.cut_intervals, new.cut_intervals) +# nt.assert_equal(len(new.cut_intervals), len(test.cut_intervals)) +# cut_interval_new_ = [] +# cut_interval_test_ = [] +# for x in new.cut_intervals: +# cut_interval_new_.append(x[:3]) +# for x in test.cut_intervals: +# cut_interval_test_.append(x[:3]) + +# nt.assert_equal(cut_interval_new_, cut_interval_test_) +# # print(set(os.listdir(ROOT + "QC/"))) +# assert are_files_equal(ROOT + "QC/QC.log", qc_folder + "/QC.log") +# assert set(os.listdir(ROOT + "QC/")) == set(os.listdir(qc_folder)) + +# outfile_metadata = NamedTemporaryFile(suffix='.txt', delete=False) +# outfile_metadata.close() +# args = "-m {} -o {}".format(outfile.name, outfile_metadata.name).split() +# hicInfo.main(args) +# assert are_files_equal(ROOT + "hicBuildMatrixMicroC/metadata.txt", outfile_metadata.name, delta=7) + +# os.unlink(outfile.name) +# shutil.rmtree(qc_folder) + + +# def test_build_matrix_cooler_multiple(): +# outfile = NamedTemporaryFile(suffix='.mcool', delete=False) +# outfile.close() +# outfile_bam = NamedTemporaryFile(suffix='.bam', delete=False) +# outfile.close() +# qc_folder = mkdtemp(prefix="testQC_") +# args = "-s {} {} --outFileName {} -bs 5000 10000 20000 -b {} --QCfolder {} --threads 4 \ +# --restrictionSequence GATC --danglingSequence GATC -rs {}".format(sam_R1, sam_R2, +# outfile.name, outfile_bam.name, +# qc_folder, dpnii_file).split() +# # hicBuildMatrixMicroC.main(args) +# compute(hicBuildMatrixMicroC.main, args, 5) + +# test_5000 = hm.hiCMatrix(ROOT + "hicBuildMatrixMicroC/multi_small_test_matrix.mcool::/resolutions/5000") +# test_10000 = hm.hiCMatrix(ROOT + "hicBuildMatrixMicroC/multi_small_test_matrix.mcool::/resolutions/10000") +# test_20000 = hm.hiCMatrix(ROOT + "hicBuildMatrixMicroC/multi_small_test_matrix.mcool::/resolutions/20000") + +# new_5000 = hm.hiCMatrix(outfile.name + '::/resolutions/5000') +# new_10000 = hm.hiCMatrix(outfile.name + '::/resolutions/10000') +# new_20000 = hm.hiCMatrix(outfile.name + '::/resolutions/20000') + +# nt.assert_equal(test_5000.matrix.data, new_5000.matrix.data) +# nt.assert_equal(test_10000.matrix.data, new_10000.matrix.data) +# nt.assert_equal(test_20000.matrix.data, new_20000.matrix.data) + +# # nt.assert_equal(test.cut_intervals, new.cut_intervals) +# nt.assert_equal(len(new_5000.cut_intervals), len(test_5000.cut_intervals)) +# nt.assert_equal(len(new_10000.cut_intervals), len(test_10000.cut_intervals)) +# nt.assert_equal(len(new_20000.cut_intervals), len(test_20000.cut_intervals)) + +# cut_interval_new_ = [] +# cut_interval_test_ = [] +# for x in new_5000.cut_intervals: +# cut_interval_new_.append(x[:3]) +# for x in test_5000.cut_intervals: +# cut_interval_test_.append(x[:3]) + +# nt.assert_equal(cut_interval_new_, cut_interval_test_) + +# cut_interval_new_ = [] +# cut_interval_test_ = [] +# for x in new_10000.cut_intervals: +# cut_interval_new_.append(x[:3]) +# for x in test_10000.cut_intervals: +# cut_interval_test_.append(x[:3]) + +# nt.assert_equal(cut_interval_new_, cut_interval_test_) + +# cut_interval_new_ = [] +# cut_interval_test_ = [] +# for x in new_20000.cut_intervals: +# cut_interval_new_.append(x[:3]) +# for x in test_20000.cut_intervals: +# cut_interval_test_.append(x[:3]) + +# nt.assert_equal(cut_interval_new_, cut_interval_test_) +# # print(set(os.listdir(ROOT + "QC/"))) +# assert are_files_equal(ROOT + "QC/QC.log", qc_folder + "/QC.log") +# assert set(os.listdir(ROOT + "QC/")) == set(os.listdir(qc_folder)) + +# os.unlink(outfile.name) +# shutil.rmtree(qc_folder) + + +# def test_build_matrix_rf(): +# outfile = NamedTemporaryFile(suffix='.h5', delete=False) +# outfile.close() +# qc_folder = mkdtemp(prefix="testQC_") +# args = "-s {} {} -rs {} --outFileName {} --QCfolder {} " \ +# "--restrictionSequence GATC " \ +# "--danglingSequence GATC " \ +# "--minDistance 150 " \ +# "--maxLibraryInsertSize 1500 --threads 4".format(sam_R1, sam_R2, dpnii_file, +# outfile.name, +# qc_folder).split() +# # hicBuildMatrixMicroC.main(args) +# compute(hicBuildMatrixMicroC.main, args, 5) + +# test = hm.hiCMatrix(ROOT + "small_test_rf_matrix.h5") +# new = hm.hiCMatrix(outfile.name) + +# nt.assert_equal(test.matrix.data, new.matrix.data) +# nt.assert_equal(test.cut_intervals, new.cut_intervals) + +# print(set(os.listdir(ROOT + "QC_rc/"))) +# assert are_files_equal(ROOT + "QC_rc/QC.log", qc_folder + "/QC.log") +# assert set(os.listdir(ROOT + "QC_rc/")) == set(os.listdir(qc_folder)) + +# os.unlink(outfile.name) +# shutil.rmtree(qc_folder) + + +# def test_build_matrix_rf_multi(): +# outfile = NamedTemporaryFile(suffix='.h5', delete=False) +# outfile.close() +# qc_folder = mkdtemp(prefix="testQC_") +# args = "-s {} {} -rs {} {} --outFileName {} --QCfolder {} " \ +# "--restrictionSequence GATC AAGCTT " \ +# "--danglingSequence GATC AGCT " \ +# "--minDistance 150 " \ +# "--maxLibraryInsertSize 1500 --threads 4".format(sam_R1, sam_R2, dpnii_file, ROOT + 'hicFindRestSite/hindIII.bed', +# outfile.name, +# qc_folder).split() +# # --danglingSequence GATC AGCT --restrictionSequence GATC AAGCTT +# # hicBuildMatrixMicroC.main(args) +# compute(hicBuildMatrixMicroC.main, args, 5) + +# test = hm.hiCMatrix(ROOT + "small_test_rf_matrix_multiple.h5") +# new = hm.hiCMatrix(outfile.name) + +# nt.assert_equal(test.matrix.data, new.matrix.data) +# nt.assert_equal(test.cut_intervals, new.cut_intervals) + +# print(set(os.listdir(ROOT + "QC_rc_multiple/"))) +# assert are_files_equal(ROOT + "QC_rc_multiple/QC.log", qc_folder + "/QC.log") +# assert set(os.listdir(ROOT + "QC_rc_multiple/")) == set(os.listdir(qc_folder)) + +# os.unlink(outfile.name) +# shutil.rmtree(qc_folder) diff --git a/setup.py b/setup.py index 841292a0..bf591a95 100755 --- a/setup.py +++ b/setup.py @@ -128,7 +128,7 @@ def checkProgramIsInstalled(self, program, args, where_to_download, author='Joachim Wolff, Leily Rabbani, Bjoern Gruening, Vivek Bhardwaj, Fidel Ramírez', author_email='deeptools@googlegroups.com', packages=find_packages(), - scripts=['bin/hicFindRestSite', 'bin/hicAggregateContacts', 'bin/hicBuildMatrix', 'bin/hicCorrectMatrix', + scripts=['bin/hicFindRestSite', 'bin/hicAggregateContacts', 'bin/hicBuildMatrix', 'bin/hicBuildMatrixMicroC', 'bin/hicCorrectMatrix', 'bin/hicCorrelate', 'bin/hicFindTADs', 'bin/hicMergeMatrixBins', 'bin/hicPlotMatrix', 'bin/hicPlotDistVsCounts', 'bin/hicPlotTADs', 'bin/hicSumMatrices', 'bin/hicInfo', 'bin/hicexplorer', 'bin/hicQC', 'bin/hicCompareMatrices', 'bin/hicPCA', 'bin/hicTransform', 'bin/hicPlotViewpoint', From 37e776b862973daddb1d3b057c7a6910fe500d00 Mon Sep 17 00:00:00 2001 From: Joachim Wolff Date: Tue, 26 Nov 2024 19:33:16 +0100 Subject: [PATCH 2/6] Making test cases for hicBuildMatrix and hicBuildMatrixMicroC run. Liniting, and updating to Python 3.11 and 3.12. Increasing the version number to 3.7.6 --- azure-pipelines.yml | 10 +- docs/content/News.rst | 8 + hicexplorer/_version.py | 2 +- hicexplorer/hicBuildMatrix.py | 23 +- hicexplorer/hicBuildMatrixMicroC.py | 16 +- hicexplorer/hicPlotDistVsCounts.py | 10 +- hicexplorer/hicPrepareQCreport.py | 9 +- hicexplorer/lib/buildMatrixMethods.py | 54 ++-- .../test/general/test_hicBuildMatrix.py | 2 +- .../test/general/test_hicBuildMatrixMicroC.py | 269 +----------------- .../test_data/QC_no_restriction_site/QC.log | 24 ++ .../QC_no_restriction_site/QC_table.txt | 2 + .../discarded_table.txt | 2 + .../QC_no_restriction_site/distance.png | Bin 0 -> 76693 bytes .../QC_no_restriction_site/distance_table.txt | 2 + .../QC_no_restriction_site/hicQC.html | 234 +++++++++++++++ .../pairs_discarded.png | Bin 0 -> 122153 bytes .../pairs_sequenced.png | Bin 0 -> 45459 bytes .../read_orientation.png | Bin 0 -> 67947 bytes .../read_orientation_table.txt | 2 + .../unmapable_table.txt | 2 + .../unmappable_and_non_unique.png | Bin 0 -> 84352 bytes .../test/test_data/number_of_tests.txt | 2 +- 23 files changed, 352 insertions(+), 321 deletions(-) create mode 100644 hicexplorer/test/test_data/QC_no_restriction_site/QC.log create mode 100644 hicexplorer/test/test_data/QC_no_restriction_site/QC_table.txt create mode 100644 hicexplorer/test/test_data/QC_no_restriction_site/discarded_table.txt create mode 100644 hicexplorer/test/test_data/QC_no_restriction_site/distance.png create mode 100644 hicexplorer/test/test_data/QC_no_restriction_site/distance_table.txt create mode 100644 hicexplorer/test/test_data/QC_no_restriction_site/hicQC.html create mode 100644 hicexplorer/test/test_data/QC_no_restriction_site/pairs_discarded.png create mode 100644 hicexplorer/test/test_data/QC_no_restriction_site/pairs_sequenced.png create mode 100644 hicexplorer/test/test_data/QC_no_restriction_site/read_orientation.png create mode 100644 hicexplorer/test/test_data/QC_no_restriction_site/read_orientation_table.txt create mode 100644 hicexplorer/test/test_data/QC_no_restriction_site/unmapable_table.txt create mode 100644 hicexplorer/test/test_data/QC_no_restriction_site/unmappable_and_non_unique.png diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fc09c773..e8560053 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,7 +15,10 @@ jobs: python.version: '3.9' Python310: python.version: '3.10' - + Python311: + python.version: '3.11' + Python312: + python.version: '3.12' steps: - bash: | @@ -66,6 +69,11 @@ jobs: python.version: '3.9' Python310: python.version: '3.10' + Python311: + python.version: '3.11' + Python312: + python.version: '3.12' + steps: - bash: | diff --git a/docs/content/News.rst b/docs/content/News.rst index 03b4c1e6..861222b3 100644 --- a/docs/content/News.rst +++ b/docs/content/News.rst @@ -1,6 +1,14 @@ News and Developments ===================== +Release 3.7.6 +------------- +**27 November 2024** + +- Add a new hicBuildMatrixMicroC script to build matrices from Micro-C data. It is the same as hicBuildMatrix but without the enforcement of the restriction cut site file, restriction sequence and dangling end since this is not necessary for Micro-C data. +- Update to include support for Python 3.11 and 3.12 + + Release 3.7.5 ------------- **June 2024** diff --git a/hicexplorer/_version.py b/hicexplorer/_version.py index bbd9c98c..043cd286 100644 --- a/hicexplorer/_version.py +++ b/hicexplorer/_version.py @@ -2,4 +2,4 @@ # This file is originally generated from Git information by running 'setup.py # version'. Distribution tarballs contain a pre-generated copy of this file. -__version__ = '3.7.5' +__version__ = '3.7.6' diff --git a/hicexplorer/hicBuildMatrix.py b/hicexplorer/hicBuildMatrix.py index 2188fcfb..7ded21d2 100644 --- a/hicexplorer/hicBuildMatrix.py +++ b/hicexplorer/hicBuildMatrix.py @@ -261,21 +261,10 @@ def main(args=None): """ args = parse_arguments().parse_args(args) - + createMatrix(pOutFileName=args.outFileName, pMaxDistance=args.maxDistance, pMaxLibraryInsertSize=args.maxLibraryInsertSize, pQCfolder=args.QCfolder, - pThreads=args.threads, pDanglingSequence=args.danglingSequence, pRestrictionSequence=args.restrictionSequence, pSamFiles=args.samFiles, - pDoTestRun=args.doTestRun, pOutBam=args.outBam, pChromosomeSizes=args.chromosomeSizes, pRestrictionCutFile=args.restrictionCutFile, - pRegion=args.region, pBinSize=args.binSize, pInputBufferSize=args.inputBufferSize, pMinDistance=args.minDistance, - pDoTestRunLines=args.doTestRunLines, pSkipDuplicationCheck=args.skipDuplicationCheck, pMinMappingQuality=args.minMappingQuality, - pKeepSelfCircles=args.keepSelfCircles, pKeepSelfLigation=args.keepSelfLigation, pGenomeAssembly=args.genomeAssembly) - - -class Tester(object): - def __init__(self): - hic_test_data_dir = os.environ.get('HIC_TEST_DATA_DIR', False) - if hic_test_data_dir: - self.root = hic_test_data_dir - else: - self.root = os.path.dirname( - os.path.abspath(__file__)) + "/test/test_data/" - self.bam_file_1 = os.path.join(self.root, "hic.bam") + pThreads=args.threads, pDanglingSequence=args.danglingSequence, pRestrictionSequence=args.restrictionSequence, pSamFiles=args.samFiles, + pDoTestRun=args.doTestRun, pOutBam=args.outBam, pChromosomeSizes=args.chromosomeSizes, pRestrictionCutFile=args.restrictionCutFile, + pRegion=args.region, pBinSize=args.binSize, pInputBufferSize=args.inputBufferSize, pMinDistance=args.minDistance, + pDoTestRunLines=args.doTestRunLines, pSkipDuplicationCheck=args.skipDuplicationCheck, pMinMappingQuality=args.minMappingQuality, + pKeepSelfCircles=args.keepSelfCircles, pKeepSelfLigation=args.keepSelfLigation, pGenomeAssembly=args.genomeAssembly) diff --git a/hicexplorer/hicBuildMatrixMicroC.py b/hicexplorer/hicBuildMatrixMicroC.py index 1e8038aa..930b339e 100644 --- a/hicexplorer/hicBuildMatrixMicroC.py +++ b/hicexplorer/hicBuildMatrixMicroC.py @@ -51,7 +51,6 @@ def parse_arguments(args=None): metavar='FOLDER', required=True) - parserOpt = parser.add_argument_group('Optional arguments') parserOpt.add_argument('--outBam', '-b', @@ -77,8 +76,6 @@ def parse_arguments(args=None): nargs='+', required=True) - - parserOpt.add_argument('--maxLibraryInsertSize', help='The maximum library insert size defines different cut offs based on the maximum expected ' 'library size. *This is not the average fragment size* but the higher end of the ' @@ -104,7 +101,6 @@ def parse_arguments(args=None): type=genomicRegion ) - parserOpt.add_argument('--keepSelfCircles', help='If set, outward facing reads without any restriction fragment (self circles) are kept. ' 'They will be counted and shown in the QC plots.', @@ -210,13 +206,13 @@ def main(args=None): """ args = parse_arguments().parse_args(args) - + createMatrix(pOutFileName=args.outFileName, pMaxDistance=None, pMaxLibraryInsertSize=args.maxLibraryInsertSize, pQCfolder=args.QCfolder, - pThreads=args.threads, pDanglingSequence=None, pRestrictionSequence=None, pSamFiles=args.samFiles, - pDoTestRun=args.doTestRun, pOutBam=args.outBam, pChromosomeSizes=args.chromosomeSizes, pRestrictionCutFile=None, - pRegion=args.region, pBinSize=args.binSize, pInputBufferSize=args.inputBufferSize, pMinDistance=None, - pDoTestRunLines=args.doTestRunLines, pSkipDuplicationCheck=args.skipDuplicationCheck, pMinMappingQuality=args.minMappingQuality, - pKeepSelfCircles=args.keepSelfCircles, pKeepSelfLigation=None, pGenomeAssembly=args.genomeAssembly) + pThreads=args.threads, pDanglingSequence=None, pRestrictionSequence=None, pSamFiles=args.samFiles, + pDoTestRun=args.doTestRun, pOutBam=args.outBam, pChromosomeSizes=args.chromosomeSizes, pRestrictionCutFile=None, + pRegion=args.region, pBinSize=args.binSize, pInputBufferSize=args.inputBufferSize, pMinDistance=None, + pDoTestRunLines=args.doTestRunLines, pSkipDuplicationCheck=args.skipDuplicationCheck, pMinMappingQuality=args.minMappingQuality, + pKeepSelfCircles=args.keepSelfCircles, pKeepSelfLigation=None, pGenomeAssembly=args.genomeAssembly) class Tester(object): diff --git a/hicexplorer/hicPlotDistVsCounts.py b/hicexplorer/hicPlotDistVsCounts.py index b147bd93..4a441641 100644 --- a/hicexplorer/hicPlotDistVsCounts.py +++ b/hicexplorer/hicPlotDistVsCounts.py @@ -156,20 +156,20 @@ def compute_distance_mean(hicmat, maxdepth=None, perchr=False, custom_cut_interv >>> hic.matrix = csr_matrix(matrix) >>> hic.setMatrix(hic.matrix, cut_intervals) >>> compute_distance_mean(hic) - {'all': OrderedDict([(0, (3.0, 7)), (10, (6.0, 5)), (20, (10.0, 3)), (30, (3.0, 1))])} + {'all': OrderedDict({0: (3.0, 7), 10: (6.0, 5), 20: (10.0, 3), 30: (3.0, 1)})} >>> compute_distance_mean(hic, perchr=True) - {'a': OrderedDict([(0, (1.25, 4)), (10, (10.0, 3)), (20, (5.0, 2)), (30, (3.0, 1))]), 'b': OrderedDict([(0, (5.333333333333333, 3)), (10, (0.0, 2)), (20, (20.0, 1))])} + {'a': OrderedDict({0: (1.25, 4), 10: (10.0, 3), 20: (5.0, 2), 30: (3.0, 1)}), 'b': OrderedDict({0: (5.333333333333333, 3), 10: (0.0, 2), 20: (20.0, 1)})} >>> custom_cut = [('tad1', 0, 10, 1), ('tad1', 10, 20, 1), ('tad2', 0, 10, 1), ... ('tad2', 10, 20, 1), ('tad3', 0, 10, 1), ('tad3', 10, 20, 1), ('tad3', 20, 30, 1)] >>> compute_distance_mean(hic, custom_cut_intervals=custom_cut) - {'all': OrderedDict([(0, (3.0, 7)), (10, (3.75, 4)), (20, (20.0, 1))])} + {'all': OrderedDict({0: (3.0, 7), 10: (3.75, 4), 20: (20.0, 1)})} >>> compute_distance_mean(hic, perchr=True, custom_cut_intervals=custom_cut) - {'a': OrderedDict([(0, (1.25, 4)), (10, (7.5, 2))]), 'b': OrderedDict([(0, (5.333333333333333, 3)), (10, (0.0, 2)), (20, (20.0, 1))])} + {'a': OrderedDict({0: (1.25, 4), 10: (7.5, 2)}), 'b': OrderedDict({0: (5.333333333333333, 3), 10: (0.0, 2), 20: (20.0, 1)})} >>> custom_cut = [('_ignore_0', 0, 10, 1), ('0', 0, 10, 1), ... ('0', 10, 20, 1), ('_ignore_3', 0, 10, 1), ... ('1', 0, 10, 1), ('1', 10, 20, 1), ('1', 20, 30, 1)] >>> compute_distance_mean(hic, custom_cut_intervals=custom_cut) - {'all': OrderedDict([(0, (4.0, 5)), (10, (5.0, 3)), (20, (20.0, 1))])} + {'all': OrderedDict({0: (4.0, 5), 10: (5.0, 3), 20: (20.0, 1)})} # >>> compute_distance_mean(hic, custom_cut_intervals=custom_cut, perchr=True) # {'a': OrderedDict([(0, (2.0, 2)), (10, (15.0, 1))]), 'b': OrderedDict([(0, (5.333333333333333, 3)), (10, (0.0, 2)), (20, (20.0, 1))])} diff --git a/hicexplorer/hicPrepareQCreport.py b/hicexplorer/hicPrepareQCreport.py index 2afc267e..d59d390c 100644 --- a/hicexplorer/hicPrepareQCreport.py +++ b/hicexplorer/hicPrepareQCreport.py @@ -72,7 +72,12 @@ def save_html(filename, unmap_table, discard_table, distance_table, orientation_ html_content = html_content.replace("%%TABLE_ORIENTATION%%", orientation_table.style .format(lambda x: '{:,}'.format(x) if x > 1 else '{:.2%}'.format(x)).to_html(classes='df')) - all_table = all_table.drop(['Min rest. site distance', 'Max library insert size'], axis=1) + if 'Min rest. site distance' in all_table.columns: + all_table = all_table.drop(['Min rest. site distance'], axis=1) + + if 'Max library insert size' in all_table.columns: + all_table = all_table.drop(['Max library insert size'], axis=1) + # all_table = all_table.drop(['Min rest. site distance', 'Max library insert size'], axis=1) html_content = html_content.replace("%%TABLE%%", all_table.style.to_html(classes='df')) with open(filename, 'w') as fh: @@ -268,6 +273,8 @@ def main(args=None): in_log_part = False log.debug('Processing {}\n'.format(fh.name)) for line in fh.readlines(): + log.debug('line {}'.format(line)) + line = line.strip() if line.startswith("File"): in_log_part = True if in_log_part is True: diff --git a/hicexplorer/lib/buildMatrixMethods.py b/hicexplorer/lib/buildMatrixMethods.py index 5f7e7628..fefe2c4e 100644 --- a/hicexplorer/lib/buildMatrixMethods.py +++ b/hicexplorer/lib/buildMatrixMethods.py @@ -7,6 +7,7 @@ import time from os import unlink import os +from pathlib import Path from io import StringIO import traceback import warnings @@ -37,6 +38,7 @@ import logging log = logging.getLogger(__name__) + class C_Interval(Structure): """Struct to map a Interval form intervaltree as a multiprocessing.sharedctype""" _fields_ = [("begin", c_uint), @@ -85,6 +87,7 @@ def is_duplicated(self, chrom1, start1, chrom2, start2): self.pos_matrix.add(id_string) return False + def intervalListToIntervalTree(interval_list): r""" given a dictionary containing tuples of chrom, start, end, @@ -554,7 +557,6 @@ def readBamFiles(pFileOneIterator, pFileTwoIterator, pNumberOfItemsPerBuffer, pS return buffer_mate1, buffer_mate2, False, duplicated_pairs, one_mate_unmapped, one_mate_not_unique, one_mate_low_quality, iter_num - len(buffer_mate1) - def process_data(pMateBuffer1, pMateBuffer2, pMinMappingQuality, pKeepSelfCircles, pRestrictionSequence, pKeepSelfLigation, pMatrixSize, pRfPositions, pRefId2name, @@ -866,13 +868,14 @@ def process_data(pMateBuffer1, pMateBuffer2, pMinMappingQuality, return return + def createMatrix(pOutFileName, pMaxDistance, pMaxLibraryInsertSize, pQCfolder, pThreads, pDanglingSequence, pRestrictionSequence, pSamFiles, pDoTestRun, pOutBam, pChromosomeSizes, pRestrictionCutFile, pRegion, pBinSize, pInputBufferSize, - pDoTestRunLines, pSkipDuplicationCheck, pMinMappingQuality, + pDoTestRunLines, pSkipDuplicationCheck, pMinMappingQuality, pKeepSelfCircles, pKeepSelfLigation, pMinDistance, pGenomeAssembly): - # pOutFileName.name = pOutFileName.name.strip() + # pOutFileName.name = pOutFileName.name.strip() # log.debug('pOutFileName.name: {}'.format(pOutFileName.name.endswith('.h5'))) if not pOutFileName.name.endswith('.h5') and not pOutFileName.name.endswith('.cool'): if '.mcool' not in pOutFileName.name: @@ -1262,19 +1265,19 @@ def createMatrix(pOutFileName, pMaxDistance, pMaxLibraryInsertSize, pQCfolder, if pMinDistance: intermediate_qc_log.write(""" - File\t{}\t\t - Sequenced reads\t{}\t\t - Min rest. site distance\t{}\t\t - Max library insert size\t{}\t\t +File\t{}\t\t +Sequenced reads\t{}\t\t +Min rest. site distance\t{}\t\t +Max library insert size\t{}\t\t - """.format(pOutFileName.name, iter_num, pMinDistance, pMaxLibraryInsertSize)) +""".format(pOutFileName.name, iter_num, pMinDistance, pMaxLibraryInsertSize)) else: intermediate_qc_log.write(""" - File\t{}\t\t - Sequenced reads\t{}\t\t - Max library insert size\t{}\t\t +File\t{}\t\t +Sequenced reads\t{}\t\t +Max library insert size\t{}\t\t - """.format(pOutFileName.name, iter_num, pMaxLibraryInsertSize)) +""".format(pOutFileName.name, iter_num, pMaxLibraryInsertSize)) intermediate_qc_log.write( "#\tcount\t(percentage w.r.t. total sequenced reads)\n") @@ -1307,20 +1310,20 @@ def createMatrix(pOutFileName, pMaxDistance, pMaxLibraryInsertSize, pQCfolder, # dangling_sequences[pRestrictionSequence[i]]['pat_forw'] intermediate_qc_log.write("dangling end {} (restriction sequence {})\t{}\t({:.2f})\n". format(dangling_sequences[key]['pat_forw'], key, dangling_end[key], 100 * float(dangling_end[key]) / mappable_unique_high_quality_pairs)) - else: - intermediate_qc_log.write("dangling end\t{}\t({:.2f})\n". - format(0, 100 * float(0) / mappable_unique_high_quality_pairs)) + # else: + # intermediate_qc_log.write("dangling end\t{}\t({:.2f})\n". + # format(0, 100 * float(0) / mappable_unique_high_quality_pairs)) if pRestrictionCutFile is not None: intermediate_qc_log.write("self ligation{}\t{}\t({:.2f})\n". - format(msg, self_ligation, 100 * float(self_ligation) / mappable_unique_high_quality_pairs)) + format(msg, self_ligation, 100 * float(self_ligation) / mappable_unique_high_quality_pairs)) intermediate_qc_log.write("One mate not close to rest site\t{}\t({:.2f})\n". - format(mate_not_close_to_rf, 100 * float(mate_not_close_to_rf) / mappable_unique_high_quality_pairs)) - intermediate_qc_log.write("self circle\t{}\t({:.2f})\n". - format(self_circle, 100 * float(self_circle) / mappable_unique_high_quality_pairs)) - + format(mate_not_close_to_rf, 100 * float(mate_not_close_to_rf) / mappable_unique_high_quality_pairs)) intermediate_qc_log.write("same fragment\t{}\t({:.2f})\n". format(same_fragment, 100 * float(same_fragment) / mappable_unique_high_quality_pairs)) + if pRestrictionCutFile is not None: + intermediate_qc_log.write("self circle\t{}\t({:.2f})\n". + format(self_circle, 100 * float(self_circle) / mappable_unique_high_quality_pairs)) intermediate_qc_log.write("duplicated pairs\t{}\t({:.2f})\n". format(duplicated_pairs, 100 * float(duplicated_pairs) / mappable_unique_high_quality_pairs)) @@ -1403,3 +1406,14 @@ def createMatrix(pOutFileName, pMaxDistance, pMaxLibraryInsertSize, pQCfolder, else: if not pDoTestRun: hic_ma.save(pOutFileName.name, pHiCInfo=hic_metadata) + + +class Tester(object): + def __init__(self): + hic_test_data_dir = os.environ.get('HIC_TEST_DATA_DIR', False) + if hic_test_data_dir: + self.root = hic_test_data_dir + else: + self.root = os.path.dirname(os.path.dirname( + os.path.abspath(__file__))) + "/test/test_data/" + self.bam_file_1 = os.path.join(self.root, "hic.bam") diff --git a/hicexplorer/test/general/test_hicBuildMatrix.py b/hicexplorer/test/general/test_hicBuildMatrix.py index cd869360..e7bf666b 100644 --- a/hicexplorer/test/general/test_hicBuildMatrix.py +++ b/hicexplorer/test/general/test_hicBuildMatrix.py @@ -55,7 +55,7 @@ def test_build_matrix(capsys): nt.assert_equal(test.cut_intervals, new.cut_intervals) # print("MATRIX NAME:", outfile.name) print(set(os.listdir(ROOT + "QC/"))) - assert are_files_equal(ROOT + "QC/QC.log", qc_folder + "/QC.log") + assert are_files_equal(ROOT + "QC/QC.log", qc_folder + "/QC.log", delta=2) assert set(os.listdir(ROOT + "QC/")) == set(os.listdir(qc_folder)) # accept delta of 80 kb, file size is around 4.5 MB diff --git a/hicexplorer/test/general/test_hicBuildMatrixMicroC.py b/hicexplorer/test/general/test_hicBuildMatrixMicroC.py index c1fdbd0f..0213375e 100644 --- a/hicexplorer/test/general/test_hicBuildMatrixMicroC.py +++ b/hicexplorer/test/general/test_hicBuildMatrixMicroC.py @@ -43,279 +43,20 @@ def test_build_matrix(capsys): outfile.close() qc_folder = mkdtemp(prefix="testQC_") args = "-s {} {} --outFileName {} -bs 5000 -b {} --QCfolder {} --threads 4".format(sam_R1, sam_R2, - outfile.name, outfile_bam.name, - qc_folder).split() - # hicBuildMatrixMicroC.main(args) + outfile.name, outfile_bam.name, + qc_folder).split() compute(hicBuildMatrixMicroC.main, args, 5) test = hm.hiCMatrix(ROOT + "small_test_matrix_parallel_one_rc.h5") new = hm.hiCMatrix(outfile.name) nt.assert_equal(test.matrix.data, new.matrix.data) nt.assert_equal(test.cut_intervals, new.cut_intervals) # print("MATRIX NAME:", outfile.name) - print(set(os.listdir(ROOT + "QC/"))) - assert are_files_equal(ROOT + "QC/QC.log", qc_folder + "/QC.log") - assert set(os.listdir(ROOT + "QC/")) == set(os.listdir(qc_folder)) + print(set(os.listdir(ROOT + "QC_no_restriction_site/"))) + assert are_files_equal(ROOT + "QC_no_restriction_site/QC.log", qc_folder + "/QC.log") + assert set(os.listdir(ROOT + "QC_no_restriction_site/")) == set(os.listdir(qc_folder)) # accept delta of 80 kb, file size is around 4.5 MB assert abs(os.path.getsize(ROOT + "small_test_matrix_result.bam") - os.path.getsize(outfile_bam.name)) < delta os.unlink(outfile.name) shutil.rmtree(qc_folder) - # os.unlink("/tmp/test.bam") - - -# def test_build_matrix_restriction_enzyme_region(capsys): -# outfile = NamedTemporaryFile(suffix='.h5', delete=False) -# outfile.close() -# outfile_bam = NamedTemporaryFile(suffix='.bam', delete=False) -# outfile.close() -# qc_folder = mkdtemp(prefix="testQC_") -# args = "-s {} {} --outFileName {} -bs 5000 -b {} --QCfolder {} --threads 4 --region {}".format(sam_R1, sam_R2, outfile.name, outfile_bam.name, qc_folder, 'chr3R').split() -# # hicBuildMatrixMicroC.main(args) -# compute(hicBuildMatrixMicroC.main, args, 5) - -# test = hm.hiCMatrix(ROOT + "small_test_matrix_parallel_two_rc_chr3R.h5") -# new = hm.hiCMatrix(outfile.name) - -# # print('test.cut_intervals {}'.format(test.cut_intervals)) -# # print('new.cut_intervals {}'.format(new.cut_intervals)) -# nt.assert_equal(test.matrix.data, new.matrix.data) -# nt.assert_equal(len(test.cut_intervals), len(new.cut_intervals)) - -# # print("MATRIX NAME:", outfile.name) -# print(set(os.listdir(ROOT + "QC_region/"))) -# assert are_files_equal(ROOT + "QC_region/QC.log", qc_folder + "/QC.log") -# assert set(os.listdir(ROOT + "QC_region/")) == set(os.listdir(qc_folder)) - -# # accept delta of 80 kb, file size is around 4.5 MB -# assert abs(os.path.getsize(ROOT + "build_region.bam") - os.path.getsize(outfile_bam.name)) < delta - -# os.unlink(outfile.name) -# shutil.rmtree(qc_folder) - - -# def test_build_matrix_chromosome_sizes(capsys): -# outfile = NamedTemporaryFile(suffix='.h5', delete=False) -# outfile.close() -# outfile_bam = NamedTemporaryFile(suffix='.bam', delete=False) -# outfile.close() -# qc_folder = mkdtemp(prefix="testQC_") -# args = "-s {} {} --outFileName {} -bs 5000 -b {} --QCfolder {} --threads 4 --chromosomeSizes {} \ -# --restrictionSequence GATC --danglingSequence GATC -rs {}".format(sam_R1, sam_R2, -# outfile.name, outfile_bam.name, -# qc_folder, ROOT + 'hicBuildMatrixMicroC/dm3.chrom.sizes', dpnii_file).split() -# # hicBuildMatrixMicroC.main(args) -# compute(hicBuildMatrixMicroC.main, args, 5) - -# test = hm.hiCMatrix(ROOT + "hicBuildMatrixMicroC/chromosome_sizes/small_test_chromosome_size.h5") -# new = hm.hiCMatrix(outfile.name) -# nt.assert_equal(test.matrix.data, new.matrix.data) -# nt.assert_equal(test.cut_intervals, new.cut_intervals) -# # print("MATRIX NAME:", outfile.name) -# print(set(os.listdir(ROOT + "QC/"))) -# assert are_files_equal(ROOT + "QC/QC.log", qc_folder + "/QC.log") -# assert set(os.listdir(ROOT + "QC/")) == set(os.listdir(qc_folder)) - -# # accept delta of 80 kb, file size is around 4.5 MB -# assert abs(os.path.getsize(ROOT + "hicBuildMatrixMicroC/chromosome_sizes/test.bam") - os.path.getsize(outfile_bam.name)) < delta - -# os.unlink(outfile.name) -# shutil.rmtree(qc_folder) -# # os.unlink("/tmp/test.bam") - - -# def test_build_matrix_cooler(): -# outfile = NamedTemporaryFile(suffix='.cool', delete=False) -# outfile.close() -# outfile_bam = NamedTemporaryFile(suffix='.bam', delete=False) -# outfile.close() -# qc_folder = mkdtemp(prefix="testQC_") -# args = "-s {} {} --outFileName {} -bs 5000 -b {} --QCfolder {} --threads 4 \ -# --restrictionSequence GATC --danglingSequence GATC -rs {}".format(sam_R1, sam_R2, -# outfile.name, outfile_bam.name, -# qc_folder, dpnii_file).split() -# # hicBuildMatrixMicroC.main(args) -# compute(hicBuildMatrixMicroC.main, args, 5) - -# test = hm.hiCMatrix(ROOT + "small_test_matrix_parallel.h5") -# new = hm.hiCMatrix(outfile.name) - -# nt.assert_equal(test.matrix.data, new.matrix.data) -# # nt.assert_equal(test.cut_intervals, new.cut_intervals) -# nt.assert_equal(len(new.cut_intervals), len(test.cut_intervals)) -# cut_interval_new_ = [] -# cut_interval_test_ = [] -# for x in new.cut_intervals: -# cut_interval_new_.append(x[:3]) -# for x in test.cut_intervals: -# cut_interval_test_.append(x[:3]) - -# nt.assert_equal(cut_interval_new_, cut_interval_test_) -# # print(set(os.listdir(ROOT + "QC/"))) -# assert are_files_equal(ROOT + "QC/QC.log", qc_folder + "/QC.log") -# assert set(os.listdir(ROOT + "QC/")) == set(os.listdir(qc_folder)) - -# os.unlink(outfile.name) -# shutil.rmtree(qc_folder) - - -# def test_build_matrix_cooler_metadata(): -# outfile = NamedTemporaryFile(suffix='.cool', delete=False) -# outfile.close() -# outfile_bam = NamedTemporaryFile(suffix='.bam', delete=False) -# outfile.close() -# qc_folder = mkdtemp(prefix="testQC_") -# args = "-s {} {} --outFileName {} -bs 5000 -b {} --QCfolder {} --threads 4 --genomeAssembly dm3 \ -# --restrictionSequence GATC --danglingSequence GATC -rs {}".format(sam_R1, sam_R2, -# outfile.name, outfile_bam.name, -# qc_folder, dpnii_file).split() -# # hicBuildMatrixMicroC.main(args) -# compute(hicBuildMatrixMicroC.main, args, 5) - -# test = hm.hiCMatrix(ROOT + "small_test_matrix_parallel.h5") -# new = hm.hiCMatrix(outfile.name) - -# nt.assert_equal(test.matrix.data, new.matrix.data) -# # nt.assert_equal(test.cut_intervals, new.cut_intervals) -# nt.assert_equal(len(new.cut_intervals), len(test.cut_intervals)) -# cut_interval_new_ = [] -# cut_interval_test_ = [] -# for x in new.cut_intervals: -# cut_interval_new_.append(x[:3]) -# for x in test.cut_intervals: -# cut_interval_test_.append(x[:3]) - -# nt.assert_equal(cut_interval_new_, cut_interval_test_) -# # print(set(os.listdir(ROOT + "QC/"))) -# assert are_files_equal(ROOT + "QC/QC.log", qc_folder + "/QC.log") -# assert set(os.listdir(ROOT + "QC/")) == set(os.listdir(qc_folder)) - -# outfile_metadata = NamedTemporaryFile(suffix='.txt', delete=False) -# outfile_metadata.close() -# args = "-m {} -o {}".format(outfile.name, outfile_metadata.name).split() -# hicInfo.main(args) -# assert are_files_equal(ROOT + "hicBuildMatrixMicroC/metadata.txt", outfile_metadata.name, delta=7) - -# os.unlink(outfile.name) -# shutil.rmtree(qc_folder) - - -# def test_build_matrix_cooler_multiple(): -# outfile = NamedTemporaryFile(suffix='.mcool', delete=False) -# outfile.close() -# outfile_bam = NamedTemporaryFile(suffix='.bam', delete=False) -# outfile.close() -# qc_folder = mkdtemp(prefix="testQC_") -# args = "-s {} {} --outFileName {} -bs 5000 10000 20000 -b {} --QCfolder {} --threads 4 \ -# --restrictionSequence GATC --danglingSequence GATC -rs {}".format(sam_R1, sam_R2, -# outfile.name, outfile_bam.name, -# qc_folder, dpnii_file).split() -# # hicBuildMatrixMicroC.main(args) -# compute(hicBuildMatrixMicroC.main, args, 5) - -# test_5000 = hm.hiCMatrix(ROOT + "hicBuildMatrixMicroC/multi_small_test_matrix.mcool::/resolutions/5000") -# test_10000 = hm.hiCMatrix(ROOT + "hicBuildMatrixMicroC/multi_small_test_matrix.mcool::/resolutions/10000") -# test_20000 = hm.hiCMatrix(ROOT + "hicBuildMatrixMicroC/multi_small_test_matrix.mcool::/resolutions/20000") - -# new_5000 = hm.hiCMatrix(outfile.name + '::/resolutions/5000') -# new_10000 = hm.hiCMatrix(outfile.name + '::/resolutions/10000') -# new_20000 = hm.hiCMatrix(outfile.name + '::/resolutions/20000') - -# nt.assert_equal(test_5000.matrix.data, new_5000.matrix.data) -# nt.assert_equal(test_10000.matrix.data, new_10000.matrix.data) -# nt.assert_equal(test_20000.matrix.data, new_20000.matrix.data) - -# # nt.assert_equal(test.cut_intervals, new.cut_intervals) -# nt.assert_equal(len(new_5000.cut_intervals), len(test_5000.cut_intervals)) -# nt.assert_equal(len(new_10000.cut_intervals), len(test_10000.cut_intervals)) -# nt.assert_equal(len(new_20000.cut_intervals), len(test_20000.cut_intervals)) - -# cut_interval_new_ = [] -# cut_interval_test_ = [] -# for x in new_5000.cut_intervals: -# cut_interval_new_.append(x[:3]) -# for x in test_5000.cut_intervals: -# cut_interval_test_.append(x[:3]) - -# nt.assert_equal(cut_interval_new_, cut_interval_test_) - -# cut_interval_new_ = [] -# cut_interval_test_ = [] -# for x in new_10000.cut_intervals: -# cut_interval_new_.append(x[:3]) -# for x in test_10000.cut_intervals: -# cut_interval_test_.append(x[:3]) - -# nt.assert_equal(cut_interval_new_, cut_interval_test_) - -# cut_interval_new_ = [] -# cut_interval_test_ = [] -# for x in new_20000.cut_intervals: -# cut_interval_new_.append(x[:3]) -# for x in test_20000.cut_intervals: -# cut_interval_test_.append(x[:3]) - -# nt.assert_equal(cut_interval_new_, cut_interval_test_) -# # print(set(os.listdir(ROOT + "QC/"))) -# assert are_files_equal(ROOT + "QC/QC.log", qc_folder + "/QC.log") -# assert set(os.listdir(ROOT + "QC/")) == set(os.listdir(qc_folder)) - -# os.unlink(outfile.name) -# shutil.rmtree(qc_folder) - - -# def test_build_matrix_rf(): -# outfile = NamedTemporaryFile(suffix='.h5', delete=False) -# outfile.close() -# qc_folder = mkdtemp(prefix="testQC_") -# args = "-s {} {} -rs {} --outFileName {} --QCfolder {} " \ -# "--restrictionSequence GATC " \ -# "--danglingSequence GATC " \ -# "--minDistance 150 " \ -# "--maxLibraryInsertSize 1500 --threads 4".format(sam_R1, sam_R2, dpnii_file, -# outfile.name, -# qc_folder).split() -# # hicBuildMatrixMicroC.main(args) -# compute(hicBuildMatrixMicroC.main, args, 5) - -# test = hm.hiCMatrix(ROOT + "small_test_rf_matrix.h5") -# new = hm.hiCMatrix(outfile.name) - -# nt.assert_equal(test.matrix.data, new.matrix.data) -# nt.assert_equal(test.cut_intervals, new.cut_intervals) - -# print(set(os.listdir(ROOT + "QC_rc/"))) -# assert are_files_equal(ROOT + "QC_rc/QC.log", qc_folder + "/QC.log") -# assert set(os.listdir(ROOT + "QC_rc/")) == set(os.listdir(qc_folder)) - -# os.unlink(outfile.name) -# shutil.rmtree(qc_folder) - - -# def test_build_matrix_rf_multi(): -# outfile = NamedTemporaryFile(suffix='.h5', delete=False) -# outfile.close() -# qc_folder = mkdtemp(prefix="testQC_") -# args = "-s {} {} -rs {} {} --outFileName {} --QCfolder {} " \ -# "--restrictionSequence GATC AAGCTT " \ -# "--danglingSequence GATC AGCT " \ -# "--minDistance 150 " \ -# "--maxLibraryInsertSize 1500 --threads 4".format(sam_R1, sam_R2, dpnii_file, ROOT + 'hicFindRestSite/hindIII.bed', -# outfile.name, -# qc_folder).split() -# # --danglingSequence GATC AGCT --restrictionSequence GATC AAGCTT -# # hicBuildMatrixMicroC.main(args) -# compute(hicBuildMatrixMicroC.main, args, 5) - -# test = hm.hiCMatrix(ROOT + "small_test_rf_matrix_multiple.h5") -# new = hm.hiCMatrix(outfile.name) - -# nt.assert_equal(test.matrix.data, new.matrix.data) -# nt.assert_equal(test.cut_intervals, new.cut_intervals) - -# print(set(os.listdir(ROOT + "QC_rc_multiple/"))) -# assert are_files_equal(ROOT + "QC_rc_multiple/QC.log", qc_folder + "/QC.log") -# assert set(os.listdir(ROOT + "QC_rc_multiple/")) == set(os.listdir(qc_folder)) - -# os.unlink(outfile.name) -# shutil.rmtree(qc_folder) diff --git a/hicexplorer/test/test_data/QC_no_restriction_site/QC.log b/hicexplorer/test/test_data/QC_no_restriction_site/QC.log new file mode 100644 index 00000000..3d5310de --- /dev/null +++ b/hicexplorer/test/test_data/QC_no_restriction_site/QC.log @@ -0,0 +1,24 @@ + +File /tmp/tmpjoshwi_n.h5 +Sequenced reads 99983 +Max library insert size 1000 + +# count (percentage w.r.t. total sequenced reads) +Pairs mappable, unique and high quality 52726 (52.73) +Hi-C contacts 37321 (37.33) +One mate unmapped 8777 (8.78) +One mate not unique 3603 (3.60) +Low mapping quality 34877 (34.88) + +# count (percentage w.r.t. mappable, unique and high quality pairs) +same fragment 15393 (29.19) +duplicated pairs 12 (0.02) + +# count (percentage w.r.t. total valid pairs used) +inter chromosomal 5955 (15.96) +Intra short range (< 20kb) 8853 (23.72) +Intra long range (>= 20kb) 22513 (60.32) +Read pair type: inward pairs 7145 (19.14) +Read pair type: outward pairs 9731 (26.07) +Read pair type: left pairs 7156 (19.17) +Read pair type: right pairs 7334 (19.65) diff --git a/hicexplorer/test/test_data/QC_no_restriction_site/QC_table.txt b/hicexplorer/test/test_data/QC_no_restriction_site/QC_table.txt new file mode 100644 index 00000000..dbaf4fdb --- /dev/null +++ b/hicexplorer/test/test_data/QC_no_restriction_site/QC_table.txt @@ -0,0 +1,2 @@ +File Sequenced reads Min rest. site distance Max library insert size Pairs mappable, unique and high quality Hi-C contacts One mate unmapped One mate not unique Low mapping quality dangling end GATC self ligation (removed) One mate not close to rest site same fragment self circle duplicated pairs inter chromosomal Intra short range (< 20kb) Intra long range (>= 20kb) Read pair type: inward pairs Read pair type: outward pairs Read pair type: left pairs Read pair type: right pairs +/tmp/tmphfn27ves.h5 99983 300 1000 52726 37321 8777 3603 34877 54 5056 0 10283 651 12 5955 8853 22513 7145 9731 7156 7334 diff --git a/hicexplorer/test/test_data/QC_no_restriction_site/discarded_table.txt b/hicexplorer/test/test_data/QC_no_restriction_site/discarded_table.txt new file mode 100644 index 00000000..d2258dd7 --- /dev/null +++ b/hicexplorer/test/test_data/QC_no_restriction_site/discarded_table.txt @@ -0,0 +1,2 @@ +File One mate not close to rest site One mate not close to rest site % dangling end GATC % duplicated pairs duplicated pairs % same fragment same fragment % self circle self circle % self ligation (removed) self ligation (removed) % +/tmp/tmphfn27ves.h5 0 0.0 0.0010241626522019497 12 0.00022759170048932214 10283 0.1950271213443083 651 0.012346849751545727 5056 0.09589196980616774 diff --git a/hicexplorer/test/test_data/QC_no_restriction_site/distance.png b/hicexplorer/test/test_data/QC_no_restriction_site/distance.png new file mode 100644 index 0000000000000000000000000000000000000000..2fc52ac2124259faa51781800bf1e6a5209170a9 GIT binary patch literal 76693 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 20kb) Intra long range (>= 20kb) % +/tmp/tmphfn27ves.h5 5955 0.15956164089922564 8853 0.23721229334690924 22513 0.6032260657538652 diff --git a/hicexplorer/test/test_data/QC_no_restriction_site/hicQC.html b/hicexplorer/test/test_data/QC_no_restriction_site/hicQC.html new file mode 100644 index 00000000..0f3393aa --- /dev/null +++ b/hicexplorer/test/test_data/QC_no_restriction_site/hicQC.html @@ -0,0 +1,234 @@ + + + + + HiCExplorer QC report + + + + + + + +
+
+ +
+
+ + diff --git a/hicexplorer/test/test_data/QC_no_restriction_site/pairs_discarded.png b/hicexplorer/test/test_data/QC_no_restriction_site/pairs_discarded.png new file mode 100644 index 0000000000000000000000000000000000000000..164d803fc2b1a8817750cb88b6c379ecd707f0bb GIT binary patch literal 122153 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 literal 0 HcmV?d00001 diff --git a/hicexplorer/test/test_data/QC_no_restriction_site/pairs_sequenced.png b/hicexplorer/test/test_data/QC_no_restriction_site/pairs_sequenced.png new file mode 100644 index 0000000000000000000000000000000000000000..b66a9991e414b1de4a9ed0914f8abb7b018623de GIT binary patch literal 45459 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 ZK0&#(vnK@9H<1UT9z1p+ZQq$I{{{IxjgkNW literal 0 HcmV?d00001 diff --git a/hicexplorer/test/test_data/QC_no_restriction_site/read_orientation.png b/hicexplorer/test/test_data/QC_no_restriction_site/read_orientation.png new file mode 100644 index 0000000000000000000000000000000000000000..5022d5e18bf8f94454e18954d301fbdbfd7457b9 GIT binary patch literal 67947 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 JF(YQJ`(JlU-u(ao literal 0 HcmV?d00001 diff --git a/hicexplorer/test/test_data/QC_no_restriction_site/read_orientation_table.txt b/hicexplorer/test/test_data/QC_no_restriction_site/read_orientation_table.txt new file mode 100644 index 00000000..59dde0a9 --- /dev/null +++ b/hicexplorer/test/test_data/QC_no_restriction_site/read_orientation_table.txt @@ -0,0 +1,2 @@ +File Read pair type: inward pairs Read pair type: inward pairs % Read pair type: outward pairs Read pair type: outward pairs % Read pair type: left pairs Read pair type: left pairs % Read pair type: right pairs Read pair type: right pairs % +/tmp/tmphfn27ves.h5 7145 0.22779442708665434 9731 0.3102403876809284 7156 0.2281451252949053 7334 0.23382005993751195 diff --git a/hicexplorer/test/test_data/QC_no_restriction_site/unmapable_table.txt b/hicexplorer/test/test_data/QC_no_restriction_site/unmapable_table.txt new file mode 100644 index 00000000..e1f126e2 --- /dev/null +++ b/hicexplorer/test/test_data/QC_no_restriction_site/unmapable_table.txt @@ -0,0 +1,2 @@ +File Hi-C contacts Hi-C contacts_% Low mapping quality Low mapping quality_% One mate not unique One mate not unique_% One mate unmapped One mate unmapped_% +/tmp/tmphfn27ves.h5 37321 0.3732734564876029 34877 0.3488293009811668 3603 0.036036126141444046 8777 0.08778492343698428 diff --git a/hicexplorer/test/test_data/QC_no_restriction_site/unmappable_and_non_unique.png b/hicexplorer/test/test_data/QC_no_restriction_site/unmappable_and_non_unique.png new file mode 100644 index 0000000000000000000000000000000000000000..aa7ac743fe0763be287c36187427dff7d1d9bd69 GIT binary patch literal 84352 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 a2mcv=AH0{$@&q^$4+NgBelF{r5}E*Lg*k2j literal 0 HcmV?d00001 diff --git a/hicexplorer/test/test_data/number_of_tests.txt b/hicexplorer/test/test_data/number_of_tests.txt index e88ff725..a7ff3ab0 100644 --- a/hicexplorer/test/test_data/number_of_tests.txt +++ b/hicexplorer/test/test_data/number_of_tests.txt @@ -1 +1 @@ -602 \ No newline at end of file +605 \ No newline at end of file From 5648c5f5ef4ed2cab69fc64057a59e6232603a04 Mon Sep 17 00:00:00 2001 From: Joachim Wolff Date: Tue, 26 Nov 2024 19:40:58 +0100 Subject: [PATCH 3/6] Add bin for hicBuildMatrixMicroC --- bin/hicBuildMatrixMicroC | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100755 bin/hicBuildMatrixMicroC diff --git a/bin/hicBuildMatrixMicroC b/bin/hicBuildMatrixMicroC new file mode 100755 index 00000000..c648daa7 --- /dev/null +++ b/bin/hicBuildMatrixMicroC @@ -0,0 +1,7 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from hicexplorer.hicBuildMatrixMicroC import main + +if __name__ == "__main__": + main() From eeddf4201cb4fa42579f945588730700bb418083 Mon Sep 17 00:00:00 2001 From: Joachim Wolff Date: Wed, 27 Nov 2024 17:56:36 +0100 Subject: [PATCH 4/6] Fixing doc string test issue of different python versions --- hicexplorer/hicPlotDistVsCounts.py | 107 +++++++++++++++++++---------- 1 file changed, 72 insertions(+), 35 deletions(-) diff --git a/hicexplorer/hicPlotDistVsCounts.py b/hicexplorer/hicPlotDistVsCounts.py index 4a441641..1dca5ba0 100644 --- a/hicexplorer/hicPlotDistVsCounts.py +++ b/hicexplorer/hicPlotDistVsCounts.py @@ -5,6 +5,7 @@ import numpy as np import pandas as pd import argparse +import sys from hicmatrix import HiCMatrix from hicexplorer._version import __version__ @@ -138,41 +139,6 @@ def compute_distance_mean(hicmat, maxdepth=None, perchr=False, custom_cut_interv and values are ordered dictionary where keys are distances and values are a 2-tuple with the mean and the number of bins considered. - >>> from scipy.sparse import csr_matrix - >>> cut_intervals = [('a', 0, 10, 1), ('a', 10, 20, 1), - ... ('a', 20, 30, 1), ('a', 30, 40, 1), - ... ('b', 20, 30, 1), ('b', 30, 40, 1), ('b', 40, 50, 1)] - >>> hic = HiCMatrix.hiCMatrix() - >>> hic.nan_bins = [] - >>> matrix = np.array([ - ... [ 1, 8, 5, 3, 0, 0, 0], - ... [ 0, 4, 15, 5, 1, 0, 0], - ... [ 0, 0, 0, 7, 2, 0, 1], - ... [ 0, 0, 0, 0, 1, 0, 2], - ... [ 0, 0, 0, 0, 10, 0, 20], - ... [ 0, 0, 0, 0, 0, 0, 0], - ... [ 0, 0, 0, 0, 0, 0, 6]]) - - >>> hic.matrix = csr_matrix(matrix) - >>> hic.setMatrix(hic.matrix, cut_intervals) - >>> compute_distance_mean(hic) - {'all': OrderedDict({0: (3.0, 7), 10: (6.0, 5), 20: (10.0, 3), 30: (3.0, 1)})} - >>> compute_distance_mean(hic, perchr=True) - {'a': OrderedDict({0: (1.25, 4), 10: (10.0, 3), 20: (5.0, 2), 30: (3.0, 1)}), 'b': OrderedDict({0: (5.333333333333333, 3), 10: (0.0, 2), 20: (20.0, 1)})} - >>> custom_cut = [('tad1', 0, 10, 1), ('tad1', 10, 20, 1), ('tad2', 0, 10, 1), - ... ('tad2', 10, 20, 1), ('tad3', 0, 10, 1), ('tad3', 10, 20, 1), ('tad3', 20, 30, 1)] - >>> compute_distance_mean(hic, custom_cut_intervals=custom_cut) - {'all': OrderedDict({0: (3.0, 7), 10: (3.75, 4), 20: (20.0, 1)})} - >>> compute_distance_mean(hic, perchr=True, custom_cut_intervals=custom_cut) - {'a': OrderedDict({0: (1.25, 4), 10: (7.5, 2)}), 'b': OrderedDict({0: (5.333333333333333, 3), 10: (0.0, 2), 20: (20.0, 1)})} - >>> custom_cut = [('_ignore_0', 0, 10, 1), ('0', 0, 10, 1), - ... ('0', 10, 20, 1), ('_ignore_3', 0, 10, 1), - ... ('1', 0, 10, 1), ('1', 10, 20, 1), ('1', 20, 30, 1)] - >>> compute_distance_mean(hic, custom_cut_intervals=custom_cut) - {'all': OrderedDict({0: (4.0, 5), 10: (5.0, 3), 20: (20.0, 1)})} - - # >>> compute_distance_mean(hic, custom_cut_intervals=custom_cut, perchr=True) - # {'a': OrderedDict([(0, (2.0, 2)), (10, (15.0, 1))]), 'b': OrderedDict([(0, (5.333333333333333, 3)), (10, (0.0, 2)), (20, (20.0, 1))])} """ binsize = hicmat.getBinSize() @@ -515,3 +481,74 @@ def main(args=None): plt.tight_layout() plt.savefig(args.plotFile.name, bbox_inches='tight', bbox_extra_artists=(lgd,)) plt.close(fig) + + +if sys.version_info >= (3, 12): + compute_distance_mean.__doc__ += """ + >>> from scipy.sparse import csr_matrix + >>> cut_intervals = [('a', 0, 10, 1), ('a', 10, 20, 1), + ... ('a', 20, 30, 1), ('a', 30, 40, 1), + ... ('b', 20, 30, 1), ('b', 30, 40, 1), ('b', 40, 50, 1)] + >>> hic = HiCMatrix.hiCMatrix() + >>> hic.nan_bins = [] + >>> matrix = np.array([ + ... [ 1, 8, 5, 3, 0, 0, 0], + ... [ 0, 4, 15, 5, 1, 0, 0], + ... [ 0, 0, 0, 7, 2, 0, 1], + ... [ 0, 0, 0, 0, 1, 0, 2], + ... [ 0, 0, 0, 0, 10, 0, 20], + ... [ 0, 0, 0, 0, 0, 0, 0], + ... [ 0, 0, 0, 0, 0, 0, 6]]) + + >>> hic.matrix = csr_matrix(matrix) + >>> hic.setMatrix(hic.matrix, cut_intervals) + >>> compute_distance_mean(hic) + {'all': OrderedDict({0: (3.0, 7), 10: (6.0, 5), 20: (10.0, 3), 30: (3.0, 1)})} + >>> compute_distance_mean(hic, perchr=True) + {'a': OrderedDict({0: (1.25, 4), 10: (10.0, 3), 20: (5.0, 2), 30: (3.0, 1)}), 'b': OrderedDict({0: (5.333333333333333, 3), 10: (0.0, 2), 20: (20.0, 1)})} + >>> custom_cut = [('tad1', 0, 10, 1), ('tad1', 10, 20, 1), ('tad2', 0, 10, 1), + ... ('tad2', 10, 20, 1), ('tad3', 0, 10, 1), ('tad3', 10, 20, 1), ('tad3', 20, 30, 1)] + >>> compute_distance_mean(hic, custom_cut_intervals=custom_cut) + {'all': OrderedDict({0: (3.0, 7), 10: (3.75, 4), 20: (20.0, 1)})} + >>> compute_distance_mean(hic, perchr=True, custom_cut_intervals=custom_cut) + {'a': OrderedDict({0: (1.25, 4), 10: (7.5, 2)}), 'b': OrderedDict({0: (5.333333333333333, 3), 10: (0.0, 2), 20: (20.0, 1)})} + >>> custom_cut = [('_ignore_0', 0, 10, 1), ('0', 0, 10, 1), + ... ('0', 10, 20, 1), ('_ignore_3', 0, 10, 1), + ... ('1', 0, 10, 1), ('1', 10, 20, 1), ('1', 20, 30, 1)] + >>> compute_distance_mean(hic, custom_cut_intervals=custom_cut) + {'all': OrderedDict({0: (4.0, 5), 10: (5.0, 3), 20: (20.0, 1)})} + """ +else: + compute_distance_mean.__doc__ += """ + >>> from scipy.sparse import csr_matrix + >>> cut_intervals = [('a', 0, 10, 1), ('a', 10, 20, 1), + ... ('a', 20, 30, 1), ('a', 30, 40, 1), + ... ('b', 20, 30, 1), ('b', 30, 40, 1), ('b', 40, 50, 1)] + >>> hic = HiCMatrix.hiCMatrix() + >>> hic.nan_bins = [] + >>> matrix = np.array([ + ... [ 1, 8, 5, 3, 0, 0, 0], + ... [ 0, 4, 15, 5, 1, 0, 0], + ... [ 0, 0, 0, 7, 2, 0, 1], + ... [ 0, 0, 0, 0, 1, 0, 2], + ... [ 0, 0, 0, 0, 10, 0, 20], + ... [ 0, 0, 0, 0, 0, 0, 0], + ... [ 0, 0, 0, 0, 0, 0, 6]]) + >>> hic.matrix = csr_matrix(matrix) + >>> hic.setMatrix(hic.matrix, cut_intervals) + >>> compute_distance_mean(hic) + {'all': OrderedDict([(0, (3.0, 7)), (10, (6.0, 5)), (20, (10.0, 3)), (30, (3.0, 1))])} + >>> compute_distance_mean(hic, perchr=True) + {'a': OrderedDict([(0, (1.25, 4)), (10, (10.0, 3)), (20, (5.0, 2)), (30, (3.0, 1))]), 'b': OrderedDict([(0, (5.333333333333333, 3)), (10, (0.0, 2)), (20, (20.0, 1))])} + >>> custom_cut = [('tad1', 0, 10, 1), ('tad1', 10, 20, 1), ('tad2', 0, 10, 1), + ... ('tad2', 10, 20, 1), ('tad3', 0, 10, 1), ('tad3', 10, 20, 1), ('tad3', 20, 30, 1)] + >>> compute_distance_mean(hic, custom_cut_intervals=custom_cut) + {'all': OrderedDict([(0, (3.0, 7)), (10, (3.75, 4)), (20, (20.0, 1))])} + >>> compute_distance_mean(hic, perchr=True, custom_cut_intervals=custom_cut) + {'a': OrderedDict([(0, (1.25, 4)), (10, (7.5, 2))]), 'b': OrderedDict([(0, (5.333333333333333, 3)), (10, (0.0, 2)), (20, (20.0, 1))])} + >>> custom_cut = [('_ignore_0', 0, 10, 1), ('0', 0, 10, 1), + ... ('0', 10, 20, 1), ('_ignore_3', 0, 10, 1), + ... ('1', 0, 10, 1), ('1', 10, 20, 1), ('1', 20, 30, 1)] + >>> compute_distance_mean(hic, custom_cut_intervals=custom_cut) + {'all': OrderedDict([(0, (4.0, 5)), (10, (5.0, 3)), (20, (20.0, 1))])} + """ From d7bb826c284139a3ceeb934519aaefb276bf1ea1 Mon Sep 17 00:00:00 2001 From: Joachim Wolff Date: Wed, 27 Nov 2024 19:20:35 +0100 Subject: [PATCH 5/6] Try to fix azure with macOS --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 4e8e3511..2f83dc0f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -26,3 +26,4 @@ python-graphviz >= 0.20 scikit-learn >= 1.3,<1.4 imbalanced-learn >= 0.11 cleanlab >= 2.5 +xz \ No newline at end of file From 1238d17cd17ee7521dc811704a7829682fbc9564 Mon Sep 17 00:00:00 2001 From: Joachim Wolff Date: Wed, 27 Nov 2024 19:33:09 +0100 Subject: [PATCH 6/6] Update docs, remove of macOS fix try --- README.rst | 6 +++--- docs/content/list-of-tools.rst | 3 +++ requirements.txt | 3 +-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index e2f1ed3f..69b0cf9c 100644 --- a/README.rst +++ b/README.rst @@ -16,8 +16,8 @@ HiCExplorer =========== -Set of programs to process, analyze and visualize Hi-C and cHi-C data ---------------------------------------------------------------------- +Set of programs to process, analyze and visualize Hi-C, Micro-C and cHi-C data +------------------------------------------------------------------------------ Sequencing techniques that probe the 3D organization of the genome generate large amounts of data whose processing, analysis and visualization is challenging. Here, we present HiCExplorer, a set of tools for the analysis and @@ -26,7 +26,7 @@ of contacts, TAD detection, A/B compartments, merging, reordering or chromosomes `cooler `_ and detection of long-range contacts. Moreover, it allows the visualization of multiple contact matrices along with other types of data like genes, compartments, ChIP-seq coverage tracks (and in general any type of genomic scores), long range contacts and the visualization of viewpoints. - +With version 3.7.6 we introduce the support for Micro-C data for the build of matrices. Single-cell Hi-C data --------------------- diff --git a/docs/content/list-of-tools.rst b/docs/content/list-of-tools.rst index 6cd92433..12b4347f 100644 --- a/docs/content/list-of-tools.rst +++ b/docs/content/list-of-tools.rst @@ -8,6 +8,7 @@ Tools for Hi-C data pre-processing tools/hicFindRestSite tools/hicBuildMatrix + tools/hicBuildMatrixMicroC tools/hicSumMatrices tools/hicMergeMatrixBins tools/hicCorrectMatrix @@ -98,6 +99,8 @@ For single-cell Hi-C data analysis please use `scHiCExplorer = 0.2.7 python-graphviz >= 0.20 scikit-learn >= 1.3,<1.4 imbalanced-learn >= 0.11 -cleanlab >= 2.5 -xz \ No newline at end of file +cleanlab >= 2.5 \ No newline at end of file