这是用户在 2024-9-19 10:49 为 https://app.immersivetranslate.com/pdf-pro/1278e129-84c3-433c-99af-fee32bda17e5 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?


CRAM 格式规范(版本 3.1)

samtools-devel@lists.sourceforge.net

 2024 年 9 月 4 日

 摘要


该文档的主版本可以在 https://github.com/samtools/hts-specs 找到。此打印版本为该存储库中的 4127441,最后修改日期如上所示。

 许可证:Apache 2.0

 1 概述


该规范描述了 CRAM 3.0 和 3.1 格式。


CRAM 具有以下主要目标:

  1. 比 BAM 显著更好的无损压缩

  2. 与 BAM 完全兼容

  3. 轻松从使用 BAM 文件过渡到 CRAM

  4. 对 BAM 数据的受控丢失支持

前三个目标使用户能够立即利用 CRAM 格式,同时提供从使用 BAM 文件平滑过渡的路径。第四个目标支持探索不同的有损压缩策略,并提供一个框架以实施这些选择。请注意,CRAM 格式并不对应该保留或不应保留的数据施加任何规则。相反,CRAM 支持广泛的无损和有损数据保留策略,使用户能够选择应保留哪些数据。


CRAM 中的数据存储为 CRAM 记录或使用通用压缩器(gzip,bzip2)。CRAM 记录使用多种不同的编码策略进行压缩。例如,碱基通过编码碱基差异进行参考压缩,而不是存储碱基本身。 1 1 ^(1){ }^{1}

 2 数据类型


CRAM 规范使用逻辑数据类型和存储数据类型;逻辑数据类型用单词表示(例如 int),而物理数据类型用单个字母表示(例如 i)。两者之间的区别在于存储数据类型定义了逻辑数据类型在 CRAM 中的存储方式。CRAM 中的数据以位或字节的形式存储。以下将详细描述以位和字节写入值的方式。


2.1 逻辑数据类型

 字节


有符号字节(8 位)。

 整数

 签名的 32 位整数。

 


签名的 64 位整数。

 数组


任何逻辑数据类型的数组:array


2.2 将位写入位流


位流由一系列的 1 和 0 组成。位是从最重要的位开始书写,新位堆叠在右侧,左侧的完整字节被写出。在位流中,如果最后一个字节写入的位少于 8 位,则该字节将不完整。在这种情况下,最后一个字节中的位将向左移动。


写入位流的示例


让我们考虑以下示例。下表显示了一系列写操作:
 操作顺序  缓冲区状态之前  书写的位元  缓冲区状态之后  发出字节
1 0 × 0 0 × 0 0xx00 \times 0 1 0 × 1 0 × 1 0xx10 \times 1 -
2 0 × 1 0 × 1 0xx10 \times 1 0 0 × 2 0 × 2 0xx20 \times 2 -
3 0 × 2 0 × 2 0xx20 \times 2 11 0 × B 0 × B 0xx B0 \times B -
4 0 × B 0 × B 0xx B0 \times B 00000111 0 × 7 0 × 7 0xx70 \times 7 0 × B 0 0 × B 0 0xx B00 \times B 0
Operation order Buffer state before Written bits Buffer state after Issued bytes 1 0xx0 1 0xx1 - 2 0xx1 0 0xx2 - 3 0xx2 11 0xx B - 4 0xx B 00000111 0xx7 0xx B0| Operation order | Buffer state before | Written bits | Buffer state after | Issued bytes | | :--- | :--- | :--- | :--- | :--- | | 1 | $0 \times 0$ | 1 | $0 \times 1$ | - | | 2 | $0 \times 1$ | 0 | $0 \times 2$ | - | | 3 | $0 \times 2$ | 11 | $0 \times B$ | - | | 4 | $0 \times B$ | 00000111 | $0 \times 7$ | $0 \times B 0$ |

在刷新上述比特流后,写入以下字节: 0 x B 0 0 x B 0 0xB00 x B 0 0x70。请注意,最后一个字节在左移之前是 0 × 7 0 × 7 0xx70 \times 7 ,左移后变为 0 x 70 0 x 70 0x 700 x 70
> echo "obase=16; ibase=2; 00000111" | bc
7
> echo "obase=16; ibase=2; 01110000" | bc
7 0

整个比特序列:
echo “obase=2; ibase=16; B070” | bc
1011000001110000

在读取位序列中的位时,必须知道只有 12 位是有意义的,位流在此之后不应再读取。


写入比特流的注意事项


在写入比特流时,必须知道值和该值中的比特数。这是因为编程语言通常以字节(8 位)为单位操作,而要指定要写入哪些比特需要一个比特持有者,例如一个整数,以及其中的比特数。同样,在从比特流中读取值时,必须提前知道比特数。在前缀编码(例如霍夫曼编码)的情况下,所有可能的比特组合要么是提前已知的,要么可以根据前几个比特计算出后面将跟随多少比特。或者,可以组合两个编码,第一个编码包含要读取的比特数。


2.3 将字节写入字节流


字节流的解释很简单。CRAM 在适用时使用小端字节序,并定义以下存储数据类型:

 布尔值 (bool)


布尔值以 1 字节表示,其中 0 x 0 0 x 0 0x00 x 0 为‘假’,0x1 为‘真’。

 整数 (int32)


签名的 32 位整数,以小端字节顺序写为 4 个字节。

 长整型 (int64)


签名的 64 位整数,以小端字节顺序写为 8 个字节。

 ITF-8 整数 (itf8)


这是一种写整数值的替代方法。这个想法类似于 UTF-8 编码,因此这种编码被称为 ITF-8(整数转换格式 - 8 位)。


第一个字节的最高有效位具有特殊含义,称为“前缀”。这些是 0 到 4 个真实位,后面跟着一个 0。1 的数量表示后续字节的数量。为了适应 32 位,这种表示需要 5 个字节,最后一个字节仅使用 4 个低位。

 LTF-8 长 (ltf8)


请参阅 ITF-8 以获取更多详细信息。ITF-8 和 LTF-8 之间的唯一区别是用于编码单个值的字节数。为此需要 64 位,最多可以使用 9 个字节,第一个字节仅由 1 或 0xFF 值组成。

 数组 (array<类型>)


一个具有显式维度的可变大小数组。数组长度首先以整数(itf8)形式写出,随后是数组的元素。


隐式或固定大小的数组也被使用,写作类型 [ ] 或类型 [4](例如)。这些在文件格式中没有包含显式维度,而是依赖于规范本身来记录数组大小。

 编码


编码是一种数据类型,指定数据系列是如何被压缩的。编码被定义为 encoding,其中类型是逻辑数据类型,而不是存储数据类型。


编码如下所示。第一个整数(itf8)表示编解码器 ID,第二个整数(itf8)表示后续编码特定值的字节数。


亚指数编码示例:
   类型  名称
0x7 itf8  编解码器 ID
0x2 itf8
后续字节数
0x0 itf8  偏移量
0x1 itf8  K 参数
Value Type Name 0x7 itf8 codec id 0x2 itf8 number of bytes to follow 0x0 itf8 offset 0x1 itf8 K parameter| Value | Type | Name | | :--- | :--- | :--- | | 0x7 | itf8 | codec id | | 0x2 | itf8 | number of bytes to follow | | 0x0 | itf8 | offset | | 0x1 | itf8 | K parameter |

第一个字节 " 0 × 7 0 × 7 0xx70 \times 7 " 是编解码器 ID。


下一个字节 "0 x 2" 表示后续字节的长度 (2)。


子指数编码有两个参数:整数(itf8)偏移量和整数(itf8)K。

 偏移 = 0 x 0 = 0 = 0 x 0 = 0 =0x0=0=0 \mathrm{x} 0=0
K = 0 x 1 = 1 K = 0 x 1 = 1 K=0x1=1\mathrm{K}=0 \mathrm{x} 1=1
 地图

映射是键及其关联值的集合。具有 N N NN 个键的映射写作如下:
 字节大小 N  键 1  值 1  键...  值 ...  键 N  值 N
size in bytes N key 1 value 1 key... value ... key N value N| size in bytes | N | key 1 | value 1 | key... | value ... | key N | value N | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |

字节大小和键的数量都以整数(itf8)形式写入。键和值根据其数据类型进行书写,并且对每个映射都是特定的。

 字符串


字符串使用 UTF-8 格式表示为字节数组。读取名称、参考序列名称和类型为 ' Z Z ZZ ' 的标签值存储为 UTF-8。

 3 编码


编码是一种数据结构,用于捕获关于数据系列压缩细节的信息,这些信息是解压缩所必需的。这可能是一组常量,用于初始化特定的解压缩算法,或者是数据系列的统计属性,或者在数据系列存储在外部块的情况下,块内容的 ID。

编码标记被定义为关键字“encoding”后跟其数据类型的尖括号,例如“encoding”表示对数据类型为“byte”的数据系列进行操作的编码。


编码可能具有不同数据类型的参数,例如 EXTERNAL 编码只有一个参数,即外部块的整数 ID。定义了以下编码:
 编解码器 ID  参数  评论
NULL 0    系列未被保留
EXTERNAL 1
int 块内容 id

用于将外部数据块与数据系列关联的块内容标识符
the block content identifier used to associate external data blocks with data series| the block content identifier used to | | :--- | | associate external data blocks with | | data series |
 已弃用 (GOLOMB) 2 int offset, int M  戈隆布编码
HUFFMAN 3 array<int>, array<int>
使用 int/byte 值进行编码
BYTE_ARRAY_LEN 4

编码 数组长度,编码 字节
encoding<int> array length, encoding<byte> bytes| encoding<int> array length, | | :--- | | encoding<byte> bytes |

字节数组的编码与数组长度
coding of byte arrays with array length| coding of byte arrays with array | | :--- | | length |
BYTE_ARRAY_STOP 5

字节停止,整数外部块内容 ID
byte stop, int external block content id| byte stop, int external block | | :--- | | content id |

字节数组的编码与停止值
coding of byte arrays with a stop value| coding of byte arrays with a stop | | :--- | | value |
BETA 6
int 偏移量, int 位数
 二进制编码
SUBEXP 7 int offset, int K  亚指数编码

已弃用 (GOLOMB_RICE)
8 int offset, int log 2 m log 2 m log_(2)m\log _{2} \mathrm{~m}  戈隆布-赖斯编码
GAMMA 9 int offset  埃利亚斯伽马编码
Codec ID Parameters Comment NULL 0 none series not preserved EXTERNAL 1 int block content id "the block content identifier used to associate external data blocks with data series" Deprecated (GOLOMB) 2 int offset, int M Golomb coding HUFFMAN 3 array<int>, array<int> coding with int/byte values BYTE_ARRAY_LEN 4 "encoding<int> array length, encoding<byte> bytes" "coding of byte arrays with array length" BYTE_ARRAY_STOP 5 "byte stop, int external block content id" "coding of byte arrays with a stop value" BETA 6 int offset, int number of bits binary coding SUBEXP 7 int offset, int K subexponential coding Deprecated (GOLOMB_RICE) 8 int offset, int log_(2)m Golomb-Rice coding GAMMA 9 int offset Elias gamma coding| Codec | ID | Parameters | Comment | | :--- | :--- | :--- | :--- | | NULL | 0 | none | series not preserved | | EXTERNAL | 1 | int block content id | the block content identifier used to <br> associate external data blocks with <br> data series | | Deprecated (GOLOMB) | 2 | int offset, int M | Golomb coding | | HUFFMAN | 3 | array<int>, array<int> | coding with int/byte values | | BYTE_ARRAY_LEN | 4 | encoding<int> array length, <br> encoding<byte> bytes | coding of byte arrays with array <br> length | | BYTE_ARRAY_STOP | 5 | byte stop, int external block <br> content id | coding of byte arrays with a stop <br> value | | BETA | 6 | int offset, int number of bits | binary coding | | SUBEXP | 7 | int offset, int K | subexponential coding | | Deprecated (GOLOMB_RICE) | 8 | int offset, int $\log _{2} \mathrm{~m}$ | Golomb-Rice coding | | GAMMA | 9 | int offset | Elias gamma coding |

请参阅第 13 节以获取上述所有编码算法及其参数的更详细描述。

 4 个校验和


校验和用于确保数据完整性。CRAM 中使用了以下校验和算法。

4.1 CRC32


这是一个 32 位长的循环冗余校验,使用多项式 0x04C11DB7。有关更多详细信息,请参阅 ITU-T V. 42。CRC32 哈希函数的值以整数形式表示。

 4.2 CRC32 校验和


CRC32 和是通过对所有单个 CRC32 值进行求和并对 2 32 2 32 2^(32)2^{32} 取模得到的 CRC32 值的组合。

 5 文件结构


本节描述了整体的 CRAM 文件结构。有关更详细的信息,请参阅本文档的其他部分。


CRAM 文件由一个固定长度的文件定义组成,后面是一个 CRAM 头容器,然后是零个或多个数据容器,最后是一个特殊的文件结束容器。
 文件定义
File definition| File | | :---: | | definition |
 CRAM 头部容器
CRAM Header Container| CRAM Header | | :---: | | Container |
 数据容器
Data Container| Data | | :---: | | Container |
cdots\cdots
 数据容器
Data Container| Data | | :---: | | Container |
 CRAM EOF 容器
CRAM EOF Container| CRAM EOF | | :---: | | Container |
"File definition" "CRAM Header Container" "Data Container" cdots "Data Container" "CRAM EOF Container"| File <br> definition | CRAM Header <br> Container | Data <br> Container | $\cdots$ | Data <br> Container | CRAM EOF <br> Container | | :---: | :---: | :---: | :---: | :---: | :---: |

图 1:CRAM 文件由文件定义组成,后面是头部容器,然后是其他容器。


容器由一个或多个块组成。第一个容器称为 CRAM 头容器,用于存储如 SAM 规范中所述的文本头(参见第 7.1 节)。此容器可能会有额外的填充字节,以便允许对 SAM 头进行小规模的内联重写。这些填充字节是未定义的,但我们建议用零填充。填充字节可以是显式未压缩的块结构,或者是未分配的额外空间,其中容器的大小大于其内部块的总大小。

图 2:第一个容器包含 CRAM 头文本。


每个容器以一个容器头结构开始,后面跟着一个或多个块。每个容器中的第一个块是压缩头块,提供有关如何解码后续块中数据的详细信息。每个块以一个块头结构开始,后面跟着块数据。

图 3:容器作为一系列块


压缩头后的块在逻辑上组织成切片。一个切片可能包含例如一段连续的对齐数据。切片以切片头块开始,后面跟着一个或多个数据块。正是这些数据块保存了 CRAM 数据的主要部分。数据块进一步细分为核心数据块和一个或多个外部数据块。

图 4:由一系列连接块形成的切片

 6 文件定义


每个 CRAM 文件以固定长度(26 字节)的定义开始,包含以下字段:
 数据类型  名称  
 字节[4]  格式魔数 CRAM (0x43 0x52 0x41 0x4d)
 无符号字节  主要格式编号 3 ( 0 x 3 ) 3 ( 0 x 3 ) 3(0x3)3(0 x 3)
 无符号字节  小格式编号 1 (0x1)
 字节[20]  文件 ID
CRAM 文件标识符(例如文件名或 SHA1 校验和)
Data type Name Value byte[4] format magic number CRAM (0x43 0x52 0x41 0x4d) unsigned byte major format number 3(0x3) unsigned byte minor format number 1 (0x1) byte[20] file id CRAM file identifier (e.g. file name or SHA1 checksum)| Data type | Name | Value | | :--- | :--- | :--- | | byte[4] | format magic number | CRAM (0x43 0x52 0x41 0x4d) | | unsigned byte | major format number | $3(0 x 3)$ | | unsigned byte | minor format number | 1 (0x1) | | byte[20] | file id | CRAM file identifier (e.g. file name or SHA1 checksum) |

有效的 CRAM 主版本.次版本号如下:


1.0 原始公共 CRAM 版本。


2.0 第一个 CRAM 版本在 Java 和 C 中实现;整理了 1.0 中的实现与规范差异。


2.1 获得文件结束标记;与 2.0 兼容。


3.0 额外的压缩方法;头部和数据校验和;对无序数据的改进。


3.1 仅限额外的外部压缩编解码器。

CRAM 3.0 和 3.1 仅在可用的压缩方法列表上有所不同,因此输出 CRAM 3 而不使用任何 3.1 编解码器的工具应写入头部以指示 3.0,以便允许最大兼容性。


7 容器头结构


文件定义后面跟着一个或多个容器,具有以下头部结构,其中容器内容存储在“blocks”字段中:
 数据类型  名称  
int32  长度

