seqan库是进行生物序列分析的一个现代的C++库,目前有seqan2, seqan3两个版本,seqan3正在开发当中
我打算应用seqan库实现一个简单的注释程序,因为seqan3暂时还未实现gtf文件的相关操作,因此选用seqan2
seqan是header-only的库,因此无需添加lib,只要包含头文件即可使用
定义别名
为了使用简洁,定义常用类型的别名
1 2 3 4 5 6 7 8 9 10 11
| 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文件的加载
直接上代码:
1 2 3 4 5 6 7
| 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 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加速构建过程
注释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| seqan::BamFileIn inFile; seqan::open(inFile, inputBamFilename.c_str()); seqan::BamHeader header; seqan::readHeader(header, inFile);
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);
while (!seqan::atEnd(inFile)) { seqan::readRecord(record, inFile); TPos queryBegin = record.beginPos+1; TPos queryEnd = queryBegin + getReferenceLength(record.cigar);
TIds result; if (record.rID < seqan::length(intervalTrees)) seqan::findIntervals(result, intervalTrees[record.rID], queryBegin, queryEnd);
seqan::BamTagsDict tags(record.tags); seqan::setTagValue(tags, "GE", "gene_name");
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:
WIN32_WINDOWS
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:修改代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
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)
|
参考