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