该容器中所有块的长度总和(头部和数据)以及任何填充字节(仅限 CRAM 头部容器);等于容器的总字节长度减去该头部结构的字节长度
the sum of the lengths of all blocks in this container (headers and data) and any padding bytes (CRAM header container only); equal to the total byte length of the container minus the byte length of this header structure| the sum of the lengths of all blocks in this container | | :--- | | (headers and data) and any padding bytes (CRAM header | | container only); equal to the total byte length of the | | container minus the byte length of this header structure |
itf8  参考序列 ID

参考序列标识符或 -1 表示未映射的读取 -2 表示多个参考序列。此容器中的所有切片必须具有与此值匹配的参考序列 ID。
reference sequence identifier or -1 for unmapped reads -2 for multiple reference sequences. All slices in this container must have a reference sequence id matching this value.| reference sequence identifier or | | :--- | | -1 for unmapped reads | | -2 for multiple reference sequences. | | All slices in this container must have a reference sequence | | id matching this value. |
itf8

参考上的起始位置
starting position on the reference| starting position on the | | :--- | | reference |

对齐起始位置
itf8  对齐跨度
对齐的长度
itf8  记录数
容器中的记录数
ltf8  记录计数器
文件/流中记录的基于 1 的顺序索引。
ltf8  基础
读取碱基数
itf8  块的数量
此容器中的块总数
array<itf8>  地标

该容器中切片的位置作为从该容器头部末尾的字节偏移量,用于随机访问索引。对于序列数据容器,地标计数必须等于切片计数。由于第一个切片之前的块是压缩头,因此 landmarks[0] 等于压缩头的字节长度。
the locations of slices in this container as byte offsets from the end of this container header, used for random access indexing. For sequence data containers, the landmark count must equal the slice count. Since the block before the first slice is the compression header, landmarks[0] is equal to the byte length of the compression header.| the locations of slices in this container as byte offsets from | | :--- | | the end of this container header, used for random access | | indexing. For sequence data containers, the landmark | | count must equal the slice count. | | Since the block before the first slice is the compression | | header, landmarks[0] is equal to the byte length of the | | compression header. |
 整数 crc32
容器中所有前面字节的 CRC32 哈希。
 字节[  区块
容器内包含的块。
Data type Name Value int32 length "the sum of the lengths of all blocks in this container (headers and data) and any padding bytes (CRAM header container only); equal to the total byte length of the container minus the byte length of this header structure" itf8 reference sequence id "reference sequence identifier or -1 for unmapped reads -2 for multiple reference sequences. All slices in this container must have a reference sequence id matching this value." itf8 "starting position on the reference" the alignment start position itf8 alignment span the length of the alignment itf8 number of records number of records in the container ltf8 record counter 1-based sequential index of records in the file/stream. ltf8 bases number of read bases itf8 number of blocks the total number of blocks in this container array<itf8> landmarks "the locations of slices in this container as byte offsets from the end of this container header, used for random access indexing. For sequence data containers, the landmark count must equal the slice count. Since the block before the first slice is the compression header, landmarks[0] is equal to the byte length of the compression header." int crc32 CRC32 hash of the all the preceding bytes in the container. byte[ blocks The blocks contained within the container.| Data type | Name | Value | | :---: | :---: | :---: | | int32 | length | the sum of the lengths of all blocks in this container <br> (headers and data) and any padding bytes (CRAM header <br> container only); equal to the total byte length of the <br> container minus the byte length of this header structure | | itf8 | reference sequence id | reference sequence identifier or <br> -1 for unmapped reads <br> -2 for multiple reference sequences. <br> All slices in this container must have a reference sequence <br> id matching this value. | | itf8 | starting position on the <br> reference | the alignment start position | | itf8 | alignment span | the length of the alignment | | itf8 | number of records | number of records in the container | | ltf8 | record counter | 1-based sequential index of records in the file/stream. | | ltf8 | bases | number of read bases | | itf8 | number of blocks | the total number of blocks in this container | | array<itf8> | landmarks | the locations of slices in this container as byte offsets from <br> the end of this container header, used for random access <br> indexing. For sequence data containers, the landmark <br> count must equal the slice count. <br> Since the block before the first slice is the compression <br> header, landmarks[0] is equal to the byte length of the <br> compression header. | | int | crc32 | CRC32 hash of the all the preceding bytes in the container. | | byte[ | blocks | The blocks contained within the container. |

在初始的 CRAM 头容器中,读取时必须忽略参考序列 ID、参考上的起始位置和比对跨度字段。地标数组对于 CRAM 头是可选的,但如果存在,它应该指向块偏移而不是切片,第一个块包含文本头。

在数据容器中指定未映射的读取或多个参考序列(即参考序列 ID < 0 < 0 < 0<0 )时,读取时必须忽略参考上的起始位置和比对跨度字段。在写入时,建议将每个被忽略的字段设置为值 0。


7.1 CRAM 头部容器


CRAM 文件中的第一个容器包含一个或多个块中的文本头。有关这些块内数据布局和对 SAM 头内容施加的约束的更多详细信息,请参见第 8.3 节。

容器头结构的地标字段可用于指示在头容器中使用的块的偏移量。通过指定数组大小为零,这些可以选择性地省略。

 8 块结构


容器由一个或多个块组成。块压缩是独立应用的,并且是对块内数据进行压缩时使用的任何编码的补充。块具有以下头部结构,数据存储在“块数据”字段中:
 数据类型  名称  
 字节  方法
块压缩方法(以及第一个 CRAM 版本):
 0: 原始 (无)*
1: gzip
2: bzip2 (v2.0)
3: lzma (v3.0)
4: rans4x8 (v3.0)
5: rans4x16 (v3.1)

6: 自适应算术编码器 (v3.1)
7: fqzcomp (v3.1)

8: 名称分词器 (v3.1)
 字节
区块内容类型 ID

块内容类型标识符
itf8  字节大小*
用于关联外部数据的块内容标识符

原始大小(字节)*

数据系列的块
itf8  块数据
应用块压缩后块数据的大小
itf8
在应用块压缩之前存储的数据
 字节[]
・ CRAM 记录的位流(核心数据块)

\bullet 字节流(外部数据块)
CRC32
附加字段(头部块)
 字节[4]
区块中所有前导字节的 CRC32 哈希值
Data type Name Value byte method the block compression method (and first CRAM version): 0: raw (none)* 1: gzip 2: bzip2 (v2.0) 3: lzma (v3.0) 4: rans4x8 (v3.0) 5: rans4x16 (v3.1) 6: adaptive arithmetic coder (v3.1) 7: fqzcomp (v3.1) 8: name tokeniser (v3.1) byte block content type id the block content type identifier itf8 size in bytes* the block content identifier used to associate external data raw size in bytes* blocks with data series itf8 block data size of the block data after applying block compression itf8 the data stored in the before applying block compression byte[] ・ bit stream of CRAM records (core data block) ∙ byte stream (external data block) CRC32 additional fields ( header blocks) byte[4] CRC32 hash value for all preceding bytes in the block | Data type | Name | Value | | :--- | :--- | :--- | | byte | method | the block compression method (and first CRAM version): | | | | 0: raw (none)* | | | | 1: gzip | | | | 2: bzip2 (v2.0) | | | | 3: lzma (v3.0) | | | | 4: rans4x8 (v3.0) | | | | 5: rans4x16 (v3.1) | | | | 6: adaptive arithmetic coder (v3.1) | | | | 7: fqzcomp (v3.1) | | | | 8: name tokeniser (v3.1) | | byte | block content type id | the block content type identifier | | itf8 | size in bytes* | the block content identifier used to associate external data | | | raw size in bytes* | blocks with data series | | itf8 | block data | size of the block data after applying block compression | | itf8 | | the data stored in the before applying block compression | | byte[] | ・ bit stream of CRAM records (core data block) | | | | | $\bullet$ byte stream (external data block) | | | CRC32 | additional fields ( header blocks) | | byte[4] | CRC32 hash value for all preceding bytes in the block | |

  • 关于原始方法的说明:压缩大小和原始大小必须设置为相同的值。

文件中可能会出现空块。原始(未压缩)大小为零的块被视为空块,无论其“方法”字节是什么。这相当于将它们解释为具有方法零(原始)和压缩大小为零。


8.1 块内容类型


CRAM 具有以下块内容类型:
 块内容类型

块内容类型 ID
Block content type id| Block | | :--- | | content | | type id |
 名称  内容
FILE_HEADER 0  CRAM 头块  CRAM 头部
COMPRESSION_HEADER 1
压缩头块
 查看特定部分
SLICE_HEADER a ^("a "){ }^{\text {a }} 2  切片头块  查看特定部分
3  保留
EXTERNAL_DATA 4  外部数据块

由外部编码生成的数据
data produced by external encodings| data produced by | | :--- | | external encodings |
CORE_DATA 5  核心数据块

所有编码的比特流,除了外部编码
bit stream of all encodings except for external encodings| bit stream of all | | :--- | | encodings except for | | external encodings |
Block content type "Block content type id" Name Contents FILE_HEADER 0 CRAM header block CRAM header COMPRESSION_HEADER 1 Compression header block See specific section SLICE_HEADER ^("a ") 2 Slice header block See specific section 3 reserved EXTERNAL_DATA 4 external data block "data produced by external encodings" CORE_DATA 5 core data block "bit stream of all encodings except for external encodings"| Block content type | Block <br> content <br> type id | Name | Contents | | :--- | :--- | :--- | :--- | | FILE_HEADER | 0 | CRAM header block | CRAM header | | COMPRESSION_HEADER | 1 | Compression header block | See specific section | | SLICE_HEADER ${ }^{\text {a }}$ | 2 | Slice header block | See specific section | | | 3 | | reserved | | EXTERNAL_DATA | 4 | external data block | data produced by <br> external encodings | | CORE_DATA | 5 | core data block | bit stream of all <br> encodings except for <br> external encodings |


8.2 块内容 ID


块内容 ID 用于区分同一切片中的外部块。每个外部编码都有一个 id 参数,该参数必须是外部块内容 ID 之一。对于外部块,内容 ID 是一个正整数。对于所有其他块,内容 ID 应为 0。因此,所有外部编码不得使用小于 1 的内容 ID。

 数据块


数据存储在数据块中。数据块有两种类型:核心数据块和外部数据块。核心数据块和外部数据块的区别在于,核心数据块由使用位编码压缩的数据序列组成,而外部数据块则是字节压缩的。每个切片关联一个核心数据块和任意数量的外部数据块。


通过 CRAM 记录组织对核心和外部数据块的读写。每个数据系列都与一种编码相关联。在外部编码的情况下,使用块内容 ID 来识别存储数据系列的块。请注意,外部块可以与多个数据系列相关联;在这种情况下,这些数据系列的值将交错。


8.3 CRAM 头块


SAM 头信息存储在 CRAM 头容器的第一个块中(见第 7.1 节)。该块可以是未压缩的或仅 gzip 压缩的。该块后面可以跟零个或多个未压缩的扩展块。如果存在,这些块允许对 CRAM 头进行就地编辑,使其能够随着补偿性大小变化而增长或缩小,避免了重写文件其余部分的需要。任何扩展块的内容应为零字节(空字符)。


初始 SAM 头块的格式是一个 32 位小端整数,表示 SAM 头文本的长度,减去空终止字节,后面是文本本身。尽管是 32 位,允许的最大值是 2 31 2 31 2^(31)2^{31} ,所有长度必须为正。


以下约束适用于 SAM 头文本:

  • SQ:MD5 校验和是必需的,除非参考序列已嵌入文件中。


8.4 压缩头块


压缩头块由三个部分组成:保留映射、数据系列编码映射和标签编码映射。

 保护地图


保留映射包含有关在 CRAM 文件中保留了哪些数据的信息。它作为一个具有 byte[2]键的映射存储:
 关键  值数据类型  名称  
RN  布尔值  读取包含的名称
如果所有读取的名称都被保留,则为真
AP  布尔值
AP 数据系列增量

如果 AP 数据系列是增量,则为 true,否则为 false
RR  布尔值  参考要求

如果需要参考序列以完全恢复数据,则为真
true if reference sequence is required to restore the data completely| true if reference sequence is required to restore | | :--- | | the data completely |
SM  字节[5]  替代矩阵  替代矩阵
TD  字节数组  标签 ID 字典
标签 ID 的列表列表,请参见标签编码部分
Key Value data type Name Value RN bool read names included true if read names are preserved for all reads AP bool AP data series delta true if AP data series is delta, false otherwise RR bool reference required "true if reference sequence is required to restore the data completely" SM byte[5] substitution matrix substitution matrix TD array<byte> tag ids dictionary a list of lists of tag ids, see tag encoding section| Key | Value data type | Name | Value | | :--- | :--- | :--- | :--- | | RN | bool | read names included | true if read names are preserved for all reads | | AP | bool | AP data series delta | true if AP data series is delta, false otherwise | | RR | bool | reference required | true if reference sequence is required to restore <br> the data completely | | SM | byte[5] | substitution matrix | substitution matrix | | TD | array<byte> | tag ids dictionary | a list of lists of tag ids, see tag encoding section |

布尔值是可选的,缺省为 true,尽管建议明确设置它们。SM 和 TD 是必需的。

 数据系列编码


每个数据系列都有一个编码。这些编码存储在一个以 byte[2] 为键的映射中,并大致按照以下顺序解码 2 2 ^(2){ }^{2}
 关键  值数据类型  名称  
BF  编码  BAM 位标志  请参见单独部分
CF  编码  CRAM 位标志  查看特定部分
RI  编码  参考 ID
从 SAM 文件头中记录参考 ID
RL  编码  读取长度  读取长度
AP  编码  序列中的位置

如果 AP-Delta = true:基于 0 的对齐开始增量来自于前一记录中的 AP 值。请注意,这个增量可能是负数,例如在多参考切片中切换参考时。当记录是切片中的第一个时,使用的前一个位置是切片对齐开始字段(因此对于单参考切片,第一个增量应该为零,对于多参考切片,应该是 AP 值本身)。如果 AP-Delta = false:直接编码对齐开始位置。
if AP-Delta = true: 0-based alignment start delta from the AP value in the previous record. Note this delta may be negative, for example when switching references in a multi-reference slice. When the record is the first in the slice, the previous position used is the slice alignment-start field (hence the first delta should be zero for single-reference slices, or the AP value itself for multi-reference slices). if AP-Delta = false: encodes the alignment start position directly| if AP-Delta = true: 0-based alignment start | | :--- | | delta from the AP value in the previous record. | | Note this delta may be negative, for example | | when switching references in a multi-reference | | slice. When the record is the first in the slice, the | | previous position used is the slice alignment-start | | field (hence the first delta should be zero for | | single-reference slices, or the AP value itself for | | multi-reference slices). | | if AP-Delta = false: encodes the alignment start | | position directly |
RG  编码  阅读组

读取组。特殊值 '-1' 表示没有组。
read groups. Special value ' -1 ' stands for no group.| read groups. Special value ' -1 ' stands for no | | :--- | | group. |
RN a RN a RN^(a)\mathrm{RN}^{\mathrm{a}}  编码  读取名称  读取名称
MF  编码
下一个伙伴位标志
 查看特定部分
NS  编码

下一个片段参考序列 ID
next fragment reference sequence id| next fragment | | :--- | | reference sequence id |

下一个片段的参考序列 ID
NP  编码

下一个配对对齐开始
next mate alignment start| next mate alignment | | :--- | | start |

下一个片段的对齐位置
TS  编码  模板大小  模板大小
NF  编码

到下一个片段的距离
distance to next fragment| distance to next | | :--- | | fragment |

跳过到下一个片段的记录数 b b ^(b){ }^{b}
TL C TL C TL^(C)\mathrm{TL}^{\mathrm{C}}  编码  标签 ID
标签 ID 列表,请参见标签编码部分
FN  编码

读取特征的数量
number of read features| number of read | | :--- | | features |

每条记录中读取特征的数量
FC  编码  阅读功能代码  请参见单独部分
FP  编码  阅读中的位置

读取特征的位置;相对于最后一个位置的正增量(从零开始)
positions of the read features; a positive delta to the last position (starting with zero)| positions of the read features; a positive delta to | | :--- | | the last position (starting with zero) |
DL  编码  删除长度
碱基对缺失长度
BB  编码  基础的延伸  基础
QQ  编码

质量分数的区间
stretches of quality scores| stretches of quality | | :--- | | scores |
 质量分数
BS  编码
 碱基替代编码
base substitution codes| base substitution | | :--- | | codes |
 碱基替代编码
IN  编码  插入  插入的碱基
RS  编码  参考跳过长度
'N'读取特征的跳过碱基数量
PD  编码  填充
填充碱基的数量
HC  编码  硬剪辑
硬剪切碱基的数量
SC  编码  软剪辑  软剪切碱基
MQ  编码  映射质量  映射质量分数
BA  编码  基础  基础
QS  编码  质量分数  质量分数
TC d TC d TC^(d)\mathrm{TC}^{\mathrm{d}}  不适用  遗留字段  被忽略
TN d TN d TN^(d)\mathrm{TN}^{\mathrm{d}}  不适用  遗留字段  被忽略
Key Value data type Name Value BF encoding<int> BAM bit flags see separate section CF encoding<int> CRAM bit flags see specific section RI encoding<int> reference id record reference id from the SAM file header RL encoding<int> read lengths read lengths AP encoding<int> in-seq positions "if AP-Delta = true: 0-based alignment start delta from the AP value in the previous record. Note this delta may be negative, for example when switching references in a multi-reference slice. When the record is the first in the slice, the previous position used is the slice alignment-start field (hence the first delta should be zero for single-reference slices, or the AP value itself for multi-reference slices). if AP-Delta = false: encodes the alignment start position directly" RG encoding<int> read groups "read groups. Special value ' -1 ' stands for no group." RN^(a) encoding<byte[ ]> read names read names MF encoding<int> next mate bit flags see specific section NS encoding<int> "next fragment reference sequence id" reference sequence ids for the next fragment NP encoding<int> "next mate alignment start" alignment positions for the next fragment TS encoding<int> template size template sizes NF encoding<int> "distance to next fragment" number of records to skip to the next fragment ^(b) TL^(C) encoding<int> tag ids list of tag ids, see tag encoding section FN encoding<int> "number of read features" number of read features in each record FC encoding<byte> read features codes see separate section FP encoding<int> in-read positions "positions of the read features; a positive delta to the last position (starting with zero)" DL encoding<int> deletion lengths base-pair deletion lengths BB encoding<byte[]> stretches of bases bases QQ encoding<byte[ ]> "stretches of quality scores" quality scores BS encoding<byte> "base substitution codes" base substitution codes IN encoding<byte[]> insertion inserted bases RS encoding<int> reference skip length number of skipped bases for the ' N ' read feature PD encoding<int> padding number of padded bases HC encoding<int> hard clip number of hard clipped bases SC encoding<byte[ ]> soft clip soft clipped bases MQ encoding<int> mapping qualities mapping quality scores BA encoding<byte> bases bases QS encoding<byte> quality scores quality scores TC^(d) N/A legacy field to be ignored TN^(d) N/A legacy field to be ignored| Key | Value data type | Name | Value | | :---: | :---: | :---: | :---: | | BF | encoding<int> | BAM bit flags | see separate section | | CF | encoding<int> | CRAM bit flags | see specific section | | RI | encoding<int> | reference id | record reference id from the SAM file header | | RL | encoding<int> | read lengths | read lengths | | AP | encoding<int> | in-seq positions | if AP-Delta = true: 0-based alignment start <br> delta from the AP value in the previous record. <br> Note this delta may be negative, for example <br> when switching references in a multi-reference <br> slice. When the record is the first in the slice, the <br> previous position used is the slice alignment-start <br> field (hence the first delta should be zero for <br> single-reference slices, or the AP value itself for <br> multi-reference slices). <br> if AP-Delta = false: encodes the alignment start <br> position directly | | RG | encoding<int> | read groups | read groups. Special value ' -1 ' stands for no <br> group. | | $\mathrm{RN}^{\mathrm{a}}$ | encoding<byte[ ]> | read names | read names | | MF | encoding<int> | next mate bit flags | see specific section | | NS | encoding<int> | next fragment <br> reference sequence id | reference sequence ids for the next fragment | | NP | encoding<int> | next mate alignment <br> start | alignment positions for the next fragment | | TS | encoding<int> | template size | template sizes | | NF | encoding<int> | distance to next <br> fragment | number of records to skip to the next fragment ${ }^{b}$ | | $\mathrm{TL}^{\mathrm{C}}$ | encoding<int> | tag ids | list of tag ids, see tag encoding section | | FN | encoding<int> | number of read <br> features | number of read features in each record | | FC | encoding<byte> | read features codes | see separate section | | FP | encoding<int> | in-read positions | positions of the read features; a positive delta to <br> the last position (starting with zero) | | DL | encoding<int> | deletion lengths | base-pair deletion lengths | | BB | encoding<byte[]> | stretches of bases | bases | | QQ | encoding<byte[ ]> | stretches of quality <br> scores | quality scores | | BS | encoding<byte> | base substitution <br> codes | base substitution codes | | IN | encoding<byte[]> | insertion | inserted bases | | RS | encoding<int> | reference skip length | number of skipped bases for the ' N ' read feature | | PD | encoding<int> | padding | number of padded bases | | HC | encoding<int> | hard clip | number of hard clipped bases | | SC | encoding<byte[ ]> | soft clip | soft clipped bases | | MQ | encoding<int> | mapping qualities | mapping quality scores | | BA | encoding<byte> | bases | bases | | QS | encoding<byte> | quality scores | quality scores | | $\mathrm{TC}^{\mathrm{d}}$ | N/A | legacy field | to be ignored | | $\mathrm{TN}^{\mathrm{d}}$ | N/A | legacy field | to be ignored |

a a ^(a){ }^{a} 注意 RN 这是在 MF 之后解码的,如果记录与配对分离,并且我们正在尝试自动生成读取名称。


b b ^(b){ }^{\mathrm{b}} 计数在每个切片中重置,因此 NF 只能在该切片内引用后面的记录。


c c ^(c){ }^{c} TL 后面是按标签字典中出现的顺序解码标签值。


d TC d TC ^(d)TC{ }^{\mathrm{d}} \mathrm{TC} 和 TN 是来自 CRAM 1.0 的遗留数据系列。它们在 CRAM 3.0 中没有功能,不应存在。然而,一些实现确实输出它们,解码器必须默默跳过这些字段。TC 和 TN 包含任何数据值是非法的,尽管可能与它们相关联的块是空的。

 标签编码


标签字典(TD)描述了每个比对记录中出现的标签 ID / 类型的唯一组合。例如,如果我们搜索每个记录中存在的 ID / 类型,并且只找到两个组合 - X1:i BC:Z SA:Z: 和 X1:i: BC:Z - 那么我们在 TD 映射中就有两个字典条目。


L i = { T i 0 , T i 1 , , T i x } L i = T i 0 , T i 1 , , T i x L_(i)={T_(i0),T_(i1),dots,T_(ix)}L_{i}=\left\{T_{i 0}, T_{i 1}, \ldots, T_{i x}\right\} 成为记录 R i R i R_(i)R_{i} 的所有标签 ID 的列表,其中 i i ii 是顺序记录索引, T i j T i j T_(ij)T_{i j} 表示记录中的第 j j jj 个标签 ID。唯一的 L i L i L_(i)L_{i} 列表作为保留映射中的 TD 值存储。保持顺序对编码器不是必需的(因此称为“组合”),但这是允许的,因此应该支持不同的排列,每个排列在 TD 中用其自己的元素进行编码。TD 中的每个 L i L i L_(i)L_{i} 元素都分配一个从 0 开始的顺序整数。这些整数通过 TL 数据系列进行引用。使用 TD,可以将 TL 数据系列中的一个整数映射回标签 ID 列表。因此,对于每个对齐记录,我们只需要存储标签值,而不需要存储它们的 ID 和类型。


TD 被写成一个字节数组,由 L i L i L_(i)L_{i} 值用 0 0 \\0\backslash 0 分隔。每个 L i L i L_(i)L_{i} 值被写成 3 个字节 T i j T i j T_(ij)T_{i j} 元素的连接:标签 ID 后跟 BAM 标签类型代码(在 SAM 规范中描述的 A、c、C、s、S、i、I、f、Z、H 或 B 之一)。例如,标签列表 X1:i BC:Z SA:Z 和 X1:i BC:Z 的 TD 可以编码为 X1CBCZSAZ 0 X 1 CBCZ 0 0 X 1 CBCZ 0 \\0X1CBCZ\\0\backslash 0 \mathrm{X} 1 \mathrm{CBCZ} \backslash 0 ,其中 X1C 表示标签 X1 的 1 字节无符号值。

 标签值


不同标签使用的编码存储在一个映射中。键是由 BAM 标签 ID 和类型代码形成的 3 个字节,与上述描述的 TD 字典匹配。与数据系列编码映射不同,键以 ITF8 编码的整数形式存储在映射中,构造方式为(char 1 << 16 ) + ( 1 << 16 ) + ( 1<<16)+(1<<16)+( char 2 << 8 ) + 2 << 8 ) + 2<<8)+2<<8)+ type。例如,OQ:Z 的 3 字节表示为 { 0 x 4 F , 0 x 51 , 0 × 5 A } { 0 x 4 F , 0 x 51 , 0 × 5 A } {0x4F,0x51,0xx5A}\{0 \mathrm{x} 4 \mathrm{~F}, 0 \mathrm{x} 51,0 \times 5 \mathrm{~A}\} ,这些字节被解释为整数键 0 x 004 F 515 A,导致 ITF8 字节流 { 0 xE 0 , 0 x 4 F , 0 x 51 , 0 x 5 A } { 0 xE 0 , 0 x 4 F , 0 x 51 , 0 x 5 A } {0xE0,0x4F,0x51,0x5A}\{0 \mathrm{xE} 0,0 \mathrm{x} 4 \mathrm{~F}, 0 \mathrm{x} 51,0 \mathrm{x} 5 \mathrm{~A}\}
 关键  值数据类型  名称  

