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