]> git.donarmstrong.com Git - rsem.git/blob - PairedEndQModel.h
Improved warning messages in rsem-gen-transcript-plots
[rsem.git] / PairedEndQModel.h
1 #ifndef PAIREDENDQMODEL_H_
2 #define PAIREDENDQMODEL_H_
3
4 #include<cmath>
5 #include<cstdio>
6 #include<cassert>
7 #include<cstring>
8 #include<string>
9 #include<algorithm>
10 #include<sstream>
11
12 #include "utils.h"
13 #include "my_assert.h"
14 #include "Orientation.h"
15 #include "LenDist.h"
16 #include "RSPD.h"
17 #include "QualDist.h"
18 #include "QProfile.h"
19 #include "NoiseQProfile.h"
20
21 #include "ModelParams.h"
22 #include "RefSeq.h"
23 #include "Refs.h"
24 #include "SingleReadQ.h"
25 #include "PairedEndReadQ.h"
26 #include "PairedEndHit.h"
27 #include "ReadReader.h"
28
29 #include "simul.h"
30
31 class PairedEndQModel {
32 public:
33         PairedEndQModel(Refs* refs = NULL) {
34                 this->refs = refs;
35                 M = (refs != NULL ? refs->getM() : 0);
36                 memset(N, 0, sizeof(N));
37                 estRSPD = false;
38                 needCalcConPrb = true;
39
40                 ori = new Orientation();
41                 gld = new LenDist();
42                 rspd = new RSPD(estRSPD);
43                 qd = new QualDist();
44                 qpro = new QProfile();
45                 nqpro = new NoiseQProfile();
46                 mld = new LenDist();
47
48                 mw = NULL;
49                 seedLen = 0;
50         }
51
52         //If it is not a master node, only init & update can be used!
53         PairedEndQModel(ModelParams& params, bool isMaster = true) {
54                 M = params.M;
55                 memcpy(N, params.N, sizeof(params.N));
56                 refs = params.refs;
57                 estRSPD = params.estRSPD;
58                 seedLen = params.seedLen;
59                 needCalcConPrb = true;
60
61                 ori = NULL; gld = NULL; rspd = NULL; qd = NULL; qpro = NULL; nqpro = NULL; mld = NULL;
62                 mw = NULL;
63
64                 if (isMaster) {
65                         if (!estRSPD) rspd = new RSPD(estRSPD);
66                         qd = new QualDist();
67                         mld = new LenDist(params.mate_minL, params.mate_maxL);
68                 }
69
70                 ori = new Orientation(params.probF);
71                 gld = new LenDist(params.minL, params.maxL);
72                 if (estRSPD) rspd = new RSPD(estRSPD, params.B);
73                 qpro = new QProfile();
74                 nqpro = new NoiseQProfile();
75         }
76
77         ~PairedEndQModel() {
78                 refs = NULL;
79                 if (ori != NULL) delete ori;
80                 if (gld != NULL) delete gld;
81                 if (rspd != NULL) delete rspd;
82                 if (qd != NULL) delete qd;
83                 if (qpro != NULL) delete qpro;
84                 if (nqpro != NULL) delete nqpro;
85                 if (mld != NULL) delete mld;
86                 if (mw != NULL) delete mw;
87         }
88
89         void estimateFromReads(const char*);
90
91         //if prob is too small, just make it 0
92         double getConPrb(const PairedEndReadQ& read, const PairedEndHit& hit) {
93                 if (read.isLowQuality()) return 0.0;
94
95                 double prob;
96                 int sid = hit.getSid();
97                 RefSeq &ref = refs->getRef(sid);
98                 int dir = hit.getDir();
99                 int pos = hit.getPos();
100                 int fullLen = ref.getFullLen();
101                 int totLen = ref.getTotLen();
102                 int insertLen = hit.getInsertL();
103
104                 int fpos = (dir == 0 ? pos : totLen - pos - insertLen); // the aligned position reported in SAM file, should be a coordinate in forward strand
105                 int effL = std::min(fullLen, totLen - insertLen + 1);
106
107                 general_assert(fpos >= 0, "The alignment of fragment " + read.getName() + " to transcript " + itos(sid) + " starts at " + itos(fpos) + \
108                                 " from the forward direction, which should be a non-negative number! " + \
109                                 "It is possible that the aligner you use gave different read lengths for a same read in SAM file.");
110                 general_assert(fpos + insertLen <= totLen,"Fragment " + read.getName() + " is hung over the end of transcript " + itos(sid) + "! " \
111                                 + "It is possible that the aligner you use gave different read lengths for a same read in SAM file.");
112                 general_assert(insertLen <= totLen, "Fragment " + read.getName() + " has length " + itos(insertLen) + ", but it is aligned to transcript " \
113                                 + itos(sid) + ", whose length (" + itos(totLen) + ") is shorter than the fragment's length!");
114
115                 if (fpos >= fullLen || ref.getMask(fpos)) return 0.0; // For paired-end model, fpos is the seedPos
116
117                 prob = ori->getProb(dir) * gld->getAdjustedProb(insertLen, totLen) *
118                        rspd->getAdjustedProb(fpos, effL, fullLen);
119
120                 const SingleReadQ& mate1 = read.getMate1();
121                 prob *= mld->getAdjustedProb(mate1.getReadLength(), insertLen) *
122                         qpro->getProb(mate1.getReadSeq(), mate1.getQScore(), ref, pos, dir);
123
124                 const SingleReadQ& mate2 = read.getMate2();
125                 int m2pos = totLen - pos - insertLen;
126                 int m2dir = !dir;
127                 prob *= mld->getAdjustedProb(mate2.getReadLength(), hit.getInsertL()) *
128                         qpro->getProb(mate2.getReadSeq(), mate2.getQScore(), ref, m2pos, m2dir);
129
130                 if (prob < EPSILON) { prob = 0.0; }
131
132                 prob = (mw[sid] < EPSILON ? 0.0 : prob / mw[sid]);
133
134                 return prob;
135         }
136
137         double getNoiseConPrb(const PairedEndReadQ& read) {
138                 if (read.isLowQuality()) return 0.0;
139
140                 double prob;
141                 const SingleReadQ& mate1 = read.getMate1();
142                 const SingleReadQ& mate2 = read.getMate2();
143
144                 prob = mld->getProb(mate1.getReadLength()) * nqpro->getProb(mate1.getReadSeq(), mate1.getQScore());
145                 prob *= mld->getProb(mate2.getReadLength()) * nqpro->getProb(mate2.getReadSeq(), mate2.getQScore());
146
147                 if (prob < EPSILON) { prob = 0.0; }
148
149                 prob = (mw[0] < EPSILON ? 0.0: prob / mw[0]);
150
151                 return prob;
152         }
153
154         double getLogP() { return nqpro->getLogP(); }
155
156         void init();
157
158         void update(const PairedEndReadQ& read, const PairedEndHit& hit, double frac) {
159                 if (read.isLowQuality() || frac < EPSILON) return;
160
161                 RefSeq& ref = refs->getRef(hit.getSid());
162                 const SingleReadQ& mate1 = read.getMate1();
163                 const SingleReadQ& mate2 = read.getMate2();
164
165                 gld->update(hit.getInsertL(), frac);
166                 if (estRSPD) {
167                         int fpos = (hit.getDir() == 0 ? hit.getPos() : ref.getTotLen() - hit.getPos() - hit.getInsertL());
168                         rspd->update(fpos, ref.getFullLen(), frac);
169                 }
170                 qpro->update(mate1.getReadSeq(), mate1.getQScore(), ref, hit.getPos(), hit.getDir(), frac);
171
172                 int m2pos = ref.getTotLen() - hit.getPos() - hit.getInsertL();
173                 int m2dir = !hit.getDir();
174                 qpro->update(mate2.getReadSeq(), mate2.getQScore(), ref, m2pos, m2dir, frac);
175         }
176
177         void updateNoise(const PairedEndReadQ& read, double frac) {
178                 if (read.isLowQuality() || frac < EPSILON) return;
179
180                 const SingleReadQ& mate1 = read.getMate1();
181                 const SingleReadQ& mate2 = read.getMate2();
182
183                 nqpro->update(mate1.getReadSeq(), mate1.getQScore(), frac);
184                 nqpro->update(mate2.getReadSeq(), mate2.getQScore(), frac);
185         }
186
187         void finish();
188
189         void collect(const PairedEndQModel&);
190
191         bool getNeedCalcConPrb() { return needCalcConPrb; }
192         void setNeedCalcConPrb(bool value) { needCalcConPrb = value; }
193
194         void read(const char*);
195         void write(const char*);
196
197         const LenDist& getGLD() { return *gld; }
198
199         void startSimulation(simul*, double*);
200         bool simulate(int, PairedEndReadQ&, int&);
201         void finishSimulation();
202
203         //Use it after function 'read' or 'estimateFromReads'
204         double* getMW() { 
205           assert(mw != NULL);
206           return mw;
207         }
208
209         int getModelType() const { return model_type; }
210  
211 private:
212         static const int model_type = 3;
213         static const int read_type = 3;
214
215         int M;
216         int N[3];
217         Refs *refs;
218         int seedLen;
219
220         bool estRSPD;
221         bool needCalcConPrb; //true need, false does not need
222
223         Orientation *ori;
224         LenDist *gld, *mld; //mld1 mate_length_dist
225         RSPD *rspd;
226         QualDist *qd;
227         QProfile *qpro;
228         NoiseQProfile *nqpro;
229
230         simul *sampler; // for simulation
231         double *theta_cdf; // for simulation
232
233         double *mw; // for masking
234
235         void calcMW();
236 };
237
238 void PairedEndQModel::estimateFromReads(const char* readFN) {
239         int s;
240         char readFs[2][STRLEN];
241     PairedEndReadQ read;
242
243     mld->init();
244     for (int i = 0; i < 3; i++)
245         if (N[i] > 0) {
246                 genReadFileNames(readFN, i, read_type, s, readFs);
247                 ReadReader<PairedEndReadQ> reader(s, readFs, refs->hasPolyA(), seedLen); // allow calculation of calc_lq() function
248
249                 int cnt = 0;
250                 while (reader.next(read)) {
251                         SingleReadQ mate1 = read.getMate1();
252                         SingleReadQ mate2 = read.getMate2();
253
254                         if (!read.isLowQuality()) {
255                                 mld->update(mate1.getReadLength(), 1.0);
256                                 mld->update(mate2.getReadLength(), 1.0);
257
258                                 qd->update(mate1.getQScore());
259                                 qd->update(mate2.getQScore());
260                           
261                                 if (i == 0) {
262                                         nqpro->updateC(mate1.getReadSeq(), mate1.getQScore());
263                                         nqpro->updateC(mate2.getReadSeq(), mate2.getQScore());
264                                 }
265                         }
266                         else if (verbose && (mate1.getReadLength() < seedLen || mate2.getReadLength() < seedLen)) {
267                                 printf("Warning: Read %s is ignored due to at least one of the mates' length < seed length %d!\n", read.getName().c_str(), seedLen);
268                         }
269
270                         ++cnt;
271                         if (verbose && cnt % 1000000 == 0) { printf("%d READS PROCESSED\n", cnt); }
272                 }
273
274                 if (verbose) { printf("estimateFromReads, N%d finished.\n", i); }
275         }
276
277     mld->finish();
278     qd->finish();
279     nqpro->calcInitParams();
280
281     mw = new double[M + 1];
282     calcMW();
283 }
284
285 void PairedEndQModel::init() {
286         gld->init();
287         if (estRSPD) rspd->init();
288         qpro->init();
289         nqpro->init();
290 }
291
292 void PairedEndQModel::finish() {
293         gld->finish();
294         if (estRSPD) rspd->finish();
295         qpro->finish();
296         nqpro->finish();
297         needCalcConPrb = true;
298         calcMW();
299 }
300
301 void PairedEndQModel::collect(const PairedEndQModel& o) {
302         gld->collect(*(o.gld));
303         if (estRSPD) rspd->collect(*(o.rspd));
304         qpro->collect(*(o.qpro));
305         nqpro->collect(*(o.nqpro));
306 }
307
308 //Only master node can call
309 void PairedEndQModel::read(const char* inpF) {
310         int val;
311         FILE *fi = fopen(inpF, "r");
312         if (fi == NULL) { fprintf(stderr, "Cannot open %s! It may not exist.\n", inpF); exit(-1); }
313
314         assert(fscanf(fi, "%d", &val) == 1);
315         assert(val == model_type);
316
317         ori->read(fi);
318         gld->read(fi);
319         mld->read(fi);
320         rspd->read(fi);
321         qd->read(fi);
322         qpro->read(fi);
323         nqpro->read(fi);
324
325         if (fscanf(fi, "%d", &val) == 1) {
326                 if (M == 0) M = val;
327                 if (M == val) {
328                         mw = new double[M + 1];
329                         for (int i = 0; i <= M; i++) assert(fscanf(fi, "%lf", &mw[i]) == 1);
330                 }
331         }
332
333
334         fclose(fi);
335 }
336
337 //Only master node can call. Only be called at EM.cpp
338 void PairedEndQModel::write(const char* outF) {
339         FILE *fo = fopen(outF, "w");
340
341         fprintf(fo, "%d\n", model_type);
342         fprintf(fo, "\n");
343
344         ori->write(fo);  fprintf(fo, "\n");
345         gld->write(fo);  fprintf(fo, "\n");
346         mld->write(fo);  fprintf(fo, "\n");
347         rspd->write(fo); fprintf(fo, "\n");
348         qd->write(fo);   fprintf(fo, "\n");
349         qpro->write(fo); fprintf(fo, "\n");
350         nqpro->write(fo);
351
352         if (mw != NULL) {
353           fprintf(fo, "\n%d\n", M);
354           for (int i = 0; i < M; i++) {
355             fprintf(fo, "%.15g ", mw[i]);
356           }
357           fprintf(fo, "%.15g\n", mw[M]);
358         }
359
360         fclose(fo);
361 }
362
363 void PairedEndQModel::startSimulation(simul* sampler, double* theta) {
364         this->sampler = sampler;
365
366         theta_cdf = new double[M + 1];
367         for (int i = 0; i <= M; i++) {
368                 theta_cdf[i] = theta[i];
369                 if (i > 0) theta_cdf[i] += theta_cdf[i - 1];
370         }
371
372         rspd->startSimulation(M, refs);
373         qd->startSimulation();
374         qpro->startSimulation();
375         nqpro->startSimulation();
376 }
377
378 bool PairedEndQModel::simulate(int rid, PairedEndReadQ& read, int& sid) {
379         int dir, pos;
380         int insertL, mateL1, mateL2;
381         std::string name;
382         std::string qual1, qual2, readseq1, readseq2;
383         std::ostringstream strout;
384
385         sid = sampler->sample(theta_cdf, M + 1);
386
387         if (sid == 0) {
388                 dir = pos = insertL = 0;
389                 mateL1 = mld->simulate(sampler, -1);
390                 qual1 = qd->simulate(sampler, mateL1);
391                 readseq1 = nqpro->simulate(sampler, mateL1, qual1);
392
393                 mateL2 = mld->simulate(sampler, -1);
394                 qual2 = qd->simulate(sampler, mateL2);
395                 readseq2 = nqpro->simulate(sampler, mateL2, qual2);
396         }
397         else {
398                 RefSeq &ref = refs->getRef(sid);
399                 dir = ori->simulate(sampler);
400                 insertL = gld->simulate(sampler, ref.getTotLen());
401                 if (insertL < 0) return false;
402                 int effL = std::min(ref.getFullLen(), ref.getTotLen() - insertL + 1);
403                 pos = rspd->simulate(sampler, sid, effL);
404                 if (pos < 0) return false;
405                 if (dir > 0) pos = ref.getTotLen() - pos - insertL;
406
407                 mateL1 = mld->simulate(sampler, insertL);
408                 qual1 = qd->simulate(sampler, mateL1);
409                 readseq1 = qpro->simulate(sampler, mateL1, pos, dir, qual1, ref);
410
411                 int m2pos = ref.getTotLen() - pos - insertL;
412                 int m2dir = !dir;
413
414                 mateL2 = mld->simulate(sampler, insertL);
415                 qual2 = qd->simulate(sampler, mateL2);
416                 readseq2 = qpro->simulate(sampler, mateL2, m2pos, m2dir, qual2, ref);
417         }
418
419         strout<<rid<<"_"<<dir<<"_"<<sid<<"_"<<pos<<"_"<<insertL;
420         name = strout.str();
421
422         read = PairedEndReadQ(SingleReadQ(name + "/1", readseq1, qual1), SingleReadQ(name + "/2", readseq2, qual2));
423
424         return true;
425 }
426
427 void PairedEndQModel::finishSimulation() {
428         delete[] theta_cdf;
429
430         rspd->finishSimulation();
431         qd->finishSimulation();
432         qpro->finishSimulation();
433         nqpro->finishSimulation();
434 }
435
436
437 void PairedEndQModel::calcMW() {
438         assert(mld->getMinL() >= seedLen);
439
440         memset(mw, 0, sizeof(double) * (M + 1));
441         mw[0] = 1.0;
442
443         for (int i = 1; i <= M; i++) {
444                 RefSeq& ref = refs->getRef(i);
445                 int totLen = ref.getTotLen();
446                 int fullLen = ref.getFullLen();
447                 int end = std::min(fullLen, totLen - gld->getMinL() + 1);
448                 double value = 0.0;
449                 int minL, maxL;
450                 int effL, pfpos;
451
452                 //seedPos is fpos here
453                 for (int seedPos = 0; seedPos < end; seedPos++)
454                         if (ref.getMask(seedPos)) {
455                                 minL = gld->getMinL();
456                                 maxL = std::min(gld->getMaxL(), totLen - seedPos);
457                                 pfpos = seedPos;
458                                 for (int fragLen = minL; fragLen <= maxL; fragLen++) {
459                                         effL = std::min(fullLen, totLen - fragLen + 1);
460                                         value += gld->getAdjustedProb(fragLen, totLen) * rspd->getAdjustedProb(pfpos, effL, fullLen);
461                                 }
462                         }
463     
464                 mw[i] = 1.0 - value;
465
466                 if (mw[i] < 1e-8) {
467                         //      fprintf(stderr, "Warning: %dth reference sequence is masked for almost all positions!\n", i);
468                         mw[i] = 0.0;
469                 }
470         }
471 }
472
473 #endif /* PAIREDENDQMODEL_H_ */