标签 ID 1:标签类型 1
 编码  读取标签 1

标签值(名称和类型在数据系列代码中可用)
tag values (names and types are available in the data series code)| tag values (names and types are | | :--- | | available in the data series code) |
dots\ldots dots\ldots dots\ldots

标签 ID N:标签类型 N
 编码  读取标签 N dots\ldots
Key Value data type Name Value TAG ID 1:TAG TYPE 1 encoding<byte[ ]> read tag 1 "tag values (names and types are available in the data series code)" dots dots dots TAG ID N:TAG TYPE N encoding<byte[]> read tag N dots| Key | Value data type | Name | Value | | :--- | :--- | :--- | :--- | | TAG ID 1:TAG TYPE 1 | encoding<byte[ ]> | read tag 1 | tag values (names and types are <br> available in the data series code) | | $\ldots$ | | $\ldots$ | $\ldots$ | | TAG ID N:TAG TYPE N | encoding<byte[]> | read tag N | $\ldots$ |

请注意,标签值被编码为字节数组。将标签值转换为字节数组及其反向转换的例程与 BAM 中的相同,唯一的区别是值类型被捕获在标签键中而不是值中。因此,类型 'C' 和 'c' 消耗 1 个字节,类型 'S' 和 's' 消耗 2 个字节,类型 'I'、'i' 和 'f' 消耗 4 个字节,而类型 ' H H HH '、' Z Z ZZ ' 和 ' B B BB ' 消耗可变数量的字节。


8.5 切片头块


切片头块从不压缩(块方法=原始)。对于参考映射读取,切片头还定义了与切片相关的数据块的参考序列上下文。映射读取可以与放置的未映射 3 3 ^(3){ }^{3} 读取存储在同一切片中的同一参考上。


带有多个参考标志(-2)设置为头部中的序列 ID 的切片可能包含映射到多个外部参考的读取,包括未映射的 3 3 ^(3){ }^{3} 读取(放置在这些参考上或未放置),但无法以这种方式组合多个嵌入的参考。当使用多个参考时,将使用 RI 数据系列来确定每个记录的参考序列 ID。当切片中仅使用单个参考时,此数据系列不存在。

头部中的未映射 (-1) 序列 ID 用于仅包含未放置的未映射 3 3 ^(3){ }^{3} 读取的切片。


一个包含不在任何序列中使用外部引用的数据切片可以将引用的 MD5 和设置为零。这可能是因为数据未映射或序列已逐字存储,而不是通过引用差异化。对于未排序或非坐标排序的数据,推荐使用后一种情况。

切片头块包含以下字段。
 数据类型  名称  
itf8  参考序列 ID

参考序列标识符或 -1 表示未映射的读取 -2 表示多个参考序列。此值必须与其封闭容器的值匹配。
reference sequence identifier or -1 for unmapped reads -2 for multiple reference sequences. This value must match that of its enclosing container.| reference sequence identifier or | | :--- | | -1 for unmapped reads | | -2 for multiple reference sequences. | | This value must match that of its enclosing | | container. |
itf8  对齐开始
对齐起始位置
itf8  对齐跨度
对齐的长度
itf8  记录数
切片中的记录数
ltf8  记录计数器

文件/流中记录的基于 1 的顺序索引
1-based sequential index of records in the file/stream| 1-based sequential index of records in the | | :--- | | file/stream |
itf8  块的数量
切片中的块数
itf8[]
嵌入式参考基块内容 ID

块内容的 ID,切片中块的内容 ID,用于嵌入引用序列的碱基,或 -1 表示无
block content ids of the blocks in the slice block content id for the embedded reference sequence bases or -1 for none| block content ids of the blocks in the slice | | :--- | | block content id for the embedded reference | | sequence bases or -1 for none |
itf8  参考 md5

切片边界内参考基因组的 MD5 校验和。如果该切片的参考序列 ID 为-1(未映射)或-2(多参考),则 MD5 应为 16 个字节的 0 0 \\0\backslash 0 。对于嵌入的参考,MD5 可以是全零或嵌入序列的 MD5。
MD5 checksum of the reference bases within the slice boundaries. If this slice has reference sequence id of -1 (unmapped) or -2 (multi-ref) the MD5 should be 16 bytes of \\0. For embedded references, the MD5 can either be all-zeros or the MD5 of the embedded sequence.| MD5 checksum of the reference bases within | | :--- | | the slice boundaries. If this slice has | | reference sequence id of -1 (unmapped) or -2 | | (multi-ref) the MD5 should be 16 bytes of $\backslash 0$. | | For embedded references, the MD5 can either | | be all-zeros or the MD5 of the embedded | | sequence. |
 字节[16]

一系列根据 BAM 辅助字段编码的标签、类型、值元组。
a series of tag,type,value tuples encoded as per BAM auxiliary fields.| a series of tag,type,value tuples encoded as | | :--- | | per BAM auxiliary fields. |
 字节[]  可选标签
Data type Name Value itf8 reference sequence id "reference sequence identifier or -1 for unmapped reads -2 for multiple reference sequences. This value must match that of its enclosing container." itf8 alignment start the alignment start position itf8 alignment span the length of the alignment itf8 number of records the number of records in the slice ltf8 record counter "1-based sequential index of records in the file/stream" itf8 number of blocks the number of blocks in the slice itf8[] embedded reference bases block content id "block content ids of the blocks in the slice block content id for the embedded reference sequence bases or -1 for none" itf8 reference md5 "MD5 checksum of the reference bases within the slice boundaries. If this slice has reference sequence id of -1 (unmapped) or -2 (multi-ref) the MD5 should be 16 bytes of \\0. For embedded references, the MD5 can either be all-zeros or the MD5 of the embedded sequence." byte[16] "a series of tag,type,value tuples encoded as per BAM auxiliary fields." byte[] optional tags | Data type | Name | Value | | :--- | :--- | :--- | | itf8 | reference sequence id | reference sequence identifier or <br> -1 for unmapped reads <br> -2 for multiple reference sequences. <br> This value must match that of its enclosing <br> container. | | itf8 | alignment start | the alignment start position | | itf8 | alignment span | the length of the alignment | | itf8 | number of records | the number of records in the slice | | ltf8 | record counter | 1-based sequential index of records in the <br> file/stream | | itf8 | number of blocks | the number of blocks in the slice | | itf8[] | embedded reference bases block content id | block content ids of the blocks in the slice <br> block content id for the embedded reference <br> sequence bases or -1 for none | | itf8 | reference md5 | MD5 checksum of the reference bases within <br> the slice boundaries. If this slice has <br> reference sequence id of -1 (unmapped) or -2 <br> (multi-ref) the MD5 should be 16 bytes of $\backslash 0$. <br> For embedded references, the MD5 can either <br> be all-zeros or the MD5 of the embedded <br> sequence. | | byte[16] | | a series of tag,type,value tuples encoded as <br> per BAM auxiliary fields. | | byte[] | optional tags | |

对齐开始和对齐跨度值仅在解码时使用,如果切片已映射数据对齐到单个参考(参考序列 ID >= 0 >= 0 >=0>=0 )。对于多参考切片或那些具有未映射数据的切片,建议将这些字段填充为值 0。

