Provides algorithms for calculating simple depth of coverage. | (ns cljam.algo.depth
(:require [com.climate.claypoole :as cp]
[com.climate.claypoole.lazy :as lazy]
[cljam.common :as common]
[cljam.util.region :as region]
[cljam.io.sam :as sam]
[cljam.io.sam.util :as sam-util]
[cljam.io.sam.util.refs :as refs])
(:import [cljam.io.protocols SAMRegionBlock])) |
(def ^:private ^:const default-step 1000000) | |
lazy | |
Piles the alignments up and counts them in the positions, returning it as a seq. | (defn- count-for-positions
[alns ^long beg ^long end]
(let [pile (long-array (inc (- end beg)))]
(doseq [aln alns]
(let [left (max (long (:pos aln)) beg)
right (min (long (:end aln)) end)
left-index (- left beg)]
(dotimes [i (inc (- right left))]
(aset pile (+ i left-index) (inc (aget pile (+ i left-index)))))))
(seq pile))) |
Internal lazy-depth function returning lazy sequence of depth. | (defn- lazy-depth*
[rdr rname start end step]
(let [n-threads (common/get-exec-n-threads)
read-fn (fn [r start end]
(sam/read-blocks r {:chr rname :start start :end end} {:mode :region}))
count-fn (fn [xs]
(if (= n-threads 1)
(map (fn [[start end]]
(count-for-positions (read-fn rdr start end) start end)) xs)
(lazy/pmap (dec n-threads)
(fn [[start end]]
(with-open [r (sam/clone-bam-reader rdr)]
(count-for-positions (read-fn r start end) start end))) xs)))]
(->> (region/divide-region start end step)
count-fn
(apply concat)))) |
Calculate depth of coverage lazily. Returns a lazy seq of depth for range [start, end].
Requires a | (defn lazy-depth
[bam-reader {:keys [chr ^long start ^long end] :or {start 1 end Long/MAX_VALUE}}
& [{:keys [step n-threads] :or {step default-step n-threads 1}}]]
{:pre [chr ^long start ^long end (pos? start) (pos? end) (<= start end)]}
(when-let [{:keys [len]} (refs/ref-by-name (sam/read-refs bam-reader) chr)]
(binding [common/*n-threads* n-threads]
(lazy-depth* bam-reader
chr
(min (long len) start)
(min (long len) end)
step)))) |
eager | |
Piles alignments up and sets depth values to a part of the given int-array. | (defn- unchecked-aset-depth-in-region!
[alns beg end offset ^ints pile]
(let [beg (int beg)
end (int end)
offset (int offset)]
(run! (fn [^SAMRegionBlock aln]
(let [left (Math/max ^int (.pos aln) beg)
right (unchecked-inc-int (.end aln))
left-index (unchecked-add-int (unchecked-subtract-int left beg) offset)
right-index (unchecked-add-int (unchecked-subtract-int right beg) offset)]
(aset pile left-index (unchecked-inc-int (aget pile left-index)))
(when (<= right end)
(aset pile right-index (unchecked-dec-int (aget pile right-index))))))
alns)
(dotimes [i (- end beg)]
(aset
pile
(unchecked-add-int (unchecked-inc-int i) offset)
(unchecked-add-int
(aget pile (unchecked-add-int i offset))
(aget pile (unchecked-add-int (unchecked-inc-int i) offset))))))) |
Piles alignments up and sets depth values to a part of the given int-array. It's roughly 15-25% slower than unchecked version. | (defn- aset-depth-in-region!
[alns beg end offset ^ints pile]
(let [beg (int beg)
end (int end)
offset (int offset)]
(run! (fn [aln]
(let [left (Math/max (int (:pos aln)) beg)
right (inc (or (long (:end aln)) (sam-util/get-end aln)))
left-index (+ (- left beg) offset)
right-index (+ (- right beg) offset)]
(aset pile left-index (inc (aget pile left-index)))
(when (<= right end)
(aset pile right-index (dec (aget pile right-index))))))
alns)
(dotimes [i (- end beg)]
(aset pile (+ (inc i) offset) (+ (aget pile (+ i offset)) (aget pile (+ (inc i) offset))))))) |
Internal depth function which returns an int-array. | (defn ^"[I" depth*
[rdr {:keys [chr ^long start ^long end] :as region}
& [{:keys [step unchecked? n-threads] :or {step default-step unchecked? false n-threads 1}}]]
(let [pile (int-array (inc (- end start)))
f (if unchecked? unchecked-aset-depth-in-region! aset-depth-in-region!)]
(if (= n-threads 1)
(f (sam/read-blocks rdr region {:mode :region}) start end 0 pile)
(cp/pdoseq
n-threads
[[s e] (region/divide-region start end step)]
(with-open [r (sam/clone-bam-reader rdr)]
(-> (sam/read-blocks r {:chr chr, :start s, :end e} {:mode :region})
(f s e (- (long s) start) pile)))))
pile)) |
Calculate depth of coverage eagerly. Returns a seq of depth for range [start, end].
Requires a | (defn depth
[bam-reader {:keys [chr ^long start ^long end]
:or {start 1 end Long/MAX_VALUE}}
& [{:keys [step unchecked? n-threads] :or {step default-step unchecked? false n-threads 1}}]]
{:pre [chr start end
(pos? (long start)) (pos? (long end)) (<= (long start) (long end))]}
(when-let [{:keys [len]} (refs/ref-by-name (sam/read-refs bam-reader) chr)]
(seq
(depth*
bam-reader
{:chr chr, :start (min (long len) start), :end (min (long len) end)}
{:step step, :unchecked? unchecked?, :n-threads n-threads})))) |