Repository navigation
Expand file tree
/
Copy pathcollapse.cpp
More file actions
2430 lines (2100 loc) · 110 KB
/
Copy pathcollapse.cpp
File metadata and controls
2430 lines (2100 loc) · 110 KB
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*Copyright (c) 2015-2016 Deniz Yorukoglu. All rights reserved.*/
#include<stdio.h>
#include<iostream>
#include<fstream>
#include<sstream>
#include<assert.h>
#include<stdlib.h>
#include<string>
#include<string.h>
#include<tr1/unordered_map>
#include<time.h>
#include<sys/time.h>
#include<unistd.h>
#include<signal.h>
#include<vector>
#include<limits.h>
using namespace std;
//[FEATURES]: Takes FASTQ input and collapses (no quality values are considered)
//[DONE]: Preserve Identities of each single read while collapsing
//[DONE]: Integrate open closed form printing
//[DONE]: Long read name separation should be done here as well (otherwise it takes time to re-read and print the file).
//[DONE]: Switch to multiple input files (Containg a saparate read fastq file for each individual)
#define MAX_NUM_SAMPLES 65535 //MAX LIMIT ON NUMBER OF SAMPLES is 65535 (Due to MAX_unsigned_short limit) (SAMPLE = number of fastq files in the input dataset)
#define MAX_LINE_LEN 300 //Maximum number of bases in a given line in a read dataset as well as the reference (used for static allocation of strings)
#define N_COUNT_THRESHOLD 2 //Defunct -- Previously used for when a read should be disregarded when it has more than a certain number of unknown bases ('N')
#define MRSFAST_LRN_THRESHOLD 194 //this is the maximum read length that Mrsfast can safely handle (thus anything longer is separated into a different list)
#define BWA_LRN_THRESHOLD 5000000 // ideally 2 billion for BWA but linkConstruct buffer causes trouble //2 billion iis the maximum read length that BWA can safely handle (thus anything longer is separated into a different list)
#define GENERIC_LRN_THRESHOLD 194 //[TODO] Test for Bowtie2 and separate their upper limit as well
#define MAX_ID_DIGIT_LEN 10 //This is the maximum length of a compact read ID (though the actual reasonable limit is ~7 which equals to 192 billion reads!)
////////////////////////////////////////////////
//Different flags used for collapsing
////////////////////////////////////////////////
#define PAIRED_MODE 22 //Input dataset is paired end
#define SINGLE_MODE 11 //Input dataset is single end
#define NO_SPLIT_MODE 33 //Input dataset will be collapsed as whole reads
#define HALF_SPLIT_MODE 44 //Input dataset will be collapsed as half-split reads
#define THREEWAY_SPLIT_MODE 55 //Input dataset will be collapsed as threeway-split reads
#define BWA_MODE 17 //This requires special handling of read names ending with /1 and /2
#define BOWTIE_2_MODE 18 //This requires printing a faux *.fastw files since bowtie2 causes trouble with repeated '>' in read name but not repeated '@'
#define BWA_MEM_MODE 19 //This requires special handling of names ending with /0 through /9 ([TODO] a better fix will be needed for this since there will be a lot of special cases)
#define GENERIC_MODE 34 //Generic collapsing scheme with default CORA read name assignments in FASTA format
////////////////////////////////////////////////
unsigned char inputMode; //stores paired end or single end mode flag
unsigned char splitMode; //stores no split or half split mode flag
inline double getTime() //This is the function that gets timestamps
{
struct timeval t;
gettimeofday(&t, NULL);
return t.tv_sec+t.tv_usec/1000000.0;
}
char idDigitLen; //This stores how many characters each read identity will contain
#ifdef CHR_SHORT
#define INVALIDCHRCODE 65531 /// this is what's assigned when the k-mer doesn't exist in the reference
#else
#define INVALIDCHRCODE 251
#endif
struct hashItem //A hash item contains locus information + linked list of samples and counts having the read
{
#ifdef CHR_SHORT
unsigned short refCode;
#else
unsigned char refCode;
#endif
unsigned int refPos;
char refDir; //This is to store which direction the reference readmer is stored
//TODO(denizy) For speed improvement, for any name that uses less than a pointer size (store it directly inside) -- which saves a pointer lookup cost
//TODO(denizy) For both space and speed improvement, store all of these in a large static array - and point to the index (though a proper memory manager has to be added for growing names)
char* ident; //list of identities within hashed item (representation form is a simple character array)
unsigned int identCount; //as identCount grows, the capacity grows as idDigitLen * 0, 1, 2, 4, 8, 16 etc.
};
char RevCompChar[256];
void SetupRevCompChar()
{
RevCompChar['A'] = 'T';
RevCompChar['T'] = 'A';
RevCompChar['C'] = 'G';
RevCompChar['G'] = 'C';
RevCompChar['N'] = 'N';
}
//Check if the reverse complement of the given read-mer is lexicographically smaller than the original (if so, store it in revComp array)
inline bool CheckIfComplementIsEarlier(char* refStr, char revCompStr[], int readLen) //this is a slow way to check whether the reverse complement of the seqence is lexicographically smaller than itself (might make this faster)
{
for(int i=0; i<readLen; i++)
{
char compChar = RevCompChar[(int) refStr[readLen-1-i]];
if(refStr[i] < compChar)
{
return 0;
}
else
{
revCompStr[i] = compChar;
if(refStr[i] > compChar)
{
for(int k=i+1; k<readLen; k++)
{
revCompStr[k] = RevCompChar[(int) refStr[readLen-1-k]];
}
revCompStr[readLen] = '\0';
return 1;
}
}
}
revCompStr[readLen] = '\0';
return 0;
}
//Assigns the reverse complements for half-splits of a read -- the same idea as CheckIfComplementIsEarlier is used to prevent excessive base comparisons
inline void AssignHalfSplitComplementsAndDirections(char* readLine, char* compReadLine, int inputReadLength, bool& strandSwitchedFLAG_firstSplit, bool& strandSwitchedFLAG_secondSplit)
{
int halfLen = inputReadLength / 2; //Note that the inputReadLength may not be divisible by 2 (if so, the last base in forward direction is ignored)
char* forwFirstSplit = readLine;
char* compFirstSplit = compReadLine + halfLen;
char* forwSecondSplit = readLine + halfLen;
char* compSecondSplit = compReadLine;
for(int i=0; i<halfLen; i++)
{
compFirstSplit[i] = RevCompChar[(int) forwFirstSplit[halfLen-1-i]];
if(forwFirstSplit[i] < compFirstSplit[i])
{
strandSwitchedFLAG_firstSplit = 0;
break;
}
else if(forwFirstSplit[i] > compFirstSplit[i])
{
strandSwitchedFLAG_firstSplit = 1;
for(int k=i+1; k<halfLen; k++)
{
compFirstSplit[k] = RevCompChar[(int) forwFirstSplit[halfLen-1-k]];
}
compFirstSplit[halfLen] = '\0';
break;
}
}
for(int i=0; i<halfLen; i++)
{
compSecondSplit[i] = RevCompChar[(int) forwSecondSplit[halfLen-1-i]];
if(forwSecondSplit[i] < compSecondSplit[i])
{
strandSwitchedFLAG_secondSplit = 0;
break;
}
else if(forwSecondSplit[i] > compSecondSplit[i])
{
strandSwitchedFLAG_secondSplit = 1;
for(int k=i+1; k<halfLen; k++)
{
compSecondSplit[k] = RevCompChar[(int) forwSecondSplit[halfLen-1-k]];
}
break;
}
}
}
//Assigns the reverse complements for third-splits of a read -- the same idea as CheckIfComplementIsEarlier is used to prevent excessive base comparisons
inline void AssignThirdSplitComplementsAndDirections(char* readLine, char* compReadLine, int inputReadLength, bool& strandSwitchedFLAG_firstSplit, bool& strandSwitchedFLAG_secondSplit, bool& strandSwitchedFLAG_thirdSplit)
{
int thirdLen = inputReadLength / 3;
char* forwFirstSplit = readLine;
char* compFirstSplit = compReadLine + thirdLen + thirdLen;
char* forwSecondSplit = readLine + thirdLen;
char* compSecondSplit = compReadLine + thirdLen;
char* forwThirdSplit = readLine + thirdLen + thirdLen;
char* compThirdSplit = compReadLine;
for(int i=0; i<thirdLen; i++)
{
compFirstSplit[i] = RevCompChar[(int) forwFirstSplit[thirdLen-1-i]];
if(forwFirstSplit[i] < compFirstSplit[i])
{
strandSwitchedFLAG_firstSplit = 0;
break;
}
else if(forwFirstSplit[i] > compFirstSplit[i])
{
strandSwitchedFLAG_firstSplit = 1;
for(int k=i+1; k<thirdLen; k++)
{
compFirstSplit[k] = RevCompChar[(int) forwFirstSplit[thirdLen-1-k]];
}
compFirstSplit[thirdLen] = '\0';
break;
}
}
for(int i=0; i<thirdLen; i++)
{
compSecondSplit[i] = RevCompChar[(int) forwSecondSplit[thirdLen-1-i]];
if(forwSecondSplit[i] < compSecondSplit[i])
{
strandSwitchedFLAG_secondSplit = 0;
break;
}
else if(forwSecondSplit[i] > compSecondSplit[i])
{
strandSwitchedFLAG_secondSplit = 1;
for(int k=i+1; k<thirdLen; k++)
{
compSecondSplit[k] = RevCompChar[(int) forwSecondSplit[thirdLen-1-k]];
}
break;
}
}
for(int i=0; i<thirdLen; i++)
{
compThirdSplit[i] = RevCompChar[(int) forwThirdSplit[thirdLen-1-i]];
if(forwThirdSplit[i] < compThirdSplit[i])
{
strandSwitchedFLAG_thirdSplit = 0;
break;
}
else if(forwThirdSplit[i] > compThirdSplit[i])
{
strandSwitchedFLAG_thirdSplit = 1;
for(int k=i+1; k<thirdLen; k++)
{
compThirdSplit[k] = RevCompChar[(int) forwThirdSplit[thirdLen-1-k]];
}
break;
}
}
}
//checks if the current value is a power of 2 -- this check is for resizing without spending extra memory for storing capacity
inline bool IsLog2Integer(unsigned int val)
{
while(val % 2 == 0)
{
val/=2;
}
if(val == 1) //It divided till it became 1, meaning that it's a power of two
{
return true;
}
return false; //if it falls out of the loop it's not a two-power
}
unsigned int globalLRNCount; //This is the counter for LRN codes, in the LRN list (LRN = Long read Name = Encoded names that are too long for the off-the-shelf mapper used)
//Alphabet size of the read name encoding should be text readable otherwise off-the-shelf mappers can't read it (it can be made binary by modifying mappers' source)
#define IDENTITY_ALPHABET_START 33 //This is the starting character of the text readable alphabet "!"
#define IDENTITY_ALPHABET_END 126 //This is the ending character of the text readdable alphabet "~"
#define IDENTITY_ALPHABET_SIZE 94 //This is the full size of the alphabet per character
unsigned char curID[MAX_ID_DIGIT_LEN+2]; //Stores the encoded read ID for the currently processed read or split
//ID is stored as: direction for lowest bit (0 forward, 1 is reverse); if paired-end, mate id for the next lowest bit (0 is first mate, 1 is second);
// if half-split mode the split id for the next lowest bit (0 is first split, 1 is second split); remainder is for the order in which the read appears in the original dataset
//Quick incrementation of the read ID
inline void IncrementID(unsigned char prevDirection, unsigned char strandSwitchedFlag) //This incrementation works for both single and paired end modes
{
unsigned char incrAmount = (2 - prevDirection) + strandSwitchedFlag;
unsigned char curPos = idDigitLen - 1;
curID[curPos] += incrAmount;
while(curPos > 0 && curID[curPos] > IDENTITY_ALPHABET_END) //if curPos becomes 0 and satisfies property then it means that the idDigitLen was not properly created
{
curID[curPos] -= IDENTITY_ALPHABET_SIZE;
curID[curPos -1] ++;
curPos--;
}
}
//Prints read id in integer and character form
void DebugPrintID()
{
cout << "int: ";
for(int i=0; i<idDigitLen; i++)
{
cout << int(curID[i]) << " ";
}
cout << "\tchar: '";
for(int i=0; i<idDigitLen; i++)
{
cout << curID[i];
}
cout << "'" <<endl;
}
int repMapMode; //Which off-the-shelf mapper is going to used for repMap = representative mapping = coarse mapping -- depending on this the collaper will output different types of output
char globalLRNString[50]; //this stores the encoding of the current LRN name
//(#1#, #1143# etc -- the trick is that the length of the LRN is not divisible by idDigitLen (so that mapInfer can understand that it is not the real name but the LRN encoded ID)
inline void AssignGlobalLRN() //This assigns global LRN while making sure that length of the string is not divisible by idDigitLen (for differentiating between LRN and encoded chars)
{
unsigned char n = sprintf (globalLRNString+1, "%d", globalLRNCount);
globalLRNString[n+1] = '#';
if((n+2) % idDigitLen != 0) //Just keep it normal if not dividisble by idDigitLen
{
globalLRNString[n+2] = '\0';
}
else
{
globalLRNString[n+2] = '#';
globalLRNString[n+3] = '\0';
}
}
char dummyQualString[256]; //Stores "S" for the entire quality string, used since of Bowtie2 can process fasta files, so a fastq file with dummy quality strings is printed for coarse mapping
#define MAX_NUM_CHRS 65530 //Limit for number of chromosomes in the input -- If longer is needed convert hashItems character refID's to short refID's
char* fullRef[MAX_NUM_CHRS+2]; //char array array storing the reference bases (not compact -- 1 byte per base) -- Positions are 1-based ( fullRef[0] is empty )
unsigned int chrLens[MAX_NUM_CHRS+2]; //Each chromosome's length in fullRef
unsigned short numChrs; //Number of chromosomes in reference
//This function loads reference genome for a given .fa file with a corresponding .fa.fai file
void ReadReference(const string& refFile, int refLineLen)
{
string refFileFai = refFile + ".fai";
//Verifying refFileFai & reference size
ifstream finFai(refFileFai.c_str());
int chrCode = 0;
string faiLine;
while(getline(finFai, faiLine))
{
stringstream faiLineSS(faiLine);
string junk;
int ctgSize;
faiLineSS >> junk >> ctgSize;
chrCode++;
fullRef[chrCode] = (char *) calloc (ctgSize+MAX_LINE_LEN, sizeof(char));
chrLens[chrCode] = ctgSize;
}
numChrs = chrCode;
//Dummy space allocation for the 0th chromosome (will not be used)
fullRef[0] = (char *) malloc (MAX_LINE_LEN);
FILE* finRef = fopen(refFile.c_str(),"r");
cout << "Reading full reference..." << endl;
int curChrCode = 0;
int curChrPos = 1;
char* curChrPtr = fullRef[0];
char* ret;
do
{
ret = fgets(curChrPtr + curChrPos, MAX_LINE_LEN, finRef);
if(curChrPtr[curChrPos] == '>')
{
curChrCode++;
curChrPtr = fullRef[curChrCode];
curChrPos = 1;
}
else
{
curChrPos += refLineLen;
}
}while(ret!=NULL);
cout << "Renaming lowercases..." << endl;
for(unsigned short chr=1; chr<=numChrs; chr++)
{
char* curPtr = fullRef[chr];
curPtr[chrLens[chr] + 1] = '\0'; // Puts end of string markers for each chromosome, for easier while-loop search
int pos = 1;
while(curPtr[pos] != '\0')
{
if(curPtr[pos] > 'Z')
curPtr[pos] -= ('a'-'A');
pos++;
}
}
cout << "Finished loading reference." << endl;
}
////////////////////////////////////////////
// Functions related ro fragmentation
// - For large input datasets that won't fit in the memory for collapsing, is done in fragmented batches.
// - Splitting hash table into fragments is done by looking at 1 or 2 bases at each end of the read-mers
///////////////////////////////////////////////
char frags[1000][10]; //each of them is a fragmentation signal (AC, TT, etc.)
int numFrags = 0; //total number of fragmentation groups (each group might have multiple signals)
bool nFLAG; //When this is turned on this frag run will also handle strings that start or end with 'N';
void SetupFragmentation_2(string fragModeStr) //fragmentation done by one character from each end (allows splitting into 10 groups)
{
if(fragModeStr == "NONE")
{
numFrags = 0;
}
else
{
if(fragModeStr[0]=='N')
{
nFLAG = 1;
fragModeStr = fragModeStr.substr(2, fragModeStr.length()-2);
}
assert(fragModeStr.length() % 3 == 0);
numFrags = fragModeStr.length() / 3;
for(int i=0; i<numFrags; i++) //All reverse complements are already provided
{
frags[i][0] = fragModeStr[3*i];
frags[i][1] = fragModeStr[3*i +1];
}
}
}
void SetupFragmentation_4(string fragModeStr) //fragmentation done by two characters from each end (allows splitting into ~144 groups)
{
if(fragModeStr == "NONE")
{
numFrags = 0;
}
else
{
if(fragModeStr[0]=='N')
{
nFLAG = 1;
fragModeStr = fragModeStr.substr(2, fragModeStr.length()-2);
}
assert(fragModeStr.length() % 5 == 0);
numFrags = fragModeStr.length() / 5;
for(int i=0; i<numFrags; i++) //All reverse complements are already provided
{
frags[i][0] = fragModeStr[5*i];
frags[i][1] = fragModeStr[5*i +1];
frags[i][2] = fragModeStr[5*i +2];
frags[i][3] = fragModeStr[5*i +3];
}
}
}
//Checks if the current 2-base signal is within the fragment group
bool IsFragIncluded_2(char c1, char c2)
{
for(int i=0; i<numFrags; i++)
{
if(frags[i][0] == c1 && frags[i][1] == c2)
{
return 1;
}
}
return 0;
}
//Checks if current 4-base signal is within the fragment group
bool IsFragIncluded_4(char c1, char c2, char c3, char c4)
{
for(int i=0; i<numFrags; i++)
{
if(frags[i][0] == c1 && frags[i][1] == c2 && frags[i][2] == c3 && frags[i][3] == c4)
{
return 1;
}
}
return 0;
}
////////////////////////////////////////////
//Create ID from given sequence oter and the direction
void CreateID(unsigned char* curID, bool dir, unsigned long long seqCode) //This directionality flag now represents which direction the read was compressed against the reference
{
if(dir)
{
seqCode++;
}
int ind = idDigitLen - 1;
while(ind >= 0)
{
curID[ind] = (seqCode % IDENTITY_ALPHABET_SIZE) + IDENTITY_ALPHABET_START;
seqCode /= IDENTITY_ALPHABET_SIZE;
ind--;
}
}
int main(int argc, char* argv[])
{
double runStartTime = getTime();
if(argc!=17)
{
cout << "This program collapses a given set of read sequences (or half splits) and print a compact fasta or fastq file for an off-the-shelf mapper to perform coarse mapping" << endl;
cout << "It also captures perfect matches to the reference and seperates them for automatic construction of perfect links (coarse mapping will only produce non-perfect links)" << endl;
cout << "ARGV[1] INPUT: FASTQ filelist (or the binary file itself if run in Fragmented mode)" << endl; //with read counts as the third field
cout << "ARGV[2] PARAM: Digit len for representing reads" << endl;
cout << "ARGV[3] OUTPUT: output simplified read file in non-fasta format (Long read names will be separated with matching ids in ARGV[9]" << endl;
cout << "ARGV[4] INPUT: reference file input (or NOREF)" << endl;
cout << "ARGV[5] PARAM: Length per line in Ref (not important if NOREF)" << endl;
cout << "ARGV[6] PARAM: read length (should be the input full read length)" << endl;
cout << "ARGV[7] OUTPUT: perfect mapping list output" << endl;
cout << "ARGV[8] CURRENTLY UNUSED PARAM: Max Chr Size" << endl;
cout << "ARGV[9] OUTPUT: Long read name list" << endl;
cout << "ARGV[10] PARAM: Input mode" << endl; //SINGLE or PAIRED
cout << "ARGv[11] PARAM: Split mode" << endl; //NONE or HALF
cout << "ARGV[12] PARAM: Representative mapping mode" << endl; //This is needed to BWA integration
cout << "ARGV[13] PARAM: NONE (no fragmentation) or AA_AC_AG_[as many as the frag signals to be considered in this stage]" << endl; //All the signals for current fragmentation signal group
cout << "ARGV[14] PARAM: fragmentation signal length" << endl; //2 or 4
cout << "ARGV[15] OUTPUT: temporary kill signal output" << endl; //This is done due to heavy use of unordered hash tables which takes a while for gcc to deallocate (but OS takes care of it much faster)
cout << "ARGV[16] PARAM: LRN offset: LRNs will be counted starting from this value" << endl; //Needed if fragmentation is used
exit(10);
}
SetupRevCompChar();
/////////////////////////////////////////
//Set parameters from input -- see beginning of code for descriptions
/////////////////////////////////////////
globalLRNCount = atoi(argv[16]); //this will offset the counts of LRN items
string fragModeStr = string(argv[13]);
int fragSignalLen = -1;
if(fragModeStr != "NONE") //Setup fragmentation signals
{
fragSignalLen = atoi(argv[14]);
if(fragSignalLen == 2)
{
SetupFragmentation_2(fragModeStr);
}
else if(fragSignalLen == 4)
{
SetupFragmentation_4(fragModeStr);
}
else
{
cout << "fragSignalLen can only be 2 or 4" << endl;
exit(19);
}
}
unsigned short inputReadLength = atoi(argv[6]);
unsigned short readLength = 0; //Length of read-mers are determined by splitMode ( equal to original read length if No_split mode, equal to half if half-split mode, (length-1)/2 if odd length reads, etc.)
string splitModeStr = argv[11];
if(splitModeStr == "FULL")
{
splitMode = NO_SPLIT_MODE;
readLength = inputReadLength;
}
else if(splitModeStr == "HALF")
{
splitMode = HALF_SPLIT_MODE;
readLength = inputReadLength/2;
}
else if(splitModeStr == "THREEWAY")
{
splitMode = THREEWAY_SPLIT_MODE;
readLength = inputReadLength/3;
}
else
{
cout << "ERROR: Split mode unrecognized" << endl;
exit(9);
}
string representativeMappingMode(argv[12]);
if(representativeMappingMode == "BWA")
{
repMapMode = BWA_MODE;
}
else if(representativeMappingMode == "BWA_MEM")
{
repMapMode = BWA_MEM_MODE;
}
else if(representativeMappingMode == "BOWTIE_2")
{
repMapMode = BOWTIE_2_MODE;
for(unsigned short i=0; i<readLength; i++) //Bowtie2 needs fastq output
{
dummyQualString[i] = 'S';
}
dummyQualString[readLength] = '\0';
}
else
{
repMapMode = GENERIC_MODE;
}
globalLRNString[0] = '#'; //This is initialization of LRN strings
string inputModeStr = argv[10];
if(inputModeStr == "PAIRED")
{
inputMode = PAIRED_MODE;
}
else if(inputModeStr == "SINGLE")
{
inputMode = SINGLE_MODE;
}
else
{
cout << "ERROR: Input mode unrecognized" << endl;
exit(8);
}
idDigitLen = atoi(argv[2]);
cout << "Total digit length of all read identities is: " << (int) idDigitLen << endl;
int refLineLen = atoi(argv[5]);
string finRefName = argv[4];
//////////////////////////////////////////////////////
//unordered resizable hash table for read-mer sequences -- optimize load factor and rehash size that determines the starting bucket count
std::tr1::unordered_map<string, hashItem*> collapsed;
float z = collapsed.max_load_factor();
collapsed.max_load_factor ( z / 1.13 );
collapsed.rehash(200000000);
cout << "NUMFRAGS:" << numFrags << endl;
//This is for the reference hashing
if(finRefName != "NOREF") //If there is reference is used for collapsing, extract unique k-mers from the reference and add them to the hash table
{
char compRefChr[100];
cout << "Reading reference data.." << endl;
ReadReference(argv[4], refLineLen); //Dumps the entire reference sequence to fullRef[][]
cout << "Reference read: " << getTime() - runStartTime << endl;
if(numFrags == 0) //hash all read-mers
{
for(unsigned short k=1; k<=numChrs; k++) //go through all chromosomes
{
unsigned int curChrLim = chrLens[k] - readLength + 1;
unsigned short curNcount = 0;
for(unsigned short i=1; i<=readLength; i++) //Counts N's within the first readMer in chromosome (remaining read-mers would be counted dynamically)
{
if(fullRef[k][i] == 'N')
{
curNcount++;
}
}
for(unsigned int i=1; i<=curChrLim; i++) //go through all bases in the reference
{
if(curNcount == 0)
{
char saveVal = fullRef[k][i+readLength]; //This sets the end of the read-mer to \0 so that hashing function can now it ends there
fullRef[k][i+readLength] = '\0';
bool strandSwitchedFLAG = CheckIfComplementIsEarlier(fullRef[k] + i, compRefChr, readLength);
hashItem **ptr;
if(strandSwitchedFLAG == 0) //if forward direction is lexicographicallysmaller, hash the original read-mer
ptr = &(collapsed[fullRef[k] + i]);
else
ptr = &(collapsed[compRefChr]); //otherwise hash the reverse complement
if((*ptr) == 0) //If read-mer is not hashed before assign chrNo, chrPos, dir (of lexicographically small version), identity info is not used yet (those are for reads)
{
//Check revComp
*(ptr) = new (hashItem);
(*ptr)->refCode = k;
(*ptr)->refPos = i;
(*ptr)->refDir = (char) strandSwitchedFLAG;
(*ptr)->ident = NULL;
(*ptr)->identCount = 0;
} //Otherwise k-mer is not unique, don't do anything
fullRef[k][i+readLength] = saveVal; //restore the character at the end of the read-mer
}
//This automatically adjusts the nCount in the current window
if(fullRef[k][i] == 'N')
{
curNcount--;
}
if(fullRef[k][i+readLength] == 'N')
{
curNcount++;
}
}
}
}
else //hash only read-mers fitting the frag signals
{
if(fragSignalLen == 2)
{
for(unsigned short k=1; k<=numChrs; k++)
{
unsigned int curChrLim = chrLens[k] - readLength + 1;
unsigned short curNcount = 0;
for(unsigned short i=1; i<=readLength; i++)
{
if(fullRef[k][i] == 'N')
{
curNcount++;
}
}
for(unsigned int i=1; i<=curChrLim; i++)
{
if(curNcount == 0)
{
if(IsFragIncluded_2(fullRef[k][i], fullRef[k][i+readLength-1])) //Check if the 2-base frag signal is within the current frag group (if so conitnue adding the reference read-mer to the hash-table)
{
char saveVal = fullRef[k][i+readLength];
fullRef[k][i+readLength] = '\0';
bool strandSwitchedFLAG = CheckIfComplementIsEarlier(fullRef[k] + i, compRefChr, readLength);
hashItem **ptr;
if(strandSwitchedFLAG == 0)
ptr = &(collapsed[fullRef[k] + i]);
else
ptr = &(collapsed[compRefChr]);
if((*ptr) == 0)
{
//Check revComp
*(ptr) = new (hashItem);
(*ptr)->refCode = k;
(*ptr)->refPos = i;
(*ptr)->refDir = (char) strandSwitchedFLAG;
(*ptr)->ident = NULL;
(*ptr)->identCount = 0;
}
fullRef[k][i+readLength] = saveVal;
}
}
//This automatically adjusts the nCount in the current window
if(fullRef[k][i] == 'N')
{
curNcount--;
}
if(fullRef[k][i+readLength] == 'N')
{
curNcount++;
}
}
}
}
else if(fragSignalLen == 4)
{
for(unsigned short k=1; k<=numChrs; k++)
{
unsigned int curChrLim = chrLens[k] - readLength + 1;
unsigned short curNcount = 0;
for(unsigned short i=1; i<=readLength; i++)
{
if(fullRef[k][i] == 'N')
{
curNcount++;
}
}
for(unsigned int i=1; i<=curChrLim; i++)
{
if(curNcount == 0)
{
if(IsFragIncluded_4(fullRef[k][i], fullRef[k][i+1], fullRef[k][i+readLength-2], fullRef[k][i+readLength-1])) //Check if the 4-base frag signal is within the current frag group (if so conitnue adding the reference read-mer to the hash-table)
{
char saveVal = fullRef[k][i+readLength];
fullRef[k][i+readLength] = '\0';
bool strandSwitchedFLAG = CheckIfComplementIsEarlier(fullRef[k] + i, compRefChr, readLength);
hashItem **ptr;
if(strandSwitchedFLAG == 0)
ptr = &(collapsed[fullRef[k] + i]);
else
ptr = &(collapsed[compRefChr]);
if((*ptr) == 0)
{
//Check revComp
*(ptr) = new (hashItem);
(*ptr)->refCode = k;
(*ptr)->refPos = i;
(*ptr)->refDir = (char) strandSwitchedFLAG;
(*ptr)->ident = NULL;
(*ptr)->identCount = 0;
}
fullRef[k][i+readLength] = saveVal;
}
}
//This automatically adjusts the nCount in the current window
if(fullRef[k][i] == 'N')
{
curNcount--;
}
if(fullRef[k][i+readLength] == 'N')
{
curNcount++;
}
}
}
}
else
{
cout << "fragSignalLen should be either 2 or 4" << endl;
cout << "val: " << argv[14] << endl;
exit(17);
}
}
}
double timeAfterFinishingReadingRef = getTime();
cout << "Time spent for processing reading and hashing ref: " << timeAfterFinishingReadingRef - runStartTime << endl;
cout << "Reading read data..." << endl;
//Read length adjustment for read repository creation
int fullReadLength = readLength; //Differs from inputReadLength earlier which is the length of a read as in the input, where as fullReadLength is readLen multiplied by splits (matters for odd length reads)
int halfReadLength = -1, oneThirdReadLength = -1, twoThirdsReadLength = -1;
if(splitMode == HALF_SPLIT_MODE)
{
fullReadLength = readLength * 2; //If half_split mode, set the full read length to be twice read-mer size (readLength denotes read-mer length)
halfReadLength = readLength;
}
else if(splitMode == THREEWAY_SPLIT_MODE)
{
fullReadLength = readLength * 3;
oneThirdReadLength = readLength;
twoThirdsReadLength = readLength * 2;
}
ifstream finFastqList(argv[1]); //This contains (1st line) number of sample datasets (N+1th line) The nth sample's fastq file name (two tab-delimited names if paired end) and the number of reads within one of them
int numSamples; //number of samples (e.g. separate fastq files for individual samples)
finFastqList >> numSamples;
if(numSamples > MAX_NUM_SAMPLES)
{
cout << "This version will crash if the number of samples is greater than " << MAX_NUM_SAMPLES << endl;
exit(28);
}
cout << "number of Samples: " << numSamples << endl;
if(numFrags == 0) //hash all reads as normal -- reading the original fastq [TODO] use the fastq reading version implemented in fastqSplitter
{
char readLine[MAX_LINE_LEN+1]; //stores original full read sequence
char compReadLine[MAX_LINE_LEN+1]; //stores the complement sequence
char readLine_mate[MAX_LINE_LEN+1]; //stores the original sequence of the mate read (if exists)
char compReadLine_mate[MAX_LINE_LEN+1]; //stores complement of mate
readLine[inputReadLength] = '\0'; compReadLine[inputReadLength] = '\0'; readLine_mate[inputReadLength] = '\0'; compReadLine_mate[inputReadLength] = '\0';
char junkLine[MAX_LINE_LEN+1]; //for the dummy line between seq and qual as well as the quality line itself
bool prevDirection = 0;
for(unsigned char i=0; i<idDigitLen; i++) //initialize the current read-mer id to 0
{
curID[i] = IDENTITY_ALPHABET_START;
}
curID[idDigitLen - 1] -= 2; //this is manually decremented for being incremented again for the first occurence (does away with if check for first item)
//This is the loop that goes over different fastq files
string curFastqFileName;
string curFastqFileName_mate;
int readCount_junk; //not used here in this program but is in the input
while(finFastqList >> curFastqFileName)
{
FILE* finRead = fopen(curFastqFileName.c_str(),"r");
FILE* finRead_mate;
setvbuf ( finRead , NULL , _IOFBF , 16777216);
if(finRead == NULL)
{
cout << "Input fastq file: " << curFastqFileName << " doesn't exist" << endl;
exit(5);
}
//A lot of repetition here, but each is doing slightly different things and I don't want to add a lot if if checks per read
if(inputMode == PAIRED_MODE) //for paired end reads
{
finFastqList >> curFastqFileName_mate >> readCount_junk;
finRead_mate = fopen(curFastqFileName_mate.c_str(), "r");
setvbuf ( finRead_mate , NULL , _IOFBF , 16777216);
if(finRead_mate == NULL)
{
cout << "Read mate input file: " << curFastqFileName_mate << " doesn't exist" << endl;
exit(6);
}
while(fgets(readLine, MAX_LINE_LEN, finRead) != NULL) //read the read header
{
assert(fgets(readLine_mate, MAX_LINE_LEN, finRead_mate) != NULL); //read the mate header
assert(fgets(readLine, MAX_LINE_LEN, finRead) != NULL); //read the actual sequence
readLine[fullReadLength] = '\0';
assert(fgets(readLine_mate, MAX_LINE_LEN, finRead_mate) != NULL); //read the mate sequence
readLine_mate[fullReadLength] = '\0';
//Read other lines that are not used here (read names and quality scores can be recovered at the end of mapInfer)
assert(fgets(junkLine, MAX_LINE_LEN, finRead) != NULL);
assert(fgets(junkLine, MAX_LINE_LEN, finRead) != NULL);
assert(fgets(junkLine, MAX_LINE_LEN, finRead_mate) != NULL);
assert(fgets(junkLine, MAX_LINE_LEN, finRead_mate) != NULL);
if(splitMode == NO_SPLIT_MODE) //Collapse each mate as a whole
{
//Currently all items are collapsed regardless of the N content (since counting N's in the read is more costly than hashing them, which doesn't need to go through all characters)
bool strandSwitchedFLAG = CheckIfComplementIsEarlier(readLine, compReadLine, fullReadLength);
hashItem **ptr;
if(strandSwitchedFLAG == 0)
ptr = &(collapsed[readLine]);
else
ptr = &(collapsed[compReadLine]);
if((*ptr) == 0) //If the reference doesn't have this read-mer
{
*(ptr) = new hashItem();
(*ptr)->refCode = INVALIDCHRCODE;
(*ptr)->refPos = -1;
(*ptr)->refDir = -1;
(*ptr)->ident = NULL;
(*ptr)->identCount = 0;
//ID changes depending on direction (we don't want to computed the id from scratch here, so we increment using previous id and its direction)
IncrementID(prevDirection, strandSwitchedFLAG); //Note that this directionality doesn't represent the mapping direction, it represents the direction change through collapsing
prevDirection = strandSwitchedFLAG; //save the current direction for the next guy
}
else //If read-mer exists in reference
{
bool readStrandFlag = strandSwitchedFLAG; //then direction represents direction to the forward reference
if((*ptr)->refDir != -1) //which means that the reference is not created
{
readStrandFlag = !(strandSwitchedFLAG == (bool) (*ptr)->refDir);
}
IncrementID(prevDirection, readStrandFlag); //This directionality flag now represents which direction the read was compressed against the reference
prevDirection = readStrandFlag;
}
//This is for adding the new read-mer ID to the hashItem
unsigned int curIdentCount = (*ptr)->identCount;
unsigned int curSize = curIdentCount * idDigitLen;
if(curIdentCount == 0)
{
(*ptr)->ident = (char *) malloc (idDigitLen);
}
else if(IsLog2Integer(curIdentCount)) //Deep copy and resize as double
{
char* prevIdent = (*ptr)->ident;
char* curIdent = (char *) malloc (curSize * 2);
for(unsigned int k=0; k<curSize; k++)
{
curIdent[k] = prevIdent[k];
}
free(prevIdent);
(*ptr)->ident = curIdent;
}
//Add identity to hashItem and increment
for(int k=0; k<idDigitLen; k++)
{
(*ptr)->ident[curSize + k] = curID[k];
}
(*ptr)->identCount++;
}
else if(splitMode == HALF_SPLIT_MODE) //collapse each mate in halves