MD5 校验和不应在存储的校验和全为零时进行验证。嵌入的引用应遵循与 MD5 校验和计算之前对外部引用应用的相同大小写和字母顺序规则。如果使用了嵌入引用,并不要求它与用于序列比对的引用完全匹配。例如,它可能包含在覆盖缺失时的“N”碱基,或者对于 SNP 变异可能有不同的碱基调用。因此,当使用嵌入序列时,MD5 校验和指的是嵌入序列的校验和,不应与任何外部参考文件进行验证。


注意嵌入引用与用于对齐的原始引用之间的差异,MD 和 NM 标签可能需要逐字存储,以便在嵌入和外部引用子字符串不同的记录中使用。

可选标签的编码方式与 BAM 标签相同。即一系列二进制编码的标签连接在一起,每个标签由一个 2 字节的键(匹配[A-Za-z][A-Za-z0-9])后跟一个 1 字节的类型([AfZHcCsSiIB]),然后是由类型定义格式的字节字符串。


以大写字母开头的标签是保留的,而小写字母开头的标签或以 X , Y X , Y X,Y\mathrm{X}, \mathrm{Y} 或 Z 开头的标签是用户可定义的。任何解码器无法理解的标签应被跳过,而不产生错误。


目前没有定义任何标签。


8.6 核心数据块


核心数据块是一个比特流(最高有效位优先),由一个或多个 CRAM 记录的数据组成。请注意,一个字节可以容纳多个 CRAM 记录,因为最小的 CRAM 记录可能只有几位长。核心数据块具有以下字段:
 数据类型  名称  
 位[ ]  CRAM 记录 1
第一个 CRAM 记录
dots\ldots dots\ldots dots\ldots
 位[ ]  CRAM 记录 N
第 N 个 CRAM 记录
Data type Name Value bit[ ] CRAM record 1 The first CRAM record dots dots dots bit[ ] CRAM record N The Nth CRAM record| Data type | Name | Value | | :--- | :--- | :--- | | bit[ ] | CRAM record 1 | The first CRAM record | | $\ldots$ | $\ldots$ | $\ldots$ | | bit[ ] | CRAM record N | The Nth CRAM record |


8.7 外部数据块


核心数据块与外部数据块之间的关系如下面的图片所示:

图 5:核心编码与外部编码之间的关系,以及核心数据块与外部数据块之间的关系。


图片显示了一个 CRAM 记录(左侧)是如何通过核心或外部编码在核心数据块和一个或多个外部数据块之间分配的。所呈现的具体编码仅为示例,旨在说明。主要目的是区分核心位编码,其输出始终存储在核心数据块中,以及外部字节编码,其输出始终存储在外部数据块中。


9 文件结束容器


一个特殊的容器用于标记文件或流的结束。它在版本 3 或更高版本中是必需的。这个想法是提供一种简单快捷的方法来检测 CRAM 文件或流是否完整。该标记基本上是一个空容器,参考序列 ID 设置为-1(未对齐),对齐起始位置设置为 4542278。


这里是 EOF 容器的完整内容,详细解释如下:
 十六进制字节  数据类型  十进制值  字段名称
 容器头部
 000000 的  整数 15
块数据的大小

ff ff ff ff 的
itf8 -1  参考序列 ID
e0 45 4f 46 itf8 4542278  对齐开始
00 itf8 0  对齐跨度
00 itf8 0  记录数
00 itf8 0  全局记录计数器
00 itf8 0  基础
01 itf8 1  块计数
00  数组 0  地标
05 bd d 94 f  整数 1339669765  容器头 CRC32

压缩头块
00  字节  0 (原始)  压缩方法
01  字节  1 (压缩头)  块内容类型
00 itf8 0  块内容 ID
06 itf8 6  压缩大小
06 itf8 6  未压缩大小
 压缩头部
01 itf8 1
保留映射字节大小
00 itf8 0  保留地图大小
01 itf8 1
编码映射字节大小
00 itf8 0  编码映射大小
01 itf8 1
标签编码字节大小
00 itf8 0
标签编码映射大小
ee 63014 b  整数 1258382318  块 CRC32
hex bytes data type decimal value field name Container header Of 000000 integer 15 size of blocks data ff ff ff ff of itf8 -1 ref seq id e0 45 4f 46 itf8 4542278 alignment start 00 itf8 0 alignment span 00 itf8 0 number of records 00 itf8 0 global record counter 00 itf8 0 bases 01 itf8 1 block count 00 array 0 landmarks 05 bd d 94 f integer 1339669765 container header CRC32 Compression header block 00 byte 0 (RAW) compression method 01 byte 1 (COMPRESSION_HEADER) block content type 00 itf8 0 block content id 06 itf8 6 compressed size 06 itf8 6 uncompressed size Compression header 01 itf8 1 preservation map byte size 00 itf8 0 preservation map size 01 itf8 1 encoding map byte size 00 itf8 0 encoding map size 01 itf8 1 tag encoding byte size 00 itf8 0 tag encoding map size ee 63014 b integer 1258382318 block CRC32| hex bytes | data type | decimal value | field name | | :---: | :---: | :---: | :---: | | Container header | | | | | Of 000000 | integer | 15 | size of blocks data | | ff ff ff ff of | itf8 | -1 | ref seq id | | e0 45 4f 46 | itf8 | 4542278 | alignment start | | 00 | itf8 | 0 | alignment span | | 00 | itf8 | 0 | number of records | | 00 | itf8 | 0 | global record counter | | 00 | itf8 | 0 | bases | | 01 | itf8 | 1 | block count | | 00 | array | 0 | landmarks | | 05 bd d 94 f | integer | 1339669765 | container header CRC32 | | Compression header block | | | | | 00 | byte | 0 (RAW) | compression method | | 01 | byte | 1 (COMPRESSION_HEADER) | block content type | | 00 | itf8 | 0 | block content id | | 06 | itf8 | 6 | compressed size | | 06 | itf8 | 6 | uncompressed size | | Compression header | | | | | 01 | itf8 | 1 | preservation map byte size | | 00 | itf8 | 0 | preservation map size | | 01 | itf8 | 1 | encoding map byte size | | 00 | itf8 | 0 | encoding map size | | 01 | itf8 | 1 | tag encoding byte size | | 00 | itf8 | 0 | tag encoding map size | | ee 63014 b | integer | 1258382318 | block CRC32 |

当编译在一起时,EOF 标记长度为 38 字节,十六进制表示为:Of 000000 ff ff ff ff of e0 454 f 4600000000010005 bd d9 4f 0001000606010001000100 ee 6301 4b

 10 记录结构


CRAM 记录基于 SAM 记录,但具有额外的功能,允许更高效的数据存储。与 BAM 记录相比,CRAM 记录使用位和字节进行数据存储。这样,例如,可以直接在 CRAM 中使用输出可变长度二进制代码的各种编码技术。另一方面,不需要二进制编码的数据序列可以单独存储在外部块中,并对它们应用其他压缩。


由于 CRAM 数据系列可能在同一块内交错 4 4 ^(4){ }^{4} ,理解 CRAM 数据系列必须解码的顺序至关重要。

整体流程图如下,后续部分有更详细的描述。

 10.1 CRAM 记录


映射和未映射的读取都以以下字段开始。请注意,数据系列类型指的是逻辑数据类型,而数据系列名称对应于数据系列编码映射。
 数据系列类型
Data series type| Data series | | :--- | | type |
 数据系列名称
Data series name| Data series | | :--- | | name |
 字段  描述
 整数 BF  BAM 位标志
请参见下面的 BAM 位标志
 整数 CF  CRAM 位标志
请参见下面的 CRAM 位标志
- -  位置信息  请参见第 10.2 节
- -  读取名称  请参见第 10.3 节
- -  配对记录  请参见第 10.4 节
- -  辅助标签  请参见第 10.5 节
- -  序列
请参见第 10.6 节和第 10.7 节
"Data series type" "Data series name" Field Description int BF BAM bit flags see BAM bit flags below int CF CRAM bit flags see CRAM bit flags below - - Positional data See section 10.2 - - Read names See section 10.3 - - Mate records See section 10.4 - - Auxiliary tags See section 10.5 - - Sequences See sections 10.6 and 10.7| Data series <br> type | Data series <br> name | Field | Description | | :--- | :--- | :--- | :--- | | int | BF | BAM bit flags | see BAM bit flags below | | int | CF | CRAM bit flags | see CRAM bit flags below | | - | - | Positional data | See section 10.2 | | - | - | Read names | See section 10.3 | | - | - | Mate records | See section 10.4 | | - | - | Auxiliary tags | See section 10.5 | | - | - | Sequences | See sections 10.6 and 10.7 |


BAM 位标志 (BF 数据系列)


以下标志是从 SAM 和 BAM 规范中复制的,具有相同的含义。然而,请注意,其中一些标志可以在解码过程中推导出来,因此可能在 CRAM 文件中被省略,并且基于同一切片内的成对文库的两个读取计算位。
 位标志  评论  描述
0x1

模板具有多个序列段
template having multiple segments in sequencing| template having multiple | | :--- | | segments in sequencing |
0x2

每个段落根据对齐器正确对齐
each segment properly aligned according to the aligner| each segment properly aligned | | :--- | | according to the aligner |
0x4  段未映射 a a ^(a){ }^{\mathrm{a}}
0x8

计算 b b ^(b)^{\mathrm{b}} 或存储在 themate 的信息中
calculated ^(b) or stored in the mate's info| calculated $^{\mathrm{b}}$ or stored in the | | :--- | | mate's info |

下一个段落在模板中未映射
next segment in template unmapped| next segment in template | | :--- | | unmapped |
0x10

SEQ 被反向互补
SEQ being reverse complemented| SEQ being reverse | | :--- | | complemented |
0 × 20 0 × 20 0xx200 \times 20

计算 b b ^(b)^{\mathrm{b}} 或存储在 themate 的信息中
calculated ^(b) or stored in the mate's info| calculated $^{\mathrm{b}}$ or stored in the | | :--- | | mate's info |

模板中下一个片段的 SEQ 被反向互补
SEQ of the next segment in the template being reverse complemented| SEQ of the next segment in the | | :--- | | template being reverse | | complemented |
0x40
模板中的第一个部分 c c ^(c){ }^{\mathrm{c}}
0x80
模板中的最后一个段落 c c ^(c){ }^{\mathrm{c}}
0x100  次级对齐
0x200
未通过质量控制
0x400
PCT 或光学副本
0x800  补充对齐
Bit flag Comment Description 0x1 "template having multiple segments in sequencing" 0x2 "each segment properly aligned according to the aligner" 0x4 segment unmapped ^(a) 0x8 "calculated ^(b) or stored in the mate's info" "next segment in template unmapped" 0x10 "SEQ being reverse complemented" 0xx20 "calculated ^(b) or stored in the mate's info" "SEQ of the next segment in the template being reverse complemented" 0x40 the first segment in the template ^(c) 0x80 the last segment in the template ^(c) 0x100 secondary alignment 0x200 not passing quality controls 0x400 PCT or optical duplicate 0x800 Supplementary alignment| Bit flag | Comment | Description | | :---: | :---: | :---: | | 0x1 | | template having multiple <br> segments in sequencing | | 0x2 | | each segment properly aligned <br> according to the aligner | | 0x4 | | segment unmapped ${ }^{\mathrm{a}}$ | | 0x8 | calculated $^{\mathrm{b}}$ or stored in the <br> mate's info | next segment in template <br> unmapped | | 0x10 | | SEQ being reverse <br> complemented | | $0 \times 20$ | calculated $^{\mathrm{b}}$ or stored in the <br> mate's info | SEQ of the next segment in the <br> template being reverse <br> complemented | | 0x40 | | the first segment in the template ${ }^{\mathrm{c}}$ | | 0x80 | | the last segment in the template ${ }^{\mathrm{c}}$ | | 0x100 | | secondary alignment | | 0x200 | | not passing quality controls | | 0x400 | | PCT or optical duplicate | | 0x800 | | Supplementary alignment |

a a ^(a){ }^{a} 位 0 x 4 是判断读取是否未映射的唯一可靠位置。如果设置了 0 x 4,则不能对位 0 × 2 , 0 × 100 0 × 2 , 0 × 100 0xx2,0xx1000 \times 2,0 \times 100 0 x 800 0 x 800 0x 8000 x 800 做出任何假设。


b b ^(b){ }^{\mathrm{b}} 对于同一切片内的段。


c ^("c "){ }^{\text {c }} 位 0 x 40 和 0 x 80 反映了在所使用的测序技术中每个模板内的读取顺序,这可能与实际的映射方向无关。如果 0 × 40 0 × 40 0xx400 \times 40 0 × 80 0 × 80 0xx800 \times 80 都被设置,则该读取是线性模板的一部分(即模板序列预计是线性顺序),但它既不是第一个读取也不是最后一个读取。如果 0 x 40 和 0 x 80 都未设置,则模板中读取的索引是未知的。这可能发生在非线性模板(例如通过拼接其他模板构建的模板)中,或者在数据处理过程中丢失了此信息。


CRAM 位标志 (CF 数据系列)


CRAM 位标志(也称为压缩位标志)以整数形式表示 CF 数据系列。为每个 CRAM 读取记录定义了以下压缩标志:
 位标志  名称  描述
0x1
质量分数存储为数组

质量分数可以作为读取特征存储,也可以作为类似于读取碱基的数组存储。
quality scores can be stored as read features or as an array similar to read bases.| quality scores can be stored as read features or as an | | :--- | | array similar to read bases. |
0x2  分离的

配对信息被逐字存储(例如,因为该配对跨越多个切片或字段与 CRAM 计算方法不同)
mate information is stored verbatim (e.g. because the pair spans multiple slices or the fields differ to the CRAM computed method)| mate information is stored verbatim (e.g. because the | | :--- | | pair spans multiple slices or the fields differ to the | | CRAM computed method) |
0 x 4  有配偶下游

告诉是否应该在流中进一步期待下一个段落
tells if the next segment should be expected further in the stream| tells if the next segment should be expected further in | | :--- | | the stream |
0x8
解码序列为 "*"

告知解码器该序列未知,并且任何编码的参考差异仅存在于重建 CIGAR 字符串。
informs the decoder that the sequence is unknown and that any encoded reference differences are present only to recreate the CIGAR string.| informs the decoder that the sequence is unknown and | | :--- | | that any encoded reference differences are present only | | to recreate the CIGAR string. |
Bit flag Name Description 0x1 quality scores stored as array "quality scores can be stored as read features or as an array similar to read bases." 0x2 detached "mate information is stored verbatim (e.g. because the pair spans multiple slices or the fields differ to the CRAM computed method)" 0 x 4 has mate downstream "tells if the next segment should be expected further in the stream" 0x8 decode sequence as "*" "informs the decoder that the sequence is unknown and that any encoded reference differences are present only to recreate the CIGAR string."| Bit flag | Name | Description | | :--- | :--- | :--- | | 0x1 | quality scores stored as array | quality scores can be stored as read features or as an <br> array similar to read bases. | | 0x2 | detached | mate information is stored verbatim (e.g. because the <br> pair spans multiple slices or the fields differ to the <br> CRAM computed method) | | 0 x 4 | has mate downstream | tells if the next segment should be expected further in <br> the stream | | 0x8 | decode sequence as "*" | informs the decoder that the sequence is unknown and <br> that any encoded reference differences are present only <br> to recreate the CIGAR string. |

以下伪代码描述了解码整个 CRAM 记录的一般过程。序列数据本身根据记录是否对齐(映射)采用两种编码格式之一。

 解码伪代码

procedure DECODERECORD
        \(B A M \_\)flags \(\leftarrow\) READITEM(BF, Integer)
        \(C R A \bar{M} \_\)flags \(\leftarrow\) READITEM \((\mathrm{CF}\), Integer \()\)
        DECODEPoSITIONS \(\triangleright\) See section 10.2
        DECODENAMES \(\triangleright\) See section 10.3
        DECODEMateData \(\triangleright\) See section 10.4
        DecoDeTaGData \(\triangleright\) See section 10.5
        if \((B F\) AND 4\()=0\) then \(\triangleright\) Unmapped flag
            DECODEMAPPEDREAD \(\triangleright\) See section 10.6
        else
            DECODEUNMAPPEDREAD \(\triangleright\) See section 10.7
        end if
end procedure

此伪代码并不旨在成为一个完全可实现的编程语言,而是作为 CRAM 解码的顺序和结构的算法指导。


