seqan库的使用

2022-03-28 15:21:05 浏览数 (1)

seqan库是进行生物序列分析的一个现代的C 库,目前有seqan2, seqan3两个版本,seqan3正在开发当中 我打算应用seqan库实现一个简单的注释程序,因为seqan3暂时还未实现gtf文件的相关操作,因此选用seqan2

seqan是header-only的库,因此无需添加lib,只要包含头文件即可使用

定义别名

为了使用简洁,定义常用类型的别名

代码语言:javascript复制
typedef seqan::FragmentStore<> TStore;
typedef seqan::Value<TStore::TAnnotationStore>::Type TAnnotation;
typedef TAnnotation::TId TId;
typedef TAnnotation::TPos TPos;
typedef seqan::IntervalAndCargo<TPos, TId> TInterval;
typedef seqan::IntervalTree<TPos, TId> TIntervalTree;
typedef seqan::String<TIntervalTree> TIntervalTrees;
typedef seqan::Iterator<TStore const, seqan::AnnotationTree<> >::Type TCIterator;
typedef seqan::Iterator<TStore, seqan::AnnotationTree<> >::Type TIterator;
typedef seqan::String<TId> TIds;
typedef seqan::BamAlignmentRecord BamRecord;

gtf文件的加载

直接上代码:

代码语言:javascript复制
seqan::FragmentStore<> store;
seqan::GffFileIn annotationFile;
if (!seqan::open(annotationFile, gtf_file.c_str()))
{
    return;
}
readRecords(store, annotationFile);

可以看到,只要几行代码就将gtf文件的数据读取到内存中;使用FragmentStore来管理内存

gtf数据在内存中的存储,可以被视为关系型数据库,每一行表示一个gene,因此通过唯一ID可以访问gene数据,而gene数据是树状结构

想要遍历gtf数据,首先拿到根节点迭代器,然后使用树的遍历方式即可

构建interval tree

代码语言:javascript复制
seqan::String<seqan::String<TInterval>> intervals;
int numContigs = seqan::length(store.contigStore);
resize(intervals, numContigs);

TIterator it = seqan::begin(store, seqan::AnnotationTree<>());
if (!goDown(it))
{
    return;
}
do
{
    SEQAN_ASSERT_EQ(getType(it), "gene");
    TPos beginPos = getAnnotation(it).beginPos;
    TPos endPos = getAnnotation(it).endPos;
    TId contigId = getAnnotation(it).contigId;
    if (beginPos > endPos)
        std::swap(beginPos, endPos);
    appendValue(intervals[contigId], TInterval(beginPos, endPos, value(it)));
} while (goRight(it));

TIntervalTrees intervalTrees;
resize(intervalTrees, numContigs);

SEQAN_OMP_PRAGMA(parallel for)
for (int i = 0; i < numContigs;   i)
    seqan::createIntervalTree(intervalTrees[i], intervals[i]);

要构建线段树intervalTrees,首先得有一组线段intervals.通过遍历gtf数据,对每个gene构建一个interval,加入intervals,这里注意chromosome之间无关联,应分别建立数据;最后通过createIntervalTree接口构建intervalTrees,利用chromosome之间独立的特性,使用openmp加速构建过程

注释

代码语言:javascript复制
// 打开输入bam
seqan::BamFileIn inFile;
seqan::open(inFile, inputBamFilename.c_str());
seqan::BamHeader header;
seqan::readHeader(header, inFile);

// 打开输出bam,注意初始化header
seqan::BamFileOut fileOut;
fileOut.context = seqan::context(inFile);
seqan::setFormat(fileOut, seqan::Bam());
seqan::open(fileOut, outputBamFilename.c_str(), seqan::OPEN_WRONLY |seqan::OPEN_CREATE);
seqan::writeHeader(fileOut, header);

// 遍历bam中每条read
while (!seqan::atEnd(inFile))
{
    seqan::readRecord(record, inFile);
    TPos queryBegin = record.beginPos 1;
    // 这里是根据read的cigar信息计算出长度,省略部分代码
    TPos queryEnd = queryBegin   getReferenceLength(record.cigar);

    TIds result;
    if (record.rID < seqan::length(intervalTrees))
        seqan::findIntervals(result, intervalTrees[record.rID], queryBegin, queryEnd);

    /*
    *result记录了与当前read有overlap的gene在数据库中的唯一ID,由于计算逻辑实现过长
    *接下来省略对locusFunction等的计算代码,result的使用简略记录下,通过迭代器访问原始gtf数据
    *TIterator it;
    *for (unsigned j = 0; j < seqan::length(result);   j)
    *{
    *   int id = result[j];
    *   goTo(it, id);
    *   ...
    *}
    */

    // 更新read的tag信息,示例会生成tag信息: GE:Z:gene_name (中间的Z表示value为字符串)
    seqan::BamTagsDict tags(record.tags);
    seqan::setTagValue(tags, "GE", "gene_name");

    // 输出bam
    seqan::writeRecord(fileOut, record);
}

不同的注释逻辑自然实现不同,所以这里仅给出代码结构,更多细节要多阅读seqan库的文档,还是挺详细的

优化

一些预定义宏可能有加速效果

  • SEQAN_ASYNC_IO=1 允许异步输入输出操作
  • SEQAN_BGZF_NUM_THREADS=value 读写bam文件使用的线程数

其他的就是使用性能分析工具如valgrind,gprof等找出瓶颈并针对性优化

问题总结

编译问题

Q:error MSB8036: The Windows SDK version 8.1 was not found A:控制面板-应用程序-修改vs studio-勾选上通用工具中的win10SDK,重新安装

Q:No CMAKE_CXX_COMPILER could be found A:删掉缓存,重新编译

Q:windows下的项目配置 A:配置属性-C/C -语言 复合模式选择否,启用运行时类型信息选择是(/GR) OpenMP支持选择是;字符集选择多字节字符集;警告等级选择/W2;添加zlib,用于读取bam文件,注意x86和x64不要搞混

Q:预处理设置 A:

代码语言:javascript复制
WIN32WINDOWS
SEQAN_ENABLE_DEBUG=1
SEQAN_GLOBAL_EXCEPTION_HANDLER=1
_WIN32_WINNT=0x0600
WINVER=0x0600
_SCL_SECURE_NO_WARNINGS
_CRT_SECURE_NO_WARNINGS
NOMINMAX
SEQAN_HAS_EXECINFO=0
SEQAN_HAS_OPENMP=1
SEQAN_APP_VERSION=”1.5.8”
SEQAN_REVISION=”f5f6583”
SEQAN_DATE=”2019-08-02_14:42:28 0000”
CMAKE_INTDIR=”Debug”

代码错误

Q:getValueByKey接口调用异常 A:修改代码

代码语言:javascript复制
// 注释掉此接口
//template <typename TFragmentStore, typename TSpec, typename TKey>
//inline CharString
//getValueByKey(
//    Iter<TFragmentStore, AnnotationTree<TSpec> > const & it,
//    TKey const & key)
//{
//    return annotationGetValueByKey(*it.store, getAnnotation(it), key);
//}

// FragmentStore<TSpec, TConfig> & fragStore, 参数加const
template <typename TSpec, typename TConfig, typename TAnnotation, typename TKey, typename TValue>
inline bool
annotationGetValueByKey (
    TValue & value,
    FragmentStore<TSpec, TConfig> const & fragStore,
    TAnnotation const & annotation,
    TKey const & key)

参考

  • seqan官网
  • github仓库
  • API文档
  • Simple RNA-Seq

0 人点赞