diff --git a/src/common.h b/src/common.h index 9845f97..790abfb 100644 --- a/src/common.h +++ b/src/common.h @@ -1,7 +1,7 @@ #ifndef COMMON_H #define COMMON_H -#define FUSIONSCAN_VER "0.4.0" +#define FUSIONSCAN_VER "0.5.0" #define _DEBUG true diff --git a/src/fusionscan.cpp b/src/fusionscan.cpp index 4a54a00..aba2f2d 100644 --- a/src/fusionscan.cpp +++ b/src/fusionscan.cpp @@ -6,23 +6,24 @@ #include "pescanner.h" #include "util.h" -FusionScan::FusionScan(string fusionFile, string refFile, string read1File, string read2File, string html, int threadNum){ +FusionScan::FusionScan(string fusionFile, string refFile, string read1File, string read2File, string html, string json, int threadNum){ mRead1File = read1File; mRead2File = read2File; mFusionFile = fusionFile; mRefFile = refFile; mHtmlFile = html; + mJsonFile = json; mThreadNum = threadNum; } bool FusionScan::scan(){ vector fusions = Fusion::parseCsv(mFusionFile); if(mRead2File != ""){ - PairEndScanner pescanner( mFusionFile, mRefFile, mRead1File, mRead2File, mHtmlFile, mThreadNum); + PairEndScanner pescanner( mFusionFile, mRefFile, mRead1File, mRead2File, mHtmlFile, mJsonFile, mThreadNum); return pescanner.scan(); } else{ - SingleEndScanner sescanner( mFusionFile, mRefFile, mRead1File, mHtmlFile, mThreadNum); + SingleEndScanner sescanner( mFusionFile, mRefFile, mRead1File, mHtmlFile, mJsonFile, mThreadNum); return sescanner.scan(); } } diff --git a/src/fusionscan.h b/src/fusionscan.h index 58d8e1d..a41450e 100644 --- a/src/fusionscan.h +++ b/src/fusionscan.h @@ -12,7 +12,7 @@ using namespace std; class FusionScan{ public: - FusionScan(string fusionFile, string refFile, string read1File, string read2File, string html, int threadNum); + FusionScan(string fusionFile, string refFile, string read1File, string read2File, string html, string json, int threadNum); bool scan(); private: @@ -20,6 +20,7 @@ class FusionScan{ string mRead1File; string mRead2File; string mHtmlFile; + string mJsonFile; string mRefFile; int mThreadNum; }; diff --git a/src/jsonreporter.cpp b/src/jsonreporter.cpp new file mode 100644 index 0000000..2c1fd20 --- /dev/null +++ b/src/jsonreporter.cpp @@ -0,0 +1,82 @@ +#include "jsonreporter.h" +#include "common.h" +#include +#include "globalsettings.h" + +JsonReporter::JsonReporter(string filename, FusionMapper* mapper){ + mFusionMapper = mapper; + mFusionResults = mapper->mFusionResults; + mFilename = filename; + mFile.open(mFilename.c_str(), ifstream::out); +} + +JsonReporter::~JsonReporter(){ + mFile.close(); +} + +extern string getCurrentSystemTime(); +extern string command; + +void JsonReporter::run() { + mFile << "{" << endl; + mFile << "\t\"command\":\"" << command << "\"," << endl; + mFile << "\t\"version\":\"" << FUSIONSCAN_VER << "\"," << endl; + mFile << "\t\"time\":\"" << getCurrentSystemTime() << "\"," << endl; + mFile << "\t\"mutations\":{"; + + bool isFirstMut = true; + for(int i=0;i matches = fusion.mMatches; + + if(isFirstMut) { + mFile << endl; + isFirstMut = false; + } + else + mFile << "," << endl; + + mFile << "\t\t\"" << fusion.mTitle << "\":{" << endl; + mFile << "\t\t\t\"" << "left" << "\":{" << endl; + mFile << "\t\t\t\t\"" << "gene_name" << "\":" << "\"" << fusion.mLeftGene.mName << "\"," << endl; + mFile << "\t\t\t\t\"" << "gene_chr" << "\":" << "\"" << fusion.mLeftGene.mChr << "\"," << endl; + mFile << "\t\t\t\t\"" << "position" << "\":" << fusion.mLeftGP.position << "," << endl; + mFile << "\t\t\t\t\"" << "reference" << "\":" << "\"" << fusion.mLeftRef << "\"," << endl; + mFile << "\t\t\t\t\"" << "ref_ext" << "\":" << "\"" << fusion.mLeftRefExt << "\"," << endl; + mFile << "\t\t\t\t\"" << "pos_str" << "\":" << "\"" << fusion.mLeftPos << "\"," << endl; + mFile << "\t\t\t\t\"" << "exon_or_intron" << "\":" << "\"" << (fusion.mLeftIsExon?"exon":"intron") << "\"," << endl; + mFile << "\t\t\t\t\"" << "exon_or_intron_id" << "\":" << fusion.mLeftExonOrIntronID << "," << endl; + mFile << "\t\t\t\t\"" << "strand" << "\":" << "\"" << (fusion.isLeftProteinForward()?"forward":"reversed") << "\"" << endl; + mFile << "\t\t\t}, " << endl; + mFile << "\t\t\t\"" << "right" << "\":{" << endl; + mFile << "\t\t\t\t\"" << "gene_name" << "\":" << "\"" << fusion.mRightGene.mName << "\"," << endl; + mFile << "\t\t\t\t\"" << "gene_chr" << "\":" << "\"" << fusion.mRightGene.mChr << "\"," << endl; + mFile << "\t\t\t\t\"" << "position" << "\":" << fusion.mRightGP.position << "," << endl; + mFile << "\t\t\t\t\"" << "reference" << "\":" << "\"" << fusion.mRightRef << "\"," << endl; + mFile << "\t\t\t\t\"" << "ref_ext" << "\":" << "\"" << fusion.mRightRefExt << "\"," << endl; + mFile << "\t\t\t\t\"" << "pos_str" << "\":" << "\"" << fusion.mRightPos << "\"," << endl; + mFile << "\t\t\t\t\"" << "exon_or_intron" << "\":" << "\"" << (fusion.mRightIsExon?"exon":"intron") << "\"," << endl; + mFile << "\t\t\t\t\"" << "exon_or_intron_id" << "\":" << fusion.mRightExonOrIntronID << "," << endl; + mFile << "\t\t\t\t\"" << "strand" << "\":" << "\"" << (fusion.isRightProteinForward()?"forward":"reversed") << "\"" << endl; + mFile << "\t\t\t}, " << endl; + + mFile << "\t\t\t\"" << "unique" << "\":" << fusion.mUnique << "," << endl; + mFile << "\t\t\t\"" << "reads" << "\":[" << endl; + for(int m=0; mmReadBreak << "," << endl; + mFile << "\t\t\t\t\t\"" << "strand" << "\":" << "\"" << (matches[m]->mReversed?"reversed":"forward") << "\"," << endl; + matches[m]->printReadToJson(mFile, "\t\t\t\t\t"); + mFile << "\t\t\t\t}"; + if(m!=matches.size()-1) + mFile << ","; + mFile << endl; + } + mFile << "\t\t\t]" << endl; + mFile << "\t\t}"; + } + + mFile << endl; + mFile << "\t}" << endl; + mFile << "}" << endl; +} \ No newline at end of file diff --git a/src/jsonreporter.h b/src/jsonreporter.h new file mode 100644 index 0000000..34efcdb --- /dev/null +++ b/src/jsonreporter.h @@ -0,0 +1,29 @@ +#ifndef JSON_REPORTER_H +#define JSON_REPORTER_H + +#include +#include +#include +#include "read.h" +#include "fusion.h" +#include "match.h" +#include +#include +#include "fusionmapper.h" + +using namespace std; + +class JsonReporter{ +public: + JsonReporter(string filename, FusionMapper* mapper); + ~JsonReporter(); + void run(); + +private: + string mFilename; + FusionMapper* mFusionMapper; + ofstream mFile; + vector mFusionResults; +}; + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index fc2802b..1ba8225 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,13 +23,15 @@ int main(int argc, char* argv[]){ cmd.add("ref", 'r', "reference fasta file name", true, ""); cmd.add("unique", 'u', "specify the least supporting read number is required to report a fusion, default is 2", false, 2); cmd.add("deletion", 'd', "specify the least deletion length of a intra-gene deletion to report, default is 50", false, 50); - cmd.add("html", 'h', "file name to store html report, default is genefuse.html", false, "genefuse.html"); + cmd.add("html", 'h', "file name to store HTML report, default is genefuse.html", false, "genefuse.html"); + cmd.add("json", 'j', "file name to store JSON report, default is genefuse.json", false, "genefuse.json"); cmd.add("thread", 't', "worker thread number, default is 4", false, 4); cmd.parse_check(argc, argv); string r1file = cmd.get("read1"); string r2file = cmd.get("read2"); string fusionFile = cmd.get("fusion"); string html = cmd.get("html"); + string json = cmd.get("json"); string refFile = cmd.get("ref"); int threadNum = cmd.get("thread"); int unique = cmd.get("unique"); @@ -61,7 +63,7 @@ int main(int argc, char* argv[]){ time_t t1 = time(NULL); - FusionScan fs(fusionFile, refFile, r1file, r2file, html, threadNum); + FusionScan fs(fusionFile, refFile, r1file, r2file, html, json, threadNum); fs.scan(); time_t t2 = time(NULL); diff --git a/src/match.cpp b/src/match.cpp index 7349acc..1f81a6d 100644 --- a/src/match.cpp +++ b/src/match.cpp @@ -87,3 +87,8 @@ int Match::countUnique(vector& matches) { } return count; } + +void Match::printReadToJson(ofstream& file, string pad) { + file << pad << "\"seq\":" << "\"" << mRead->mSeq.mStr << "\"," << endl; + file << pad << "\"qual\":" << "\"" << mRead->mQuality << "\"" << endl; +} diff --git a/src/match.h b/src/match.h index 9fbb118..7d47bbe 100644 --- a/src/match.h +++ b/src/match.h @@ -26,6 +26,7 @@ class Match{ Match(Read* r, int readBreak, GenePos leftGP, GenePos rightGP, int gap, bool reversed = false); ~Match(); void print(); + void printReadToJson(ofstream& file, string pad); void printHtmlTD(ofstream& file); void printReadsToFile(ofstream& file); void setReversed(bool flag); diff --git a/src/pescanner.cpp b/src/pescanner.cpp index 61ef68c..1f8544f 100644 --- a/src/pescanner.cpp +++ b/src/pescanner.cpp @@ -7,13 +7,15 @@ #include #include #include "util.h" +#include "jsonreporter.h" -PairEndScanner::PairEndScanner(string fusionFile, string refFile, string read1File, string read2File, string html, int threadNum){ +PairEndScanner::PairEndScanner(string fusionFile, string refFile, string read1File, string read2File, string html, string json, int threadNum){ mRead1File = read1File; mRead2File = read2File; mFusionFile = fusionFile; mRefFile = refFile; mHtmlFile = html; + mJsonFile = json; mProduceFinished = false; mThreadNum = threadNum; mFusionMapper = NULL; @@ -53,6 +55,7 @@ bool PairEndScanner::scan(){ mFusionMapper->clusterMatches(); htmlReport(); + jsonReport(); mFusionMapper->freeMatches(); return true; @@ -266,3 +269,11 @@ void PairEndScanner::htmlReport() { HtmlReporter reporter(mHtmlFile, mFusionMapper); reporter.run(); } + +void PairEndScanner::jsonReport() { + if(mJsonFile == "") + return; + + JsonReporter reporter(mJsonFile, mFusionMapper); + reporter.run(); +} diff --git a/src/pescanner.h b/src/pescanner.h index 6d3c5ec..e7eb35d 100644 --- a/src/pescanner.h +++ b/src/pescanner.h @@ -38,11 +38,12 @@ typedef struct ReadPairRepository ReadPairRepository; class PairEndScanner{ public: - PairEndScanner(string fusionFile, string refFile, string read1File, string read2File, string html="", int threadnum=1); + PairEndScanner(string fusionFile, string refFile, string read1File, string read2File, string html, string json, int threadnum); ~PairEndScanner(); bool scan(); void textReport(); void htmlReport(); + void jsonReport(); private: bool scanPairEnd(ReadPairPack* pack); @@ -60,6 +61,7 @@ class PairEndScanner{ string mRead1File; string mRead2File; string mHtmlFile; + string mJsonFile; ReadPairRepository mRepo; bool mProduceFinished; std::mutex mFusionMtx; diff --git a/src/read.cpp b/src/read.cpp index d1cd2f9..05556c3 100644 --- a/src/read.cpp +++ b/src/read.cpp @@ -229,6 +229,8 @@ Read* ReadPair::fastMerge(){ } else { // add the quality of the pair to make a high qual mergedQual[offset+i] = qual1[offset+i] + qual2[i] - 33; + if(mergedQual[offset+i] >= 'Z') + mergedQual[offset+i] = 'Z'; } } delete rcRight; diff --git a/src/sescanner.cpp b/src/sescanner.cpp index 4e554ef..33681de 100644 --- a/src/sescanner.cpp +++ b/src/sescanner.cpp @@ -7,12 +7,14 @@ #include #include #include "util.h" +#include "jsonreporter.h" -SingleEndScanner::SingleEndScanner(string fusionFile, string refFile, string read1File, string html, int threadNum){ +SingleEndScanner::SingleEndScanner(string fusionFile, string refFile, string read1File, string html, string json, int threadNum){ mRead1File = read1File; mFusionFile = fusionFile; mRefFile = refFile; mHtmlFile = html; + mJsonFile = json; mProduceFinished = false; mThreadNum = threadNum; mFusionMapper = NULL; @@ -51,8 +53,8 @@ bool SingleEndScanner::scan(){ mFusionMapper->sortMatches(); mFusionMapper->clusterMatches(); - textReport(); htmlReport(); + jsonReport(); mFusionMapper->freeMatches(); @@ -224,3 +226,11 @@ void SingleEndScanner::htmlReport() { HtmlReporter reporter(mHtmlFile, mFusionMapper); reporter.run(); } + +void SingleEndScanner::jsonReport() { + if(mJsonFile == "") + return; + + JsonReporter reporter(mJsonFile, mFusionMapper); + reporter.run(); +} diff --git a/src/sescanner.h b/src/sescanner.h index ed44d3f..c96c115 100644 --- a/src/sescanner.h +++ b/src/sescanner.h @@ -38,11 +38,12 @@ typedef struct ReadRepository ReadRepository; class SingleEndScanner{ public: - SingleEndScanner(string fusionFile, string refFile, string read1File, string html="", int threadnum=1); + SingleEndScanner(string fusionFile, string refFile, string read1File, string html, string json, int threadnum); ~SingleEndScanner(); bool scan(); void textReport(); void htmlReport(); + void jsonReport(); private: bool scanSingleEnd(ReadPack* pack); @@ -60,6 +61,7 @@ class SingleEndScanner{ string mRead1File; string mRead2File; string mHtmlFile; + string mJsonFile; ReadRepository mRepo; bool mProduceFinished; std::mutex mFusionMtx;