上述提到的 Readitem 函数接受两个参数;数据系列名称和编码使用的数据类型。它将使用容器压缩头中指定的编解码器从该数据系列中检索下一个值。请注意,每个数据系列仅允许一种数据类型,因此第二个参数是多余的,仅作为备忘。


10.2 CRAM 位置数据


在位元组 BAM 和 CRAM 标志之后,CRAM 编码位置相关数据,包括参考、比对位置和长度,以及读取组。位置数据存储在已比对和未比对的序列中,因为未比对的数据仍然可以在基因组中的特定位置“放置”(而不进行比对)。通常,这样做是为了在一对序列(成对末端或配对序列库)中保持它们在一起,当其中一个序列比对而另一个不比对时。

对于存储在位置排序切片中的读取,压缩头部保留映射中的 AP-delta 标志应被设置,AP 数据系列将进行增量编码,使用切片对齐起始值作为增量的第一个位置。请注意,对于多参考切片,这可能意味着 AP 系列包含负值,例如在从一个参考序列的对齐末尾移动到下一个参考序列的起始位置或未映射未放置数据时。当 AP-delta 标志未设置时,AP 数据系列将作为普通整数值存储。
 数据系列类型
Data series type| Data series | | :--- | | type |
 数据系列名称
Data series name| Data series | | :--- | | name |
 字段  描述
 整数 RI  引用 ID

参考序列 ID(仅在多参考切片中存在)
reference sequence id (only present in multiref slices)| reference sequence id (only present in | | :--- | | multiref slices) |
 整数 RL  读取长度
读取的长度
 整数 AP  对齐开始
对齐起始位置
 整数 RG  读取组

在头部中以 Nh 记录表示的读取组标识符,从 0 开始,-1 表示没有组
the read group identifier expressed as the Nh record in the header, starting from 0 with -1 for no group| the read group identifier expressed as | | :--- | | the Nh record in the header, starting | | from 0 with -1 for no group |
"Data series type" "Data series name" Field Description int RI ref id "reference sequence id (only present in multiref slices)" int RL read length the length of the read int AP alignment start the alignment start position int RG read group "the read group identifier expressed as the Nh record in the header, starting from 0 with -1 for no group"| Data series <br> type | Data series <br> name | Field | Description | | :--- | :--- | :--- | :--- | | int | RI | ref id | reference sequence id (only present in <br> multiref slices) | | int | RL | read length | the length of the read | | int | AP | alignment start | the alignment start position | | int | RG | read group | the read group identifier expressed as <br> the Nh record in the header, starting <br> from 0 with -1 for no group |
procedure DECODEPOSITIONS
    if slice_header.reference_sequence_id \(=-2\) then
        reference \(\_i d \leftarrow\) READITEM(RI, Integer)
    else
        \(r e f e r e n c e \_i d \leftarrow\) slice_header.reference_sequence_id
    end if
    read_length \(\leftarrow\) READITEM(RL, Integer)
    if container_pmap.AP_delta \(\neq 0\) then
            if first_record_in_slice then
            last_position \(\leftarrow\) slice_header.alignment_start
            end if
            alignment_position \(\leftarrow\) READITEM(AP, Integer) + last_position
            last_position \(\leftarrow\) alignment_position
        else
            alignment_position \(\leftarrow\) READITEM(AP, Integer)
        end if
        read_group \(\leftarrow\) READITEM \((\) RG, Integer \()\)
    end procedure


10.3 读取名称(RN 数据系列)


读取名称可以在 CRAM 格式中保留,但这是可选的,并由容器压缩头中的 RN 保留映射键控制。请参见第 8.4 节。当读取名称未被保留时,CRAM 解码器应生成名称,通常基于文件名和使用切片头块的记录计数器字段的读取的数字 ID。请注意,即使 RN 压缩头键指示相反,读取名称仍可能被保留,例如当读取是读取对的一部分,并且该对跨越多个切片。在这种情况下,记录将标记为分离(请参见 CF 数据系列),下面的配对数据(第 10.4 节)将包含读取名称。
 数据系列类型
Data series type| Data series | | :--- | | type |
 数据系列名称
Data series name| Data series | | :--- | | name |
 字段  描述
 字节[ ] ] ]] ] RN  读取名称  读取名称
"Data series type" "Data series name" Field Description byte[ ] RN read names read names| Data series <br> type | Data series <br> name | Field | Description | | :--- | :--- | :--- | :--- | | byte[ $]$ | RN | read names | read names |
procedure DECODENAMES
        if container_pmap.read_names_included \(=1\) then
            read_name \(\leftarrow\) REAd \(\overline{\operatorname{ITEM}}(\mathrm{RN}\), Byte[])
        else
            read_name \(\leftarrow\) GENERATENAME
        end if
end procedure


10.4 Mate 记录


在 CRAM 中,有两种方式可以保留配对信息。如果下一个片段不在同一切片中,我们会逐字存储插入大小、配对参考染色体和位置以及配对标志的副本。


(映射状态,方向)对于两个记录。在这种情况下,两个记录在 CF 数据系列中都标记为“分离”,使用位 2。


如果这个片段和下一个片段在同一个切片内,我们可以通过比较这两个记录来推导出很多信息。上游记录的 CF 位 4(配对下游)标志被设置,并存储了在这个记录和该模板上下一个片段的记录之间要跳过的记录数(在 NF 数据系列中),零表示下一个片段也是下一个记录。下游记录既没有设置 CF 位 2(分离)也没有设置 CF 位 4(配对下游),也不使用 NF 数据系列(除非它还有一个额外的“下一个片段”可供参考)。

不强制使用这种去重方法,选择性地,CRAM 写入实现可能希望将数据标记为分离,即使模板的所有记录都位于同一切片中。这样做的一个原因可能是为了保留不一致的数据,以便它能够以完整的保真度在 CRAM 格式中往返传输。
 数据系列类型
Data series type| Data series | | :--- | | type |
 数据系列名称  描述
 整数 NF
跳过到下一个片段的记录数
"Data series type" Data series name Description int NF the number of records to skip to the next fragment| Data series <br> type | Data series name | Description | | :--- | :--- | :--- | | int | NF | the number of records to skip to the next fragment |

在上述情况下,两个记录的 NS(配对参考名称)、NP(配对位置)和 TS(模板大小)字段应在配对也被解码后得出。配对参考名称和位置显而易见,直接从配对中复制。模板大小是使用 SAM 规范中描述的方法计算的;从最左侧到最右侧映射碱基的包含距离,最左侧记录的符号为正,最右侧记录的符号为负。


如果在此切片中未找到下一个片段,则以下结构将包含在 CRAM 记录中。请注意,在某些情况下,同一切片中的读对可能被标记为分离,并使用此结构,例如存储与 CRAM 用于动态计算配对数据的算法不匹配的配对信息。
 数据系列类型
Data series type| Data series | | :--- | | type |
 数据系列名称  描述
 整数 MF
下一个伙伴位标志,请参见下表
 字节[] RN
读取名称(仅在尚不知晓时)
 整数 NS
配对参考序列标识符
 整数 NP
配对对齐起始位置
 整数 TS
模板的大小(插入大小)
"Data series type" Data series name Description int MF next mate bit flags, see table below byte[] RN the read name (if and only if not known already) int NS mate reference sequence identifier int NP mate alignment start position int TS the size of the template (insert size)| Data series <br> type | Data series name | Description | | :--- | :--- | :--- | | int | MF | next mate bit flags, see table below | | byte[] | RN | the read name (if and only if not known already) | | int | NS | mate reference sequence identifier | | int | NP | mate alignment start position | | int | TS | the size of the template (insert size) |


下一个配对位标志(MF 数据系列)


下一个 mate 位标志以整数形式表示 MF 数据系列。这些表示我们从 BF 数据系列中排除的缺失位(与完整的 SAM/BAM 标志相比)。以下位标志被定义:
 位标志  名称  描述
0x1
配对负链位

如果配对在负链上,则位被设置
0 × 2 0 × 2 0xx20 \times 2  配对未映射位
如果配对未映射,则位被设置
Bit flag Name Description 0x1 mate negative strand bit the bit is set if the mate is on the negative strand 0xx2 mate unmapped bit the bit is set if the mate is unmapped| Bit flag | Name | Description | | :--- | :--- | :--- | | 0x1 | mate negative strand bit | the bit is set if the mate is on the negative strand | | $0 \times 2$ | mate unmapped bit | the bit is set if the mate is unmapped |

 解码配对伪代码


在以下伪代码中,我们假设当前记录是这个,它的配对是 next_frag。


过程 DECODEMATEDATA


如果 C F C F CFC F 和 2 那么 \triangleright 已与配偶断开连接


mate_flags larr\leftarrow 读取项(MF, 整数)


如果 mate_flags 和 1 那么


bam_flags larr\leftarrow bam_flags 或 0 × 20 0 × 20 0xx20quad▹0 \times 20 \quad \triangleright 配对是反向互补的

 结束如果

如果 mate_flags 和 2 那么


bam_flags larr\leftarrow bam_flags OR 0x08 \triangleright 配对未映射

 结束如果

如果 container_pmap.read_names_included 1 1 !=1\neq 1 那么

