Utility functions for SAM flags.

(ns cljam.io.sam.util.flag)
(def ^:private ^:const flags
  {:multiple         1 ; template having multiple segments in sequencing
   :properly-aligned 2 ; each segment properly aligned according to the aligner
   :unmapped         4 ; segment unmapped
   :next-unmapped    8 ; next segment in the template unmapped
   :reversed        16 ; SEQ begin reverse complemented
   :next-reversed   32 ; SEQ of the next segment in the template being reverse complemented
   :first           64 ; the first segment in the template
   :last           128 ; the last segment in the template
   :secondary      256 ; secondary alignment
   :filtered-out   512 ; not passing filters, such as platform/vendor quality controls
   :duplicated    1024 ; PCR or optical duplicate
   :supplementary 2048 ; supplementary alignment
   })
(def ^:private ^:const flag-keywords
  (vec (map vector (map key (sort-by val flags)) (range))))
(defn- long-bit-test
  [^long x ^long n]
  (. clojure.lang.Numbers testBit x n))

Returns a set of keywords for a given flag integer.

(defn decode
  [^long f]
  (into #{} (for [[k i] flag-keywords :when (long-bit-test f i)] k)))

Returns a flag integer encoding set of keywords.

(defn encode
  [flag-set]
  (reduce + (map flags flag-set)))

Macro to provide an encoded flag with set of keywords.

(defmacro encoded
  [flag-set-literal]
  (let [f (encode flag-set-literal)]
    f))

Returns true when an alignment with given flag is a primary line.

(defn primary?
  [^long f]
  (zero? (bit-and f 0x900)))

Tests if the template has multiple segments.

(defn multiple?
  [^long f]
  (long-bit-test f 0))

Tests if the paired-end segments are properly aligned.

(defn properly-aligned?
  [^long f]
  (long-bit-test f 1))

Tests if the segment is unmapped.

(defn unmapped?
  [^long f]
  (long-bit-test f 2))

Tests if both the segment and its mate segment are unmapped.

(defn both-unmapped?
  [^long f]
  (zero? (bit-xor (bit-and f 0xC) 0xC)))

Tests if the segment is reversed.

(defn reversed?
  [^long f]
  (long-bit-test f 4))

Tests if the segment is the first in the template.

(defn r1?
  [^long f]
  (long-bit-test f 6))

Tests if the segment is the last in the template.

(defn r2?
  [^long f]
  (long-bit-test f 7))

Returns 0 for single-end, 1 for R1 and 2 for R2.

(defn r1r2
  ^long
  [^long f]
  (-> f
      (bit-and 0xC0) ;; last-bit first-bit
      (unsigned-bit-shift-right 6)))

Tests if the alignment is secondary.

(defn secondary?
  [^long f]
  (long-bit-test f 8))