r e a d _ n a m e ←← READITEM ( RN , B y t e [ ] ) r e a d _ n a m e ¯ ←← READITEM ( RN , B y t e ¯ [ ] ) read_na bar(me)larr larr READITEM(RN, bar(Byte)[])r e a d \_n a \overline{m e} \leftarrow \leftarrow \operatorname{READITEM}(\mathrm{RN}, \overline{B y t e}[])
    end if
    mate_ref_id \leftarrow READITEM(NS, Integer)
    mate_position \leftarrow READITEM(NP, Integer)
    template_size \leftarrow READITEM(TS, Integer)
    else if CF ANND 4 then }\quad\triangleright\mathrm{ Mate is downstream
    if next_frag.bam_flags AND 0x10 then
        this.bam_flags \leftarrowthis.bam_flags OR 0x20 \triangleright next segment reverse complemented
    end if
    if next_frag.bam_flags AND 0x04 then
        this.bam_flags \leftarrowthis.bam_flags OR 0x08 \triangleright next segment unmapped
    end if
    next_frag \leftarrow READITEM(NF,Integer)
    next_record \leftarrowthis_record + next_frag + 1
    Resolve mate_ref_-id for this_record and next_record once both have been decoded
    Resolve mate_position for this_record and next_record once both have been decoded
    Find leftmost and rightmost mapped coordinate in records this_record and next_record.
    For leftmost of this_record and next_record: template_size \leftarrow rightmost - leftmost + 1
    For rightmost of this_record and next_record: template_size }\leftarrow-(\mathrm{ rightmost - leftmost + 1)
        end if
end procedure

注意,与 SAM 规范一样,模板可能允许有超过两个的比对记录。在这种情况下,每个记录的“配对”被视为下一个记录,最后一个记录的配对是第一个记录,从而形成一个循环列表。上述算法是一个简化版本,没有处理这种情况。完整的方法需要观察当记录 + N F + N F +NF+N F 也被标记为在下游有额外的配对时。一种推荐的方法是在第二次遍历中解析配对信息,一旦整个切片被解码。配对链中的最后一个段需要根据第一个段相应地设置 bam_flags 字段 0x20 和 0x08。这在上述算法中也没有列出,以简洁为主。

 10.5 辅助标签


标签使用标签行(TL 数据系列)整数编码到标签字典中(压缩头保留映射中的 TD 字段,参见第 8.4 节)。有关此过程的更详细描述,请参见第 8.4 节。
 数据系列类型
Data series type| Data series | | :--- | | type |
 数据系列名称
Data series name| Data series | | :--- | | name |
 字段  描述
 整数 TL  标签行
一个索引到标签字典(TD)
*** ? ? ? ? ? ? ???? ? ?  标签名称/类型

3 个字符的键 ( 2 ( 2 (2(2 标签标识符和 1 个标签类型 ) , ) , ),), ,如标签字典所指定
3 character key (2 tag identifier and 1 tag type ), as specified by the tag dictionary| 3 character key $(2$ tag identifier and 1 tag | | :--- | | type $),$ as specified by the tag dictionary |
"Data series type" "Data series name" Field Description int TL tag line an index into the tag dictionary (TD) ** ??? tag name/type "3 character key (2 tag identifier and 1 tag type ), as specified by the tag dictionary"| Data series <br> type | Data series <br> name | Field | Description | | :--- | :--- | :--- | :--- | | int | TL | tag line | an index into the tag dictionary (TD) | | $*$ | $? ? ?$ | tag name/type | 3 character key $(2$ tag identifier and 1 tag <br> type $),$ as specified by the tag dictionary |
procedure DECODETAGDATA
        tag_line \(\leftarrow\) READITEM(TL,Integer)
        for all ele \(\in\) container_pmap.tag_dict(tag_line) do
            name \(\leftarrow\) first two characters of ele
            tag \((\) type \() \leftarrow\) last character of ele
            \(\operatorname{tag}(\) name \() \leftarrow\) READITEM \((\) ele, Byte[])
        end for
end procedure

在上述过程中,name 是一个两个字母的标签名,type 是 SAM/BAM 规范中记录的允许类型之一。类型包括 A(单个字符)、c(有符号 8 位整数)、C(无符号 8 位整数)、s(有符号 16 位整数)、S(无符号 16 位整数)、i(有符号 32 位整数)、I(无符号 32 位整数)、f(32 位浮点数)、Z(以 null 结尾的字符串)、H(以 null 结尾的十六进制数字字符串)和 B(以数组格式的二进制数据,第一字节为 c、C、s、S、i、I、f 中的一个,后跟一个 32 位整数表示数组元素的数量,随后是使用指定格式编码的数组数据)。所有整数均为小端编码。


例如,一个 SAM 标签 MQ: i 具有名称 MQ 和类型 i,并将根据整数值的大小和符号使用 MQc、MQC、MQs、MQS、MQi 和 MQI 数据系列之一进行解码。

注意,在解码过程中可以自动创建一些辅助标签,因此编码器可以选择性地将其删除。然而,如果解码器发现一个标签以逐字形式存储,它应该优先使用这个标签,而不是自动计算值。


如果读取组(RG 数据系列)值不是 -1,则应创建 RG(读取组)辅助标签。


MD 和 NM 辅助标签存储序列与参考之间的差异(编辑字符串)以及不匹配的数量。这些标签可以在基于参考的序列重建过程中动态创建,并应与 SAMtags 文档中提供的描述相匹配。当未使用参考或自动构建的值与输入数据不同的情况下,编码器可以决定逐字存储这些标签。


请注意,没有机制来描述哪些记录具有 MD/NM,哪些没有。如果这被认为很重要,唯一的解决办法是逐字存储所有 MD 和 NM,并请求解码软件对于没有存储 MD 和 NM 标签的记录不要自动生成自己的标签。

 10.6 映射读取

 读取特性记录


读取特征用于存储使用读取坐标表示的读取细节(例如,相对于参考序列的碱基差异)。读取特征记录以读取特征的数量开始,后面是读取特征本身。每个读取特征的位置编码为自上一个特征位置以来的距离,或者对于第一个特征的绝对位置(即与零的差异)。最后,存储单一映射质量和每碱基质量分数。
 数据系列类型
 数据系列名称
Data series name| Data series | | :--- | | name |
 字段  描述
 整数 FN

读取特征的数量
number of read features| number of read | | :--- | | features |

读取特征的数量
 整数 FP  在读取位置 a a ^(a)^{\mathrm{a}}
读取特征的增量位置
 字节 FC  读取功能代码
请参见下面的功能代码
*** ***  读取特征数据 a a ^(a){ }^{\mathrm{a}}
请参见下面的功能代码
 整数 MQ  映射质量  映射质量分数
 字节[读取长度] QS  质量分数
基础品质,如果保持
Data series type "Data series name" Field Description int FN "number of read features" the number of read features int FP in-read-position ^(a) delta-position of the read feature byte FC read feature code See feature codes below ** ** read feature data ^(a) See feature codes below int MQ mapping qualities mapping quality score byte[read length] QS quality scores the base qualities, if preserved| Data series type | Data series <br> name | Field | Description | | :--- | :--- | :--- | :--- | | int | FN | number of read <br> features | the number of read features | | int | FP | in-read-position $^{\mathrm{a}}$ | delta-position of the read feature | | byte | FC | read feature code | See feature codes below | | $*$ | $*$ | read feature data ${ }^{\mathrm{a}}$ | See feature codes below | | int | MQ | mapping qualities | mapping quality score | | byte[read length] | QS | quality scores | the base qualities, if preserved |

a a ^(a){ }^{a} 重复 FN 次,每次读取特征一次。

 读取功能代码


每个功能代码都有其相关的数据系列,其中包含特定于该功能的进一步信息。以下代码用于区分读取坐标的变体:
 功能代码  标识符
 数据系列类型
Data series type| Data series | | :--- | | type |
 数据系列名称
Data series name| Data series | | :--- | | name |
 描述
 基础 b (0x62)  字节[ BB
一段基础
 分数 q (0x71)  字节[ QQ
一段分数
 读取基础 B (0x42)  字节,字节 BA,QS

一个基础及相关的质量分数
A base and associated quality score| A base and associated quality | | :--- | | score |
 替代 X (0x58)  字节 BS

基本替换代码,SAM 操作符 X , M X , M X,M\mathrm{X}, \mathrm{M} = = ==
base substitution codes, SAM operators X,M and =| base substitution codes, SAM | | :--- | | operators $\mathrm{X}, \mathrm{M}$ and $=$ |
 插入  我 (0x49)  字节[] IN

插入的碱基,SAM 操作符 I
inserted bases, SAM operator I| inserted bases, SAM operator | | :--- | | I |
 删除 D (0x44)  整数 DL

删除的碱基数量,SAM 操作符 D
number of deleted bases, SAM operator D| number of deleted bases, | | :--- | | SAM operator D |
 插入基础 i (0x69)  字节 BA

单插入基,SAM 操作符 I
single inserted base, SAM operator I| single inserted base, SAM | | :--- | | operator I |
 质量得分 Q (0x51)  字节 QS  单一质量分数
 参考跳过 N (0x4E)  整数 RS

跳过的碱基数,SAM 操作符 N
number of skipped bases, SAM operator N| number of skipped bases, | | :--- | | SAM operator N |
 软剪辑 S (0x53)  字节[] SC

软剪切碱基,SAM 操作符 S
soft clipped bases, SAM operator S| soft clipped bases, SAM | | :--- | | operator S |
 填充 P ( 0 × 50 ) P ( 0 × 50 ) P(0xx50)\mathrm{P}(0 \times 50)  整数 PD

填充碱基的数量,SAM 操作符 P
number of padded bases, SAM operator P| number of padded bases, | | :--- | | SAM operator P |
 硬剪辑 H (0x48)  整数 HC

硬剪切碱基的数量,SAM 操作符 H
number of hard clipped bases, SAM operator H| number of hard clipped bases, | | :--- | | SAM operator H |
Feature code Id "Data series type" "Data series name" Description Bases b (0x62) byte[ BB a stretch of bases Scores q (0x71) byte[ QQ a stretch of scores Read base B (0x42) byte,byte BA,QS "A base and associated quality score" Substitution X (0x58) byte BS "base substitution codes, SAM operators X,M and =" Insertion I (0x49) byte[] IN "inserted bases, SAM operator I" Deletion D (0x44) int DL "number of deleted bases, SAM operator D" Insert base i (0x69) byte BA "single inserted base, SAM operator I" Quality score Q (0x51) byte QS single quality score Reference skip N (0x4E) int RS "number of skipped bases, SAM operator N" Soft clip S (0x53) byte[] SC "soft clipped bases, SAM operator S" Padding P(0xx50) int PD "number of padded bases, SAM operator P" Hard clip H (0x48) int HC "number of hard clipped bases, SAM operator H"| Feature code | Id | Data series <br> type | Data series <br> name | Description | | :---: | :---: | :---: | :---: | :---: | | Bases | b (0x62) | byte[ | BB | a stretch of bases | | Scores | q (0x71) | byte[ | QQ | a stretch of scores | | Read base | B (0x42) | byte,byte | BA,QS | A base and associated quality <br> score | | Substitution | X (0x58) | byte | BS | base substitution codes, SAM <br> operators $\mathrm{X}, \mathrm{M}$ and $=$ | | Insertion | I (0x49) | byte[] | IN | inserted bases, SAM operator <br> I | | Deletion | D (0x44) | int | DL | number of deleted bases, <br> SAM operator D | | Insert base | i (0x69) | byte | BA | single inserted base, SAM <br> operator I | | Quality score | Q (0x51) | byte | QS | single quality score | | Reference skip | N (0x4E) | int | RS | number of skipped bases, <br> SAM operator N | | Soft clip | S (0x53) | byte[] | SC | soft clipped bases, SAM <br> operator S | | Padding | $\mathrm{P}(0 \times 50)$ | int | PD | number of padded bases, <br> SAM operator P | | Hard clip | H (0x48) | int | HC | number of hard clipped bases, <br> SAM operator H |

关于与 BAM 的兼容性,所有碱基比较应以不区分大小写的方式进行,所有写入 SC、IN 和 BA 数据系列的碱基应为大写。


基本替代代码(BS 数据系列)


碱基替换被定义为从一个核苷酸碱基(参考碱基)更改为另一个(读取碱基),包括 N 作为未知或缺失的碱基。支持 5 种参考碱基(ACGTN),每种碱基有 4 种可能的替换。任何其他碱基类型,例如模糊代码,必须使用 BA 数据系列逐字书写。

所有可能替代的代码存储在一个二维替代矩阵中,该矩阵由参考碱基 ( A , C , G , T , N ) ( A , C , G , T , N ) (A,C,G,T,N)(A, C, G, T, N) 和 BS 代码 ( 0 3 ) ( 0 3 ) (0-3)(0-3) 索引,每个矩阵元素保存修改后的碱基。


替代矩阵格式


BS 数据系列支持 5 种可能的基本类型:A、C、G、T 和 N。因此,对于任何参考碱基,有 4 种可能的替代。每种替代可能性按上述顺序编号为 0 到 3(省略参考碱基类型)。因此,特定参考碱基的完整替代代码列表是 42 位数字 ( 0 3 ) ( 0 3 ) (0-3)(0-3) ,按上述顺序排列,减去参考碱基本身。这些被打包成一个字节,前 2 位为高位。


例如,对于参考基准 C,我们将记录替换 C 为 A , G , T A , G , T A,G,T\mathrm{A}, \mathrm{G}, \mathrm{T} 和 N 的 BS 数值。如果我们希望 A = 1 , G = 0 , T = 2 A = 1 , G = 0 , T = 2 A=1,G=0,T=2\mathrm{A}=1, \mathrm{G}=0, \mathrm{~T}=2 N = 3 N = 3 N=3\mathrm{N}=3 ,那么我们将存储二进制 01001011,或十六进制 0 x 4 B。


完整的替代矩阵为 5 个字节,每个字节存储参考基因 A , C , G , T A , C , G , T A,C,G,T\mathrm{A}, \mathrm{C}, \mathrm{G}, \mathrm{T} 和 N 的 4 个 BS 代码。

一个完整的矩阵,将 C / G C / G C//G\mathrm{C} / \mathrm{G} 组合在一起和 A / T A / T A//T\mathrm{A} / \mathrm{T} 组合在一起,可能看起来像这样:
 序列基础
 参考基础 A A A\mathbf{A} C C C\mathbf{C} G G G\mathbf{G} T T T\mathbf{T} N N N\mathbf{N}
A - 1 2 0 3
C 1 - 0 2 3
G 2 0 - 1 3
T 0 2 1 - 3
N 0 1 2 3 -
Seq. base Ref. base A C G T N A - 1 2 0 3 C 1 - 0 2 3 G 2 0 - 1 3 T 0 2 1 - 3 N 0 1 2 3 -| | Seq. base | | | | | | :--- | :---: | :---: | :---: | :---: | :---: | | Ref. base | $\mathbf{A}$ | $\mathbf{C}$ | $\mathbf{G}$ | $\mathbf{T}$ | $\mathbf{N}$ | | A | - | 1 | 2 | 0 | 3 | | C | 1 | - | 0 | 2 | 3 | | G | 2 | 0 | - | 1 | 3 | | T | 0 | 2 | 1 | - | 3 | | N | 0 | 1 | 2 | 3 | - |

这将被编码为

 二进制 01100011 , 01001011 , 10000111 , 00100111 , 00011011 01100011 , 01001011 , 10000111 , 00100111 , 00011011 01100011,01001011,quad10000111,quad00100111,quad0001101101100011,01001011, \quad 10000111, \quad 00100111, \quad 00011011

或十六进制 0 x 63 , 0 x 4 b , 0 x 87 , 0 x 27 0 x 1 b 0 x 63 , 0 x 4 b , 0 x 87 , 0 x 27 0 x 1 b 0x 63,quad0x4b,quad0x 87,quad0x 27quad0x1b0 x 63, \quad 0 x 4 b, \quad 0 x 87, \quad 0 x 27 \quad 0 x 1 b .

要解码,我们将使用以下查找表,显示与上面相同的数据,代码按 0 , 1 , 2 , 3 1 , 2 , 3 1,2,31,2,3 顺序排序。
 BS 代码
 参考基础 0 0 0\mathbf{0} 1 1 1\mathbf{1} 2 2 2\mathbf{2} 3 3 3\mathbf{3}
A T C G N
C G A T N
G C T A N
T A G C N
N A C G T
BS Code Ref. base 0 1 2 3 A T C G N C G A T N G C T A N T A G C N N A C G T| | BS Code | | | | | :--- | :---: | :---: | :---: | :---: | | Ref. base | $\mathbf{0}$ | $\mathbf{1}$ | $\mathbf{2}$ | $\mathbf{3}$ | | A | T | C | G | N | | C | G | A | T | N | | G | C | T | A | N | | T | A | G | C | N | | N | A | C | G | T |


替代代码分配


没有严格要求使用特定的替代矩阵,也不要求其是最优的。然而,一种策略可能是确保最常见的替代始终分配代码 0,第二常见的分配代码 1,依此类推。这意味着 BS 值的分布将偏向于较低的值,这有助于在更均匀分布的频率上提高压缩效果。


例如,假设碱基 A 的以下替代频率:

AC: 15 % 15 % 15%15 \%
AG: 25 % 25 % 25%25 \%
AT: 55 % 55 % 55%55 \%
AN: 5 % 5 % 5%5 \%

然后替换代码是 T = 0 , G = 1 , C = 2 , N = 3 T = 0 , G = 1 , C = 2 , N = 3 T=0,G=1,C=2,N=3\mathrm{T}=0, \mathrm{G}=1, \mathrm{C}=2, \mathrm{~N}=3


解码映射读取伪代码

procedure DECODEMAPPEDREAD
    feature_number }\leftarrow\mathrm{ READITEM(FN, Integer)
    last_feature_position }\leftarrow
    for }i\leftarrow1\mathrm{ to feature_number do
        DECODEFEATURE
    end for
    mapping_quality \leftarrow READITEM(MQ, Integer)
    if CF AND 1 then \triangleright Quality stored as an array
            for }i\leftarrow1\mathrm{ to read_length do
                quality_score \leftarrow READITEM(QS, Integer)
            end for
        end if
end procedure
procedure DecodeFeature
    feature_code }\leftarrow\mathrm{ READITEM(FC, Integer)
    feature_position }\leftarrow\mathrm{ READITEM(FP, Integer) + last_feature_position
    last_feature_position }\leftarrow\mathrm{ feature_position
    if feature_code ='B' then
        base }\leftarrow\mathrm{ READITEM(BA, Byte)
        quality_score }\leftarrow\mathrm{ READITEM(QS, Byte)
    else if feature_code ='X' then
        substitution_code \leftarrow READItEM(BS, Byte)
    else if feature_code ='I' then
        inserted_bases }\leftarrow\mathrm{ READITEM(IN, Byte[])
        else if feature_code ='S' then
            softclip_bases }\leftarrow\mathrm{ READITEM(SC, Byte[])
    else if feature_code \(={ }^{\prime} H\) ' then
        hardclip_length \(\leftarrow\) ReAdItEm(HC, Integer)
    else if feature_code ='P' then
        pad_length \({ }^{-} \leftarrow\) READITEM(PD, Integer)
    else if feature_code \(=\) 'D' then
        deletion_length \(\leftarrow\) READITEM(DL, Integer)
    else if feature_code \(={ }^{\prime} \mathrm{N}\) ' then
        ref_skip_length \(\leftarrow\) READITEm(RS, Integer)
    else if feature_code \(=\) 'i' then
        base \(-\leftarrow\) ReAdItEm(BA, Byte)
    else if feature \(\quad\) code \(=' \mathrm{~b}\) ' then
        bases \(\leftarrow\) REadItEm(BB, Byte[])
    else if feature_code ='q' then
        quality_scores \(\leftarrow\) REAdITEM(QQ, Byte[])
    else if feature_code \(=\) ' Q ' then
        quality_score \(\leftarrow\) READITEM(QS, Byte)
    end if
end procedure


10.7 未映射的读数


未映射读取的 CRAM 记录结构具有以下附加字段:
 数据系列类型
 数据系列名称
Data series name| Data series | | :--- | | name |
 字段  描述
 字节[读取长度] BA  基础  读取的碱基
 字节[读取长度] QS  质量分数
基础品质,如果保持
Data series type "Data series name" Field Description byte[read length] BA bases the read bases byte[read length] QS quality scores the base qualities, if preserved| Data series type | Data series <br> name | Field | Description | | :--- | :--- | :--- | :--- | | byte[read length] | BA | bases | the read bases | | byte[read length] | QS | quality scores | the base qualities, if preserved |
procedure DeCoDeUnMAPpedREAD
        for \(i \leftarrow 1\) to read_length do
            base \(\leftarrow\) READITEM(BA, Byte)
        end for
        if \(C F\) AND 1 then \(\triangleright\) Quality stored as an array
            for \(i \leftarrow 1\) to read_length do
                quality_score \(\leftarrow\) READITEM(QS, Byte)
            end for
        end if
end procedure


11 参考序列


CRAM 格式本质上基于参考序列的使用,尽管在某些情况下它们并不是必需的。与 BAM 格式相比,CRAM 格式对参考序列有严格的规则。

  1. BAM 头中的@SQ 序列记录的 M5(序列 MD5 校验和)字段是必需的,UR(序列 fasta 可选 gzipped 文件的 URI)字段强烈建议使用。计算 MD5 的规则是去除任何非碱基符号(如 n n \\n\backslash \mathrm{n} 、序列名称或长度和空格),并将其余部分转换为大写。以下是一些示例:
> samtools faidx human_g1k_v37.fasta 1 | grep -v ,^>' | tr -d '\n' | tr a-z A-Z | md5sum
-
1b22b98cdeb4a9304cb5d48026a85128 -
> samtools faidx human_g1k_v37.fasta 1:10-20 |grep -v '^>' |tr -d '\n' |tr a-z A-Z |md5sum
Of2a4865e3952676ffad2c3671f14057 -

请注意,后者计算从位置 10(包含)到 20(包含)的 11 个碱基的校验和,碱基是以 1 为基数计数的,因此第一个碱基位置是 1。


2. 所有 CRAM 读取器实现都应检查参考 MD5 校验和,并报告任何缺失或不匹配的条目。因此,所有写入器实现都应确保在压缩时注入或检查所有校验和。


在某些情况下,读取可能会映射到参考序列之外。所有超出范围的参考碱基都假定为 'N'。


4. 对于未映射或多引用切片,切片头中的 MD5 校验和字节应被忽略。

 12 索引

 一般说明


索引仅在按坐标(参考 ID 然后是最左侧位置)排序的文件上有效。


请注意,CRAM 索引是外部于文件格式本身的,并且可能在未来独立于文件格式规范而变化。例如,可能会出现一种新的索引文件类型。

在 CRAM 文件中,单个记录没有被索引,应该使用切片作为随机访问的单位。CRAM 和 BAM 索引之间的另一个重要区别是,CRAM 容器头和压缩头块(容器中的第一个块)必须在解码切片之前始终读取。因此,在 CRAM 中进行随机访问需要两个读取操作。

索引 CRAM 文件被认为是一项轻量级操作,因为通常不需要读取任何 CRAM 记录。索引信息可以从容器头部获取,即序列 ID、比对起始位置和跨度、容器起始字节偏移量以及容器内的切片字节偏移量(标志)。例外情况是多参考容器,在这种情况下必须读取“RI”数据系列。

 CRAM 索引


CRAM 索引是一个 gzipped 制表符分隔的文件,包含以下列:
  1.  参考序列 ID

  2. 对齐开始(对于未映射的切片在读取时被忽略,写入时设置为 0)

  3. 对齐跨度(对未映射切片的读取忽略,写入时设置为 0)

  4. 文件中容器头的绝对字节偏移量。

  5. 切片头块的相对字节偏移量,从容器头部的末尾开始。这与容器头部中的“地标”字段相同。

  6. 切片大小(以字节为单位,包括切片头和所有块)。

每一行代表 CRAM 文件中的一个切片。请注意,所有切片必须在索引文件中列出。


多参考切片可能需要为同一切片有多行;每个切片中包含的每个参考都有一行。在这种情况下,索引参考序列 ID 将是实际的参考 ID(来自“RI”数据系列),而不是 -2。


仅包含未映射未放置数据的切片(参考 ID -1)仍然需要所有列的值,尽管对齐开始和跨度将被忽略。建议将它们都设置为零。

为了说明这一点,下面的图示出了在三片容器中使用的绝对和相对偏移量。

 BAM 索引


BAM 索引通过使用称为地标的 4 字节整数指针来支持,这些指针存储在容器头中。BAM 索引指针是一个 64 位值,其中 48 位保留用于 BAM 块的起始位置,16 位保留用于块内偏移量。当用于索引 CRAM 文件时,前 48 位用于存储 CRAM 容器的起始位置,最后 16 位用于存储容器头中地标数组的地标索引。地标索引可用于访问相应的切片。

上述索引方案将 CRAM 切片视为 BAM 文件中的单独记录。这允许对 CRAM 文件应用 BAM 索引,但在查找特定比对起始位置时会引入一些开销,因为必须读取并丢弃切片中的所有前置记录。

 13 编码

 13.1 介绍


编码的基本思想是高效地以二进制格式表示某些值。这可以通过多种方式实现,通常涉及对被编码值的性质的一些了解,例如分布统计。选择最佳编码和确定其参数的方法非常多样,并不属于 CRAM 格式规范的内容,后者仅描述了解码值所需信息的存储方式。


注意,两个编码(Golomb 和 Golomb-Rice)被列为不推荐使用。这些编码仍然是 CRAM 规范的正式部分,但主要实现中未使用,并且可能不被很好支持。因此,允许使用它们,但不推荐。

 偏移量


以下列出的许多编码用于编码正整数。使用整数偏移值可以允许编码任何整数,而不仅仅是正整数。它也可以用于最大值不等于零的单调递减分布。例如,给定的偏移量为 10,待编码的值为 1,则实际编码的值为偏移量 + 值 = 11 = 11 =11=11 。然后在解码时,偏移量将从解码值中减去。


13.2 外部: 编解码器 ID 1


可以编码类型 Byte、Integer。


外部编码只是将数据逐字存储到具有给定 ID 的外部块中。如果类型是字节,则数据按原样存储;否则,对于整数类型,数据以 ITF8 格式存储。

 参数


CRAM 格式定义了 EXTERNAL 编码的以下参数:
 数据类型  名称  评论
itf8  外部 ID
外部块的 ID,包含字节流
Data type Name Comment itf8 external id id of an external block containing the byte stream| Data type | Name | Comment | | :--- | :--- | :--- | | itf8 | external id | id of an external block containing the byte stream |


13.3 哈夫曼编码:编解码器 ID 3


可以编码类型 Byte、Integer。


霍夫曼编码通过二进制代码字替换符号(要编码的值),常见符号具有较短的代码字,从而使得二进制代码字的总消息长度比使用统一的二进制代码字长度更短。一般过程包括以下步骤。

  • 获取符号代码长度。
  •  如果编码:

  • 计算符号频率。

  • 根据频率计算代码长度。
  •  如果解码:

  • 从编解码参数读取代码长度。

  • 从码长 5 5 ^(5){ }^{5} 计算规范哈夫曼码字。

  • 根据符号到代码字表对比特进行编码或解码。代码字具有“前缀属性”,即没有任何代码字是另一个代码字的前缀,从而实现逐位无歧义解码。

使用规范哈夫曼编码意味着我们只需存储码长,并在编码器和解码器中使用相同的算法来生成码字。这是通过确保我们的符号字母表具有自然排序顺序,并以数字顺序分配码字来实现的。


重要说明:对于只有一个值的字母,代码字将是零位长。这使得霍夫曼编码器成为指定常量值的有效机制。


规范代码计算


  1. 按位长度升序排列字母,然后按值的数值顺序排列。

  2. 列表中的第一个符号被分配一个代码字,该代码字与符号的原始代码字长度相同,但全部为零。这通常是一个单独的零(‘0’)。

  3. 每个后续符号都被分配下一个顺序中的二进制数字,确保后续代码的值始终更高。

  4. 当你达到一个较长的代码字时,在递增后,附加零直到新代码字的长度等于旧代码字的长度。

 示例

 符号  代码长度  代码词
A 1 0
B 3 100
C 3 101
D 3 110
E 4 1110
F 4 1111
Symbol Code length Codeword A 1 0 B 3 100 C 3 101 D 3 110 E 4 1110 F 4 1111| Symbol | Code length | Codeword | | :--- | :--- | :--- | | A | 1 | 0 | | B | 3 | 100 | | C | 3 | 101 | | D | 3 | 110 | | E | 4 | 1110 | | F | 4 | 1111 |

 参数

 数据类型  名称  评论
itf8[]  字母表
所有编码符号(值)的列表
itf8[]  位长
字母表中每个符号的位长度数组
Data type Name Comment itf8[] alphabet list of all encoded symbols (values) itf8[] bit-lengths array of bit-lengths for each symbol in the alphabet| Data type | Name | Comment | | :--- | :--- | :--- | | itf8[] | alphabet | list of all encoded symbols (values) | | itf8[] | bit-lengths | array of bit-lengths for each symbol in the alphabet |


13.4 字节数组编码


通常需要对一个字节数组进行编码,而其长度并未预先确定。例如,读取标识符因对齐记录而异,可能具有不同的长度,并且该长度必须存储在某处。有两种选择可用:显式存储长度(BYTE_ARRAY_LEN)或继续读取字节直到看到终止值(BYTE_ARRAY_STOP)。


请注意,与此相反,质量值的长度与序列相同,这是一个已知的量,因此不需要使用字节数组编解码器进行编码。


BYTE_ARRAY_LEN: 编解码器 ID 4


可以编码类型 Byte [ ]。


字节数组是按长度优先捕获的,这意味着每个数组元素的长度是使用额外编码写入的。例如,这可以是霍夫曼编码或另一个外部块。长度首先被解码,然后是数据,接着是下一个长度和数据,依此类推。


因此,这种编码可以被视为嵌套编码,每对嵌套编码包含其自己的参数集。因此,BYTE_ARRAY_LEN 编码的参数的字节流是第 2.3 节中描述的长度和数值编码参数的连接。


BYTE_ARRAY_LEN 的参数如下:
 数据类型  名称  评论
 编码  长度编码

一个编码,描述如何捕获数组的长度
an encoding describing how the arrays lengths are captured| an encoding describing how the arrays lengths are | | :--- | | captured |
 编码  值编码
一个编码,描述了如何捕获这些值
Data type Name Comment encoding<int> lengths encoding "an encoding describing how the arrays lengths are captured" encoding<byte> values encoding an encoding describing how the values are captured| Data type | Name | Comment | | :--- | :--- | :--- | | encoding<int> | lengths encoding | an encoding describing how the arrays lengths are <br> captured | | encoding<byte> | values encoding | an encoding describing how the values are captured |

例如,指定 BYTE_ARRAY_LEN 编码的字节,包括编解码器和参数,对于 16 位 X0 辅助标签(“X0C”)可以使用 H H ¯ bar(H)\overline{\mathrm{H}} UFFMA N N ¯ bar(N)\overline{\mathrm{N}} 编码来指定长度(始终为 2 字节),并使用 EXTERNAL 编码将值存储到 ID 为 200 的外部块中。
 字节  意义
0x04  BYTE_ARRAY_LEN 编解码器 ID
0x0a
10 个剩余字节的 BYTE_ARRAY_LEN 参数
0x03
霍夫曼编码 ID,用于辅助标签长度
0x04
4 个字节的霍夫曼参数
0x01
字母数组大小 = 1 = 1 =1=1
0x02
字母符号;(长度 = 2 ) = 2 ) =2)=2)
0x01
代码字数组大小 = 1 = 1 =1=1
0x00
代码长度 = 0 = 0 =0=0 (需要零位,因为字母表大小为 1)
0x01
外部编解码器 ID,用于辅助标签值
0x02

2 个额外字节的外部参数
2 more bytes of EXTERNAL parameters| 2 more bytes of EXTERNAL parameters | | :--- |
0x80 0xc8
块 ID 200 的 ITF8 编码
Bytes Meaning 0x04 BYTE_ARRAY_LEN codec ID 0x0a 10 remaining bytes of BYTE_ARRAY_LEN parameters 0x03 HUFFMAN codec ID, for aux tag lengths 0x04 4 more bytes of HUFFMAN parameters 0x01 Alphabet array size =1 0x02 alphabet symbol; (length =2) 0x01 Codeword array size =1 0x00 Code length =0 (zero bits needed as alphabet is size 1) 0x01 EXTERNAL codec ID, for aux tag values 0x02 "2 more bytes of EXTERNAL parameters" 0x80 0xc8 ITF8 encoding for block ID 200| Bytes | Meaning | | :--- | :--- | | 0x04 | BYTE_ARRAY_LEN codec ID | | 0x0a | 10 remaining bytes of BYTE_ARRAY_LEN parameters | | | | | 0x03 | HUFFMAN codec ID, for aux tag lengths | | 0x04 | 4 more bytes of HUFFMAN parameters | | 0x01 | Alphabet array size $=1$ | | 0x02 | alphabet symbol; (length $=2)$ | | 0x01 | Codeword array size $=1$ | | 0x00 | Code length $=0$ (zero bits needed as alphabet is size 1) | | | | | 0x01 | EXTERNAL codec ID, for aux tag values | | 0x02 | 2 more bytes of EXTERNAL parameters | | 0x80 0xc8 | ITF8 encoding for block ID 200 |


BYTE_ARRAY_STOP: 编解码器 ID 5


可以编码类型 Byte [ ]。


字节数组被捕获为以特殊停止字节终止的字节序列。返回的数据不包括停止字节本身。与 BYTE_ARRAY_LEN 相比,值始终使用 EXTERNAL 编码,因此参数是外部 ID,而不是其他编码。
 数据类型  名称  评论
 字节  停止字节
一个作为分隔符处理的特殊字节
itf8  外部 ID
外部块的 ID,包含字节流
Data type Name Comment byte stop byte a special byte treated as a delimiter itf8 external id id of an external block containing the byte stream| Data type | Name | Comment | | :--- | :--- | :--- | | byte | stop byte | a special byte treated as a delimiter | | itf8 | external id | id of an external block containing the byte stream |


13.5 Beta 编码:编解码器 ID 6


可以编码类型整数。

 定义


贝塔编码是以二进制表示数字的最常见方式,有时被称为二进制编码。解码器读取指定的固定数量的位(最重要的位优先),并减去偏移值以获得解码后的整数。

 参数


CRAM 格式定义了 beta 编码的以下参数:
 数据类型  名称  评论
itf8  偏移量

在解码过程中,从每个值中减去偏移量
offset is subtracted from each value during decode| offset is subtracted from each | | :--- | | value during decode |
itf8  长度
使用的位数
Data type Name Comment itf8 offset "offset is subtracted from each value during decode" itf8 length the number of bits used| Data type | Name | Comment | | :--- | :--- | :--- | | itf8 | offset | offset is subtracted from each <br> value during decode | | itf8 | length | the number of bits used |

 示例


如果我们有范围在 10 到 15(包括 10 和 15)之间的整数值,传统上最大的值需要 4 位,但通过使用-10 的偏移量,我们可以用 3 位固定大小表示 0 到 5 的值。使用来自 beta 参数的固定偏移量和长度,我们将这些值解码为:
 偏移量  长度  比特  
-10 3 000 10
-10 3 001 11
-10 3 010 12
-10 3 011 13
-10 3 100 14
-10 3 101 15
Offset Length Bits Value -10 3 000 10 -10 3 001 11 -10 3 010 12 -10 3 011 13 -10 3 100 14 -10 3 101 15| Offset | Length | Bits | Value | | :--- | :--- | :--- | :--- | | -10 | 3 | 000 | 10 | | -10 | 3 | 001 | 11 | | -10 | 3 | 010 | 12 | | -10 | 3 | 011 | 13 | | -10 | 3 | 100 | 14 | | -10 | 3 | 101 | 15 |


13.6 亚指数编码:编解码器 ID 7


可以编码类型整数。

 定义


亚指数编码 6 6 ^(6){ }^{6} 由一个非负整数 k k kk 参数化。对于值 n < 2 k + 1 n < 2 k + 1 n < 2^(k+1)n<2^{k+1} ,亚指数编码生成与 Rice 编码 7 7 ^(7){ }^{7} 相同的代码字。对于更大的值,它以 n n nn 的对数方式增长。

 编码


  1. 将偏移量添加到 n n nn

  2. n n nn 确定 u u uu b b bb 的值
b = { k if n < 2 k log 2 n if n 2 k u = { 0 if n < 2 k b k + 1 if n 2 k b = k  if  n < 2 k log 2 n  if  n 2 k u = 0  if  n < 2 k b k + 1  if  n 2 k b={[k," if "n < 2^(k)],[|__log_(2)n __|," if "n >= 2^(k)]quad u={[0," if "n < 2^(k)],[b-k+1," if "n >= 2^(k)]:}b=\left\{\begin{array}{ll} k & \text { if } n<2^{k} \\ \left\lfloor\log _{2} n\right\rfloor & \text { if } n \geq 2^{k} \end{array} \quad u= \begin{cases}0 & \text { if } n<2^{k} \\ b-k+1 & \text { if } n \geq 2^{k}\end{cases}\right.

  1. 以一元形式写 u u uu u 1 u 1 u1u 1 位后跟一个 0 位。

  2. 以二进制形式写出 n n nn 的最低 b b bb 位。

 解码


  1. 以一元形式读取 u u uu ,计算码字中前导 1 的数量(前缀)(忽略尾随的 0 位)。
  2.  通过以下方式确定 n n nn

    如果 u = 0 u = 0 u=0u=0 则将 n n nn 读取为 k k kk 位二进制数。


    (b) 如果 u 1 u 1 u >= 1u \geq 1 则将 x x xx 读取为 ( u + k 1 ) ( u + k 1 ) (u+k-1)(u+k-1) 位二进制。设 n = 2 u + k 1 + x n = 2 u + k 1 + x n=2^(u+k-1)+xn=2^{u+k-1}+x

  3. n n nn 中减去偏移量。

 示例

 数字  代码字, k = 0 k = 0 k=0\mathbf{k}=\mathbf{0}  代码字, k = 1 k = 1 k=1\mathbf{k}=\mathbf{1}  代码字, k = 2 k = 2 k=2\mathbf{k}=\mathbf{2}
0 0 00 000
1 10 01 001
2 1100 100 010
3 1101 101 011
4 111000 11000 1000
5 111001 11001 1001
6 111010 11010 1010
7 111011 11011 1011
8 11110000 1110000 110000
9 11110001 1110001 110001
10 11110010 1110010 110010
Number Codeword, k=0 Codeword, k=1 Codeword, k=2 0 0 00 000 1 10 01 001 2 1100 100 010 3 1101 101 011 4 111000 11000 1000 5 111001 11001 1001 6 111010 11010 1010 7 111011 11011 1011 8 11110000 1110000 110000 9 11110001 1110001 110001 10 11110010 1110010 110010| Number | Codeword, $\mathbf{k}=\mathbf{0}$ | Codeword, $\mathbf{k}=\mathbf{1}$ | Codeword, $\mathbf{k}=\mathbf{2}$ | | :--- | :--- | :--- | :--- | | 0 | 0 | 00 | 000 | | 1 | 10 | 01 | 001 | | 2 | 1100 | 100 | 010 | | 3 | 1101 | 101 | 011 | | 4 | 111000 | 11000 | 1000 | | 5 | 111001 | 11001 | 1001 | | 6 | 111010 | 11010 | 1010 | | 7 | 111011 | 11011 | 1011 | | 8 | 11110000 | 1110000 | 110000 | | 9 | 11110001 | 1110001 | 110001 | | 10 | 11110010 | 1110010 | 110010 |

 参数

 数据类型  名称  评论
itf8  偏移量
在解码过程中,从每个值中减去偏移量
itf8 k
子指数编码的顺序
Data type Name Comment itf8 offset offset is subtracted from each value during decode itf8 k the order of the subexponential coding| Data type | Name | Comment | | :--- | :--- | :--- | | itf8 | offset | offset is subtracted from each value during decode | | itf8 | k | the order of the subexponential coding |


13.7 伽马编码:编解码器 ID 9


可以编码类型整数。

 定义


Elias gamma 码是正整数的前缀编码。这是单一编码和贝塔编码的组合。前者用于捕获贝塔编码所需的位数,以捕获值。

 编码


  1. 用二进制写。

  2. 从步骤 1 中写入的位数中减去 1,并在前面添加那么多零。

  3. 表达相同过程的等效方式:

  4. 将整数分解为其包含的最高 2 的幂 ( 2 N ) ( 2 N ) (2N)(2 N) 和整数的剩余 N N NN 个二进制位。

  5. N N NN 编码为一元;即, N N NN 个零后跟一个一。

  6. 将剩余的 N N NN 个二进制位附加到 N N NN 的表示中。

 解码


  1. 从流中读取并计数 0,直到遇到第一个 1。将这个零的计数称为 N N NN

  2. 考虑到达到的那个是整数的第一位,值为 2 N 2 N 2N2 N ,读取整数的其余 N N NN 位。

 示例

   代码词
1 1
2 010
3 011
4 00100
Value Codeword 1 1 2 010 3 011 4 00100| Value | Codeword | | :--- | :--- | | 1 | 1 | | 2 | 010 | | 3 | 011 | | 4 | 00100 |

 参数

 数据类型  名称  评论
itf8  偏移量

解码后从每个值中减去的偏移量
offset to subtract from each value after decode| offset to subtract from each | | :--- | | value after decode |
Data type Name Comment itf8 offset "offset to subtract from each value after decode"| Data type | Name | Comment | | :--- | :--- | :--- | | itf8 | offset | offset to subtract from each <br> value after decode |


13.8 已弃用:Golomb 编码:编解码器 ID 2


可以编码类型整数。


请注意,自 CRAM v1.0 之前,该编解码器在任何已知的 CRAM 实现中都未被使用。它在一些主要软件中也未被实现。因此,不建议使用它。

 定义


高隆布编码是一种前缀编码,最适合表示遵循几何分布的随机正数。

 编码


  1. 将参数 M M MM 修复为整数值。

  2. 对于 N N NN ,要编码的数字,找到

     (a) 商 q = N / M q = N / M q=|__ N//M __|q=\lfloor N / M\rfloor
     (b) 余数 r = N mod M r = N mod M r=N mod Mr=N \bmod M
  3.  生成代码词

    (a)代码格式:<商代码><余数代码>,其中


    (b) 商码(单一编码)


    编写一个 q q qq 长度的 1 位字符串


    ii. 写入 0 位


    © 剩余代码(以截断二进制编码)
 设置 b = log 2 ( M ) b = log 2 ( M ) b=|~log_(2)(M)~|b=\left\lceil\log _{2}(M)\right\rceil

如果 r < 2 b M r < 2 b M r < 2^(b)-Mr<2^{b}-M 代码 r r rr 作为使用 b 1 b 1 b-1b-1 位的纯二进制。


ii. 如果 r 2 b M r 2 b M r >= 2^(b)-Mr \geq 2^{b}-M 使用 b b bb 位以普通二进制表示数字 r + 2 b M r + 2 b M r+2^(b)-Mr+2^{b}-M

 解码


  1. 通过一元编码读取 q q qq :计算 1 位的数量并消耗后续的 0 位。
  2.  设置 b = log 2 ( M ) b = log 2 ( M ) b=|~log_(2)(M)~|b=\left\lceil\log _{2}(M)\right\rceil

  3. 通过 b 1 b 1 b-1b-1 位二进制编码读取 r r rr
  4.  如果 r 2 b M r 2 b M r >= 2^(b)-Mr \geq 2^{b}-M

    (a) 读取 1 个单独的位, x x xx

     (b) 设置 r = r 2 + x ( 2 b M ) r = r 2 + x 2 b M r=r**2+x-(2^(b)-M)r=r * 2+x-\left(2^{b}-M\right)
  5.  值为 q M + r q M + r q**M+r-q * M+r- 偏移量

 示例

 数字

代码字,M=10,(因此 b=4)
Codeword, M=10, (thus b=4)| Codeword, M=10, | | :--- | | (thus b=4) |
0 0000
4 0100
10 10000
26 1101100
42 11110010
Number "Codeword, M=10, (thus b=4)" 0 0000 4 0100 10 10000 26 1101100 42 11110010| Number | Codeword, M=10, <br> (thus b=4) | | :--- | :--- | | 0 | 0000 | | 4 | 0100 | | 10 | 10000 | | 26 | 1101100 | | 42 | 11110010 |

 参数


Golomb 编码采用以下参数:
 数据类型  名称  评论
itf8  偏移量
每个值都添加了偏移量
itf8 M

高隆布参数(箱子数量)
the golomb parameter (number of bins)| the golomb parameter (number | | :--- | | of bins) |
Data type Name Comment itf8 offset offset is added to each value itf8 M "the golomb parameter (number of bins)"| Data type | Name | Comment | | :--- | :--- | :--- | | itf8 | offset | offset is added to each value | | itf8 | M | the golomb parameter (number <br> of bins) |


13.9 已弃用:Golomb-Rice 编码:编解码器 ID 8


可以编码类型整数。


请注意,自 CRAM v1.0 之前,该编解码器在任何已知的 CRAM 实现中都未被使用。它在一些主要软件中也未被实现。因此,不建议使用它。


Golomb-Rice 编码是 Golomb 编码的特例,当 M 参数是 2 的幂时。使用这种编码的原因是,Golomb 编码中的除法操作可以用位移运算符替代,并且避免了额外的 r < 2 b M r < 2 b M r < 2^(b)-Mr<2^{b}-M 检查。


14 外部压缩方法


外部编码仅在字节上操作。因此,任何数据序列必须在将数据发送到外部块之前转换为字节。定义了以下方法。这些方法的确切定义在各自的互联网链接中或在本规范旁边找到的辅助 CRAMcodecs 文档中。

整数值以 ITF8 格式写入,然后可以转换为字节数组。


字符串,如读取名称,按照 UTF8 规则转换为字节。在大多数情况下,这些应该与 ASCII 一致,使得转换变得简单。

每个方法都有一个相关的数字代码,该代码在第 8 节中定义。

14.1 Gzip


Gzip 规范在 RFC 1952 中定义。Gzip 反过来是对 RFC 1951 中定义的 Deflate 算法的封装。

14.2 Bzip2


首次在 CRAM v2.0 中可用。


Bzip2 是一种压缩方法,利用了 Burrows Wheeler 变换、前移变换、游程编码和霍夫曼熵编码。对于文本数据,它通常优于 Gzip。


存在一种非正式的格式规范:

https://github.com/dsnet/compress/blob/master/doc/bzip2-format.pdf

14.3 LZMA


首次在 CRAM v3.0 中可用。


LZMA 是 Lempel-Ziv 马尔可夫链算法。CRAM 使用 xz 流格式来封装该算法,具体定义见 https://tukaani.org/xz/xz-file-format.txt。

 14.4 rANS4x8 编解码器


首次在 CRAM v3.0 中可用。


rANS 是不对称数值系统 8 8 ^(8){ }^{8} 的范围编码变体。


"4 x 8" 指的是 4 路交错与 8 位重新归一化。


这种 rANS 的变体首次出现在 CRAM v3.0 中。


该算法的详细信息已移至 CRAMcodecs 文档。

 14.5 rANS4x16 编解码器


首次在 CRAM v3.1 中可用。


4 × 16 4 × 16 4xx164 \times 16 ”指的是 4 路交错与 16 位重新归一化。


这种 rANS 的变体首次出现在 CRAM v3.1 中。


该算法的详细信息列在 CRAMcodecs 文档中。


14.6 自适应算术编码


首次在 CRAM v3.1 中可用。


一种熵编码器,速度较慢但比 rANS 略为简洁。它通过在压缩和解压缩时调整概率,而不是使用固定表来实现这一点。

该算法的详细信息列在 CRAMcodecs 文档中。

 14.7 fqzcomp 编解码器


首次在 CRAM v3.1 中可用。


这是一个专门用于压缩质量值的方法。


该算法的详细信息列在 CRAMcodecs 文档中。

 14.8 名称标记器


首次在 CRAM v3.1 中可用。


这是一个专门用于压缩读取名称的方法。


该算法的详细信息列在 CRAMcodecs 文档中。

 15 附录


15.1 选择容器大小


CRAM 格式不限制容器的大小。然而,在决定容器大小时应考虑以下因素:

  • 数据可以通过使用更大的容器来更好地压缩

  • 随机访问性能在较小的容器中更好

  • 流式传输对小容器来说更方便

  • 应用程序通常将容器缓冲到内存中

我们推荐 1 兆字节的容器。它们足够小,可以提供良好的随机访问和流媒体性能,同时又足够大,可以提供良好的压缩。1MB 的容器也足够小,可以适应大多数现代 CPU 的 L2 缓存。


以下提供了一些简化的示例,以将数据适配到 1 MB 的容器中。


未映射的短读段,包括碱基、读取名称、重新校准和原始质量分数


我们有 10,000 个未映射的短读段(100bp),带有读取名称、重新校准和原始质量分数。我们估计 0.4 位/碱基(读取名称)+0.4 位/碱基(碱基)+3 位/碱基(重新校准的质量分数)+3 位/碱基(原始质量分数) 7 7 ~~7\approx 7 位/碱基。空间估计为 10000 × 100 × 7 10000 × 100 × 7 10000 xx100 xx710000 \times 100 \times 7 0.9 MB 0.9 MB ~~0.9MB\approx 0.9 \mathrm{MB} 。数据可以存储在一个单一的容器中。


未映射的长读数,包括碱基、读名和质量分数


我们有 10,000 个未映射的长读数(10 kb),带有读取名称和质量分数。我们估计:0.4 位/碱基(碱基)+ 3 位/碱基(原始质量分数) 3.5 3.5 ~~3.5\approx 3.5 位/碱基。空间估计为 10000 × 10000 × 3.5 10000 × 10000 × 3.5 10000 xx10000 xx3.510000 \times 10000 \times 3.5 ~~\approx 42 MB。数据可以存储在 42 × 1 MB 42 × 1 MB 42 xx1MB42 \times 1 \mathrm{MB} 容器中。


映射的短读段,包含碱基、配对和映射信息


我们有 250,000 个映射的短读数(100 bp),包含碱基、配对和映射信息。我们估计压缩率为 0.2 位/碱基。空间估计为 250000 × 100 × 0.2 250000 × 100 × 0.2 250000 xx100 xx0.2250000 \times 100 \times 0.2 0.6 MB 0.6 MB ~~0.6MB\approx 0.6 \mathrm{MB} 。数据可以存储在一个单一的容器中。


嵌入式参考序列


我们有一个参考序列(10 Mb)。我们估计压缩为每个碱基 2 位。空间估计为 10000000 × 2 10000000 × 2 10000000 xx210000000 \times 2 2.4 MB 2.4 MB ~~2.4MB\approx 2.4 \mathrm{MB} 。数据可以写入三个容器: 1 MB + 1 MB + 0.4 MB 1 MB + 1 MB + 0.4 MB 1MB+1MB+0.4MB1 \mathrm{MB}+1 \mathrm{MB}+0.4 \mathrm{MB}

 15.2 CRAM 历史

 预 CRAM:2010


CRAM 的主要概念和思想源于 2010 年和 2011 年在欧洲生物信息学研究所的工作,发表在:


马库斯·希-杨·弗里茨、拉斯科·莱诺宁、盖·科克伦和尤安·伯尼,高效存储高

通过基于参考的压缩处理 DNA 测序数据,基因组研究。2011 21:
734 740 734 740 734-740734-740; doi:10.1101/gr.114819.110; PMID:21245279.

CRAM 0.x: 2011


Vadim Zalunin 在名为 CRAM 的论文中实现了这些想法,现已在 Java CRAMtools 包中实现。这包括从 0.3 到 0.86 9 0.86 9 0.86^(9)0.86^{9} 的版本。

 CRAM 1.0:2012


CRAM 规范的首次官方发布,在 Java CRAMtools 包中 10 10 ^(10){ }^{10}


此信息已在 https://github.com/enasequence/cramtools 上公开。

 CRAM 2.0:2013


C 11 C 11 C^(11)\mathrm{C}^{11} 中重新实现 CRAM 暴露了 1.0 规范的一些问题,以及规范文本与 Java 实现之间的差异。CRAM 2.0 统一了实现与规范。
 其他更改包括:

  • 支持每个容器多个引用,以允许存储高度碎片化的程序集。

  • 软剪接和插入碱基移至各自独立的数据系列,而不是共享一个。

  • 切片头包含跟踪记录数量和基础的元数据。

  • 修正了 BF(bam 标志)数据系列以符合 BAM 规范。

  • 改进了辅助标签的编码。

 CRAM 2.1:2014


这是在 HTSJDK 中出现的第一个版本(版本 1.127),移植自 Java CRAMtools 包。

  • EOF 块被添加以便于识别截断的文件。
 CRAM 3.0:2014

主要这是对大小和速度的优化。

  • 包含 LZMA 压缩库。

  • 包含自定义的 rANS 0 阶和 1 阶熵编码器。

  • 所有文件格式结构都添加了校验和,以确保数据完整性。
 CRAM 3.1:2023

注意:正式草案于 2019 年出现,并于 2016 年首次演示。


这增加了新的外部压缩方法,详见单独的 CRAMcodecs 文档,并扩展了 CRAM 块结构中允许的“方法”列表。


新压缩方法的目标是提高压缩性能,既包括使用更新的 SIMD rANS 实现的性能,也包括通过自定义名称分词器和质量编解码器来减小文件大小。

格式与 3.0 完全相同。


15.3 贡献者与致谢


  • 马库斯·弗里茨、拉斯科·莱农宁、盖·科克伦和尤安·伯尼(EBI):CRAM 背后的初步想法。

  • Vadim Zalunin (EBI):CRAM 的初始 JAVA 实现及 CRAM 规范的前维护者。

  • 詹姆斯·邦菲尔德(桑格研究所):CRAM 的初始 C 实现者及当前 CRAM 规范的维护者。

  • Joel Thibault(布罗德研究所):CRAM 规范的前维护者。

  • 克里斯·诺曼(布罗德研究所):CRAM 规范的前维护者,并参与了 HTSJDK 实现的工作。

  • 罗伯特·比尔斯(加州大学伯克利分校):CRAM 的第一个 JavaScript 实现

  • 迈克尔·马西亚斯(圣犹大儿童研究医院):CRAM 的首个 Rust 实现

  • 其他规范贡献者包括:John Marshall、Rishi Nag、Kenta Sato、Artem Tarasov 和 Jason Travis。

  • 非常感谢所有提出 GitHub 问题和/或以其他方式帮助我们改进规范的每一个人。


  1. 1 1 ^(1){ }^{1} 马库斯·希-杨·弗里茨、拉斯科·莱农、盖·科克伦和尤安·伯尼,基于参考的压缩高通量 DNA 测序数据的高效存储,《基因组研究》。2011 年 21: 734-740;doi:10.1101/gr.114819.110;PMID:21245279。

  2. a a ^(a){ }^{a} 以前是 MAPPED_SLICE_HEADER。现在所有切片头都使用它,无论映射状态如何。

  3. 2 2 ^(2){ }^{2} 精确的顺序在第 10 节中定义。

  4. 3 3 ^(3){ }^{3} 未映射的读取可以是已放置或未放置的。我们所说的已放置未映射读取是指根据 BF(BAM 位标志)数据系列的位 0 × 4 0 × 4 0xx40 \times 4 未映射的读取,但其位置信息字段已填写,从而将其“放置”在参考序列上。相反,未放置的未映射读取的参考序列 ID 为 -1,且对齐位置为 0。

  5. 4 4 ^(4){ }^{4} 交错有时可以提供更好的压缩,但它也增加了数据类型之间的依赖关系,这意味着如果一个数据系列与另一个数据系列在同一块中共存,就无法选择性地解码一个数据系列。

  6. 6 6 ^(6){ }^{6} 快速渐进无损图像压缩,保罗·G·霍华德和杰弗里·斯科特·维特,1994 年。http://www.ittc.ku.edu/jsv/Papers/HoV94.progressive_FELICS.pdf

    7 7 ^(7){ }^{7} https://en.wikipedia.org/wiki/Golomb_coding#Rice_coding

  7. 8 8 ^(8){ }^{8} J. Duda, 非对称数字系统:结合霍夫曼编码速度与算术编码压缩率的熵编码,http://arxiv.org/abs/1311.2540
  8. 9 9 ^(9){ }^{9} https://github.com/vadimzalunin/crammer/releases
    10 10 ^(10){ }^{10} https://github.com/enasequence/cramtools

    11 11 ^(11){ }^{11} Staden IO_Lib 1.13.0 及更高版本 HTSlib 0.2.0