Repository navigation
Expand file tree
/
Copy pathcora.cpp
More file actions
2133 lines (1796 loc) · 93.2 KB
/
Copy pathcora.cpp
File metadata and controls
2133 lines (1796 loc) · 93.2 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<iostream>
#include<string>
#include<fstream>
#include<sstream>
#include<assert.h>
#include<stdlib.h>
#include<time.h>
#include<sys/time.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<vector>
using namespace std;
#define VERSION "1.1.5b"
#define HOMINDEX "coraIndex"
#define MAPPERINDEX "mapperIndex"
#define SEARCH "search"
#define READFILEGEN "readFileGen"
#define FAIGENERATE "faiGenerate"
#define NUMCHROMFORSHORT 127 //If the number of chroms in the fai file exceeds this file then large chrom version will be called with "_L"
int numChromInFai; //obtained from Fai file
double getTime()
{
struct timeval t;
gettimeofday(&t, NULL);
return t.tv_sec+t.tv_usec/1000000.0;
}
//Variables for homology table construction
int homTableConstructionFlag; //This flag determines whether a homology table will be constructed
string homTablePerfectMatchFile = "./Exact"; //This field contains the compact equivalence infomation
string homTableInexactMatchFile = "./Inexact"; //This field contains the prefix for the binary files containing the inexact mappings
int numInexactHomTablePartitions; //Number of partitions (starting from 1) that should be added as a suffix to the prefix above
string PhysicalSplitsFile = "__TEMP__Aux_Physical_Splits_File"; //These splits only contain 2-char signals (they can be grouped) for physical partition of the processes through time for efficient memory management
string ParallelSplitsFile = "__TEMP__Aux_Parallel_Splits_File"; //These splits contain 4-char signals for partitioning into threads
int numPhysicalSplits = 10;
int numParallelSplits = 8;
//Parameters and variables for FASTQ splitting
#define AUTO_FASTQ_SPLIT_MODE 0 // This is the flag to set the number of fastq splits to be ceil( refLen / split_function_interval )
#define AUTO_FASTQ_SPLIT_FUNCTION_INTERVAL 100000000
#define AUTO_FASTQ_SPLIT_FUNCTION_INTERVAL_LOWMEM 66666666
#define MAX_AUTO_FASTQ_SPLIT 144
int numFastqSplits = AUTO_FASTQ_SPLIT_MODE;
// Executable names
string collapseExec("collapse");
string linkConstructExec("linkConstruct");
string homTableSetupExec("homTable_setup");
string mappingInferenceExec("mappingInference");
string fastqSplitterExec("fastqSplit");
///////////////////
// Cora main parameters
string RepresentativeMapperExecutable = "bwa"; //either the mapping executable for present aligners, or the full mapping mode for alignment
string RepresentativeMappingMode = "BWA"; // MRSFAST, MRSFAST_ULTRA, BWA, BWA_MEM, BOWTIE, BOWTIE_2, MANUAL --> manual requires the exact command to run the mapper
string runMode = "1111";
string fastqInputListFile = "";
string refFile = "", refFileFai = "";
string mappingOutputFile = "CORA_Output.sam";
string mappingReportMode = "ALL"; //ALL or BEST or UNIQUE or STRATUM or BEST_SENSITIVE or BEST_FAST (only for gapped mapping)
string mapperMetric = "HAMMING";
string inputMode = "PAIRED"; //SINGLE or PAIRED
int insertSizeLowerThreshold = 150, insertSizeUpperThreshold = 650;
string splitMode = "HALF"; //FULL or HALF (This might be made more parametric later on) -- Can also be THREEWAY
string collapseMode = "WITHREF"; //NOREF or WITHREF
string readCompressionMode = "OFF"; //OFF or GZIP
string temporaryDirectoryName = "__temporary_CORA_files";
string inputReadGroupString = "";
string killSignalFile = "__TEMP__Kill_Signal_File"; //This file is created if a subprogram is killing itself intentionally (for deallocation speed) so that the parent can ignore it
string collapseFragmentFile = "__TEMP__Aux_Fastq_Splits_File"; //either NONE or a file containing list of fragment groups (AA_GT_, TA_, N_AG_AC_, etc.) -- This is for Fastq Splitting -- It is stuomatically converted to NONE if the number of splits is specified as less than two
int numCoarseMappingThreads = 1;
int memoizationThreshold = 20; //memoization threshold show the lower inclusive bound of joint-readMer reads to be memoized.
int numMismatchesPerReadMer = 2;
int globalMapCountLimit = 0; //If non-zero determines the maximum number of mappings to be printed (only for ALL mapping)
//-=================================================
//Encoded read name (identity) related parameters
#define IDENTITY_ALPHABET_START 33
#define IDENTITY_ALPHABET_END 126
#define IDENTITY_ALPHABET_SIZE 94
long long CapOnTotalNumberOfReads; //This value determines how many chars will be used to identify each read item -- mates counted separately
long long identitySpaceUpperLimit; //This is a derived vale from total number Of reads depending on the extra bits each read will be using (for example directionality, splits etc)
//Length related parameters
char idDigitLen; //This is a derived value from identitySpaceUpperLimit and the
int refLineLen; //lineLength if reference
int readLen; //full readLength for each read
int completeReadLen; //regardless of splitMode this is the full length of the read
int kmerLen; //length for the homology table
//Item count related parameters
int numSamples; //number of individual datasets
int maxChrSizeInRef;
unsigned long long numTotalReads;
//These are precomputed LPT (longest processing time) load balancing tables for 2-base and 4-base signals to be used for splitting the k-mer space
string LPT2path("LPT_2.dat");
string LPT4path("LPT_4.dat");
string SplitTwoSignal(int numSplits)
{
if(numSplits < 1 || numSplits > 10)
{
cout << "ERROR: Number of physical splits can be between 1 and 10" << endl;
exit(89);
}
ifstream fin(LPT2path.c_str());
string twoArr;
for(int i=1; i<=numSplits; i++)
{
getline(fin, twoArr);
}
for(int i=0; i<twoArr.length(); i++)
{
if(twoArr[i] == 'X')
{
twoArr[i] = '\n';
}
}
fin.clear();
fin.close();
return twoArr;
}
string SplitFourSignal(int numSplits)
{
if(numSplits < 1 || numSplits > 144)
{
cout << "ERROR: Number of physical splits can be between 1 and 144" << endl;
exit(89);
}
ifstream fin(LPT4path.c_str());
string fourArr;
for(int i=1; i<=numSplits; i++)
{
getline(fin, fourArr);
}
for(int i=0; i<fourArr.length(); i++)
{
if(fourArr[i] == 'X')
{
fourArr[i] = '\n';
}
}
fin.clear();
fin.close();
return fourArr;
}
ofstream logOut;
#define IGNORE 17
#define VERIFY 34
//This executes a given command, while tracking runtime and exitcodes
void ExecuteSystemCall(const stringstream& call, char ignoreFlag)
{
cout << "Command: " << call.str() << endl;
logOut << "Command: " << call.str() << endl;
double callBeginTime = getTime();
int x = system(call.str().c_str());
double callEndTime = getTime();
if(ignoreFlag != IGNORE)
{
if(x != 256 && x != 0)
{
cout << "WARNING: last command returned non-zero exit code: " << x << endl;
cout << "*** CORA run might have crashed here and the rest of pipeline may not run properly ***" << endl;
}
}
else
{
//Check kill signal
FILE* finKill = fopen(killSignalFile.c_str(), "r");
if(!finKill)
{
cout << "WARNING: last command returned non-zero exit code: " << x << endl;
}
else // delete killSignalFile
{
fclose(finKill);
stringstream removeKillFile;
removeKillFile << "rm " << killSignalFile << endl;
ExecuteSystemCall(removeKillFile, VERIFY);
}
}
cout << "Exit Code: " << x << " --- Completed... (in " << callEndTime - callBeginTime << " seconds)" << endl;
logOut << "runTime: " << callEndTime - callBeginTime << endl;
}
//Fai parsing
int CheckFai_and_ReturnMaxChrSize(string faiFileName)
{
cout << "FaiFileName: " << faiFileName << endl;
assert(faiFileName.substr(faiFileName.length()-4,4) == ".fai");
string actualFileName = faiFileName.substr(0, faiFileName.length()-4);
int maxContigSizeInFai = 0;
//Verifying faiFile & reference size
ifstream finFai(faiFileName.c_str());
if(!finFai.is_open())
{
finFai.clear();
finFai.close();
cout << "ERROR: Could not find fai file: " << faiFileName << endl;
cout << "Please run 'cora " << FAIGENERATE << " " << faiFileName.substr(0,faiFileName.length()-3) << "' or 'samtools faidx " << faiFileName.substr(0,faiFileName.length()-3) << "'";
exit(99);
}
//In MultiChr Version only MaxChrSize is needed
string faiLine;
numChromInFai = 0;
while(getline(finFai, faiLine))
{
stringstream faiLineSS(faiLine);
string ctgName;
int ctgSize;
faiLineSS >> ctgName >> ctgSize;
if(ctgSize > maxContigSizeInFai)
{
maxContigSizeInFai = ctgSize;
}
numChromInFai++;
}
finFai.close();
if(numChromInFai > 32000)
{
cout << "ERROR: Current verison of CORA only supports at most 32000 chromosomes within a reference file." << endl;
cout << "Let denizy@mit.edu know if a version that supports more chromosomes is needed." << endl;
exit(100);
}
return maxContigSizeInFai;
}
long long CheckFai_and_ReturnTotalGenomeSize(string faiFileName)
{
long long totalGenomeSize = 0;
//Verifying faiFile & reference size
ifstream finFai(faiFileName.c_str());
if(!finFai.is_open())
{
finFai.clear();
finFai.close();
cout << "ERROR: Could not find fai file: " << faiFileName << endl;
cout << "Please run 'cora " << FAIGENERATE << " " << faiFileName.substr(0,faiFileName.length()-3) << "' or 'samtools faidx " << faiFileName.substr(0,faiFileName.length()-3) << "'";
exit(98);
}
string faiLine;
while(getline(finFai, faiLine))
{
stringstream faiLineSS(faiLine);
string ctgName;
int ctgSize;
faiLineSS >> ctgName >> ctgSize;
totalGenomeSize += ctgSize;
}
finFai.close();
return totalGenomeSize;
}
void SetupAuxiliaryFiles()
{
if(homTableConstructionFlag)
{
string phyStr = SplitTwoSignal(numPhysicalSplits);
//TODO(denizy) Check if homtable file paths exist and if they are writable
//Put auxiliary files in the temporary directory
ofstream foutPhy(PhysicalSplitsFile.c_str());
foutPhy << numPhysicalSplits << endl << phyStr << endl;
foutPhy.clear();
foutPhy.close();
string parStr = SplitFourSignal(numParallelSplits);
ofstream foutPar(ParallelSplitsFile.c_str());
foutPar << numParallelSplits << endl << parStr << endl;
foutPar.clear();
foutPar.close();
}
else if(runMode[0] != '0') //Fastq split is only needed for the first stage
{
if(numFastqSplits == AUTO_FASTQ_SPLIT_MODE)
{
long long totalGenomeSize = CheckFai_and_ReturnTotalGenomeSize(refFile + ".fai");
numFastqSplits = 1 + totalGenomeSize / AUTO_FASTQ_SPLIT_FUNCTION_INTERVAL;
if((mappingReportMode == "BEST" || mappingReportMode == "BEST_FAST"))
{
numFastqSplits = 1 + totalGenomeSize / AUTO_FASTQ_SPLIT_FUNCTION_INTERVAL_LOWMEM;
}
if(numFastqSplits > MAX_AUTO_FASTQ_SPLIT)
{
numFastqSplits = MAX_AUTO_FASTQ_SPLIT;
}
}
if(numFastqSplits > 1)
{
string fastqSplitStr = SplitFourSignal(numFastqSplits);
//Edit string here to make it fit fastq splitting -- This is because fastqSplit executable requires a particular input
ofstream foutFastqSplit(collapseFragmentFile.c_str());
foutFastqSplit << numFastqSplits << " " << 4 << endl;
stringstream fastqSplitStrSS(fastqSplitStr);
int lineCount = 0;
string line;
while(getline(fastqSplitStrSS, line))
{
lineCount++;
string lineRC(line);
for(int i=0; i<(int)line.length(); i++)
{
lineRC[i] = line[line.length() - i - 1];
if(lineRC[i] == 'A')
{
lineRC[i] = 'T';
}
else if(lineRC[i] == 'C')
{
lineRC[i] = 'G';
}
else if(lineRC[i] == 'G')
{
lineRC[i] = 'C';
}
else if(lineRC[i] == 'T')
{
lineRC[i] = 'A';
}
}
string stringToPrint = line + " " + lineRC + " ";
if(lineCount == numFastqSplits)
{
stringToPrint = "N " + stringToPrint;
}
//Replace all spaces with underscores + add N at the end
for(int i=0; i<(int)stringToPrint.length(); i++)
{
if(stringToPrint[i] == ' ')
{
stringToPrint[i] = '_';
}
}
foutFastqSplit << stringToPrint << endl; //Addition of the N string to the last split
//cout << stringToPrint << endl;
}
}
}
}
void VerifyRefFile(string givenRef)
{
ifstream finRef(givenRef.c_str());
if(!finRef.is_open())
{
cout << "ERROR: Could not find reference file: " << refFile << endl;
cout << "Exiting.." << endl;
exit(10);
}
string refLine, seqLine;
getline(finRef, refLine);
getline(finRef, seqLine);
if(refLine[0] != '>')
{
cout << "ERROR: Reference file is corrupted (not multi-fasta format)..." << endl;
cout << "Exiting.." << endl;
exit(11);
}
finRef.clear();
finRef.close();
}
void VerifyRefFileAndFai()
{
//Verifying refFile & reference line length
ifstream finRef(refFile.c_str());
if(!finRef.is_open())
{
cout << "ERROR: Could not find reference file: " << refFile << endl;
cout << "Exiting.." << endl;
exit(10);
}
string refLine, seqLine;
getline(finRef, refLine);
getline(finRef, seqLine);
if(refLine[0] != '>')
{
cout << "ERROR: Reference file is corrupted (not multi-fasta format)..." << endl;
cout << "Exiting.." << endl;
exit(11);
}
refLineLen = seqLine.length(); //assume all other lines would be the same
cout << "Reference line length: " << refLineLen << "bp .." << endl;
finRef.clear();
finRef.close();
//Check fai file and get the maximum chromosome size
refFileFai = refFile + ".fai";
maxChrSizeInRef = CheckFai_and_ReturnMaxChrSize(refFileFai);
cout << "Max contig size in reference: " << maxChrSizeInRef << endl;
}
void CreateDirectoryIfDoesNotExist(string name)
{
//Create temporary files folder if doesn't exist
struct stat st = {0};
if(stat(name.c_str(), &st) == -1)
{
mkdir(name.c_str(), 0700);
}
}
//Set up auxiliary parameters
void ConfigureRelatedParameters(string coraExecPath)
{
//Create temporary files folder if doesn't exist
CreateDirectoryIfDoesNotExist(temporaryDirectoryName);
killSignalFile = temporaryDirectoryName + "/" + killSignalFile;
collapseFragmentFile = temporaryDirectoryName + "/" + collapseFragmentFile;
PhysicalSplitsFile = temporaryDirectoryName + "/" + PhysicalSplitsFile;
ParallelSplitsFile = temporaryDirectoryName + "/" + ParallelSplitsFile;
size_t slashPos = coraExecPath.rfind("/");
string execPathPrefix;
if(slashPos == string::npos)
execPathPrefix = "";
else
execPathPrefix = coraExecPath.substr(0,slashPos+1);
collapseExec = execPathPrefix + collapseExec;
linkConstructExec = execPathPrefix + linkConstructExec;
homTableSetupExec = execPathPrefix + homTableSetupExec;
mappingInferenceExec = execPathPrefix + mappingInferenceExec;
fastqSplitterExec = execPathPrefix + fastqSplitterExec;
if(numChromInFai > NUMCHROMFORSHORT)
{
homTableSetupExec += "_L"; //This is the homTableSetup version that supports larger chromosomes
mappingInferenceExec += "_L"; //This is the mappingInference version that supports larger chromosomes
collapseExec += "_L"; //This is the collapse version that supports larger chromosomes
}
LPT2path = execPathPrefix + LPT2path;
LPT4path = execPathPrefix + LPT4path;
assert(killSignalFile != ""); //this is the file that an intentional kill will report in
//Remove any existing kill signal files
FILE* killIn = fopen(killSignalFile.c_str(), "r");
if(killIn)
{
fclose(killIn);
stringstream removeKillFile;
removeKillFile << "rm " << killSignalFile << endl;
ExecuteSystemCall(removeKillFile, VERIFY);
}
completeReadLen = readLen;
if(splitMode == "HALF")
{
readLen /= 2; //If full read length is odd, it will be (fullLen-1)/2
}
else if(splitMode == "THREEWAY")
{
readLen /= 3; //If full read length is not divisible by three, k-mer len will be interger division
}
//Check whether config file is proper
if(runMode.length() != 4)
{
cout << "ERROR: RunMode should have 4 stages defined" << endl;
exit(5);
}
//This generates the splitting scheme for both physical and parallel splits
SetupAuxiliaryFiles();
if(homTableConstructionFlag)
{
//Check whether splits files are prepared (physical splits are due to repeated smaller runs for memory management -- parallel splits are simultaenous)
ifstream finPhySplit(PhysicalSplitsFile.c_str());
ifstream finParSplit(ParallelSplitsFile.c_str());
if(!finPhySplit.is_open() || !finParSplit.is_open())
{
cout << "ERROR: AUX split files do not exist" << endl;
cout << "Exiting.." << endl;
exit(7);
}
//There will be as many inexact homology table partitions as the number of parallel splits (they are merged during collapsing)
finParSplit >> numInexactHomTablePartitions;
finPhySplit.clear();
finPhySplit.close();
finParSplit.clear();
finParSplit.close();
//Check whether we are overwriting the hom table files
if(homTableConstructionFlag)
{
ifstream finHomPerf(homTablePerfectMatchFile.c_str(), ios::binary);
if(finHomPerf.is_open())
{
cout << "ERROR: HomTable Perf file already exists: '" << homTablePerfectMatchFile.c_str() << "'";
cout << "Exiting.." << endl;
exit(8);
}
finHomPerf.close();
ifstream finHomInexact(homTableInexactMatchFile.c_str(), ios::binary);
if(finHomInexact.is_open())
{
cout << "ERROR: HomTable Inexact file already exists: '" << homTableInexactMatchFile.c_str() << "'";
cout << "Exiting.." << endl;
exit(9);
}
finHomInexact.close();
} //if flag is false, there is no reason to check files until search part of island
}
if(runMode != "0000") //If there is any non-zero runMode option, still read through the fai
{
//Set read length -- read lengths should be uniform throughout the dataset
ifstream finReadFile(fastqInputListFile.c_str());
if(!finReadFile.is_open())
{
cout << "ERROR: Read fastq file could not be opened: " << fastqInputListFile << endl;
cout << "Exiting.." << endl;
exit(12);
}
else
{
string firstLine;
getline(finReadFile, firstLine);
numSamples = atoi(firstLine.c_str());
string listLine;
for(int i=0; i<numSamples; i++)
{
if(!getline(finReadFile, listLine))
{
cout << "Mismatch between number of samples and number of lines in input list" << endl;
exit(45);
}
stringstream listLineSS(listLine);
if(inputMode.substr(0,6) == "PAIRED")
{
string fileName_left, fileName_right;
unsigned long long count;
if(listLineSS >> fileName_left >> fileName_right >> count)
{
ifstream left(fileName_left.c_str());
ifstream right(fileName_right.c_str());
if(!left.is_open() || !right.is_open())
{
cout << "One of the following files is missing: " << endl;
cout << fileName_left << endl;
cout << fileName_right << endl;
exit(46);
}
left.clear();
left.close();
right.clear();
right.close();
numTotalReads += count;
}
else
{
cout << "The input list line: " << listLine << endl;
cout << "It should contain [FIRST READ FILE] [SECOND READ FILE] [COUNT]" << endl;
exit(47);
}
}
else //if(inputMode.substr(0,6) == "SINGLE")
{
string fileName_single;
unsigned long long count;
if(listLineSS >> fileName_single >> count)
{
ifstream single(fileName_single.c_str());
if(!single.is_open())
{
cout << "One of the following files is missing: " << endl;
cout << fileName_single << endl;
exit(46);
}
single.clear();
single.close();
numTotalReads += count;
}
else
{
cout << "The input list line: " << listLine << endl;
cout << "It should contain [SINGLE END FILE] [COUNT]" << endl;
exit(47);
}
}
}
}
finReadFile.clear();
finReadFile.close();
CapOnTotalNumberOfReads = numTotalReads;
//Configure identity related parameters
identitySpaceUpperLimit = CapOnTotalNumberOfReads * 2 + 5; //Times four is for storing the directionality of compression and mate information (will grow in the future with splits) [There is 5 offset to allow the highest 5 idDigitLen strings to be special cases]
if(inputMode.substr(0,6) == "PAIRED")
{
identitySpaceUpperLimit *= 2;
}
if(splitMode == "HALF")
{
identitySpaceUpperLimit *= 2;
}
else if(splitMode == "THREEWAY")
{
identitySpaceUpperLimit *= 3;
}
idDigitLen = 0;
while(identitySpaceUpperLimit > 0)
{
idDigitLen++;
identitySpaceUpperLimit /= IDENTITY_ALPHABET_SIZE;
}
idDigitLen = (unsigned char) max(3, (int) idDigitLen); //Minimum idDigitLen is 3 for division purposes of long read names (unlikely but can be a faulty corner case)
}
}
#define ANSI_COLOR_RED "\x1b[31m"
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_YELLOW "\x1b[33m"
#define ANSI_COLOR_BLUE "\x1b[34m"
#define ANSI_COLOR_MAGENTA "\x1b[35m"
#define ANSI_COLOR_CYAN "\x1b[36m"
#define ANSI_COLOR_RESET "\x1b[0m"
void PrintHomManual(string error)
{
cout << "====================================================================================================" << endl;
cout << "Usage: cora " << HOMINDEX << " [options] <Reference> <ExactHom> <InexactHom>" << endl ;
cout << "====================================================================================================" << endl;
cout << "Notes: Reference should be in fasta or multi-fasta format and indexed" << endl;
cout << " You can use 'cora " << FAIGENERATE << "' or 'samtools faidx' to index the reference" << endl;
cout << " ExactHom and InexactHom are file names to be used in the search pipeline of CORA" << endl << endl;
cout << "Important Options: " << endl << endl;
cout << " -K [INT 33-64] k-mer length [no default]" << endl;
cout << " -H [INT 1-3] Hamming-distance threshold per k-mer for inexact homology table. [2] " << endl << endl;
cout << "Performance Options: " << endl << endl;
cout << " -p [INT 1-10] Number of physical file splits for computing the homology tables [10]" << endl;
cout << " Higher values substantially reduce memory use, sacrificing some run time." << endl;
cout << " -t [INT 1-24] Number of parallel threads to use for computing the inexact homology table [8]" << endl << endl;
if(error != "")
{
cout << "====================================================================================================" << endl;
cout << "Input Error: "; printf(ANSI_COLOR_RED "%s" ANSI_COLOR_RESET "\n", error.c_str());
cout << "Please see manual above... " << endl << endl;
}
exit(0);
}
void PrintFaiGenerateManual(string error)
{
cout << "====================================================================================================" << endl;
cout << "Usage: cora " << FAIGENERATE << " <Reference>" << endl ;
cout << "====================================================================================================" << endl << endl;
cout << "Notes: This command is a replacement for 'samtools faidx' in case samtools is not installed" << endl;
cout << " Reference should be in fasta or multi-fasta format" << endl << endl;
if(error != "")
{
cout << "====================================================================================================" << endl;
cout << "Input Error: "; printf(ANSI_COLOR_RED "%s" ANSI_COLOR_RESET "\n", error.c_str());
cout << "Please see manual above... " << endl << endl;
}
exit(0);
}
void PrintReadFileGenManual(string error)
{
cout << "====================================================================================================" << endl;
cout << "Usage: To generate SINGLE-end read file list: " << endl << endl;
cout << " cora " << READFILEGEN << " [option] <FileName> -S <FASTQ-A> <FASTQ-B> <...>" << endl << endl;
cout << " To generate PAIRED-end read file list: " << endl << endl;
cout << " cora " << READFILEGEN << " [option] <FileName> -P <FASTQ-A1> <FASTQ-A2> <FASTQ-B1> <FASTQ-B2> <...>" << endl << endl;
cout << "====================================================================================================" << endl << endl;
cout << "Notes: <FileName> is the output read file list name for CORA, which stores read dataset info" << endl;
cout << " FASTQ files are input read datasets. Paired and single-end read datasets cannot be mixed" << endl << endl;
cout << "Options : --ReadComp [STRING] Compression format of the input reads (GZIP or OFF) [default OFF]" << endl;
cout << " OFF -> input datasets are in plain FASTQ format" << endl;
cout << " GZIP -> input datasets are compressed with gzip" << endl << endl;
if(error != "")
{
cout << "====================================================================================================" << endl;
cout << "Input Error: "; printf(ANSI_COLOR_RED "%s" ANSI_COLOR_RESET "\n", error.c_str());
cout << "Please see manual above... " << endl << endl;
}
exit(0);
}
void PrintMapperIndexManual(string error)
{
cout << "====================================================================================================" << endl;
cout << "Usage: cora " << MAPPERINDEX << " [options] <Reference>" << endl ;
cout << "====================================================================================================" << endl << endl;
cout << "Important Options: " << endl << endl;
cout << " --Map Off-the shelf mapper to be used for coarse mapping (stages 2-3) [default BWA]" << endl;
cout << " current valid options: BWA, BWA_MEM, BOWTIE, BOWTIE_2, MRSFAST, MRSFAST_ULTRA" << endl;
cout << " --Exec Name of the executable path for mapper [default bwa]" << endl;
cout << " Can be full path (e.g. /home/folder/bwa) or just executable if installed (e.g. bwa)" << endl;
cout << " --Index Full path for the index to be constructed if [default is same as <Reference>]" << endl << endl;
cout << "Miscellaneous Options: " << endl << endl;
cout << " --opt Additional options to be passed to the mapper for indexing" << endl;
cout << " Warning: some of the non-default indexing options may not be compatible with CORA" << endl << endl;
if(error != "")
{
cout << "====================================================================================================" << endl;
cout << "Input Error: "; printf(ANSI_COLOR_RED "%s" ANSI_COLOR_RESET "\n", error.c_str());
cout << "Please see manual above... " << endl << endl;
}
exit(0);
}
void PrintSearchManual(string error)
{
cout << "====================================================================================================" << endl;
cout << "Usage: cora " << SEARCH << "[options] <Read_File_List> <Reference> <ExactHom> <InexactHom>" << endl;
cout << "====================================================================================================" << endl << endl;
cout << "Notes: <Reference> should be in fasta or multi-fasta format and indexed." << endl;
cout << " <ExactHom> and <InexactHom> are files generated in the " << HOMINDEX << " run" << endl;
cout << " <Read_File_List> can be generated using " << READFILEGEN << " command or manually." << endl << endl;
cout << "Important Options: " << endl << endl;
cout << " -C Determines which stages of CORA pipeline will be executed. [default 1111]" << endl;
cout << " Other valid options are: 1000, 1100, 1110, 0100, 0110, 0111, 0010, 0011, 0001" << endl;
cout << " These indicate 4 flags for running following 4 stages: " << endl;
cout << " 1) Compressing reads into unique k-mers." << endl;
cout << " 2) Coarse mapping k-mers to the reference using an off-the-shelf aligner." << endl;
cout << " 3) Converting coarse mapping results to read links." << endl;
cout << " 4) Traverse homology index for generating final mappings." << endl;
cout << " --Mode Mapping mode: ALL, BEST, BEST_SENSITIVE, BEST_FAST, STRATUM, or UNIQUE [ALL]." << endl;
cout << " --Map Off-the shelf mapper to be used for coarse mapping [default BWA]" << endl;
cout << " Can be BWA, BWA_MEM, BOWTIE, BOWTIE_2, MRSFAST, MRSFAST_ULTRA, MANUAL" << endl;
cout << " --Exec Name of the executable file to be run for coarse mapping" << endl;
cout << " Either full path (e.g. /home/folder/bwa) or executable if installed (e.g. bwa)" << endl;
cout << " -R Read input mode, SINGLE for single-end or PAIRED for paired-end reads [PAIRED]" << endl;
cout << " --MinI [INT] for PAIRED (paired-end) mode, min insert length (|TLEN| in SAM) [150]" << endl;
cout << " --MaxI [INT] for PAIRED (paired-end) mode, max insert length (|TLEN| in SAM) [650]" << endl;
cout << " -O Output SAM file to print the final mapping output [default = CORA_Output.sam]" << endl;
cout << " -L [INT] Read length for CORA mapping (per read end) [no default]. " << endl;
cout << " -K K-mer compression mode, FULL, HALF or THREEWAY [default = HALF]." << endl;
cout << " FULL, HALF and THREEWAY denote 1, 2, or 3 k-mers per read-end, respectively." << endl;
cout << " K-mer length in " << HOMINDEX << " stage should concordant with -K (see below): " << endl;
cout << " FULL -> index k-mer should be same as read length" << endl;
cout << " HALF -> k-mer length should be floor(read_length/2)" << endl;
cout << " THREEWAY -> k-mer length should be floor(read_length/3)" << endl;
cout << " --Metric Distance metric to be used for mapping (HAMMING or EDIT) [default HAMMING]" << endl;
cout << " HAMMING -> distance is substitution only" << endl;
cout << " EDIT -> (Levenshtein) distance allows indels (requires --Map BWA or BOWTIE_2)" << endl;
cout << " -E [INT] Distance threshold per k-mer for inexact homology table. (1 to 3) [default 2] " << endl;
cout << " Use of Hamming or Edit distance is determined by --Metric option." << endl;
cout << " Should be the same as -H used in " << HOMINDEX << " stage. " << endl;
cout << "Performance Options: " << endl << endl;
cout << " --memoi [INT] Activate memoization for k-mers appearing at least as many times as INT [20]." << endl;
cout << " Must be larger than 1. Lower values save runtime during Stage 4 using more memory." << endl;
cout << " --fs [INT or AUTO] Number of physical file splits for Input FASTQ file for compression" << endl;
cout << " Valid parameters are either AUTO or an integer between 1 to 144 [default is AUTO] " << endl;
cout << " Higher values reduce memory use during Stage 1 sacrificing some run time. " << endl;
cout << " AUTO mode determines the number of FASTQ splits as: 1 + genome_size / 10M." << endl << endl;
cout << " --cm [STRING] Determines if the reference should be used for compressing reads or not." << endl;
cout << " Options: WITHREF or NOREF [default WITHREF]" << endl << endl;
cout << "Paralelization Options: " << endl << endl;
cout << " --coarseP [INT] The number of parallel threads to be used for coarse mapping. [default is 1]" << endl;
cout << " Capped at maximum number of threads allowed by coarse-mapper" << endl << endl;
cout << "Miscellaneous Options: " << endl << endl;
cout << " --RG [\"STRING\"] All read group data for the read datasets being mapped [default NONE]" << endl;
cout << " This string will appear in the header and IDs will be attached to each mapping line" << endl;
cout << " The whole string should be double quoted, the first identifier should be a unique ID" << endl;
cout << " Multiple read datasets's RG data should be comma-separated in the order of Read_File_List" << endl;
cout << " For tab-delimiting identifiers within the command line you can use Ctrl+V -> Ctrl+I" << endl;
cout << " The following is an example --RG value for 3 single-end or paired-end read datasets" << endl;
cout << " \"ID:xx1\tCN:yya\tDS:za zb\tDT:ta,ID:xx2\tCN:yya,ID:xx3\tCN:yyb\tDS:zc zd\"" << endl << endl;
cout << " --TempDir [STRING] The directory to be used for temp CORA files. [__temporary_CORA_files]." << endl;
cout << " This enables running two CORA jobs in the same folder with different TempDir." << endl;
cout << " --ReadComp [STRING] Compression format of the input reads (GZIP or OFF) [default OFF]" << endl;
cout << " OFF means that the input datasets are in plain FASTQ format" << endl << endl;
cout << " --MaxMapCount [INT] Maximum number of mapping to print in ALL mapping mode [default is infinite]" << endl << endl;
if(error != "")
{
cout << "====================================================================================================" << endl;
cout << "Input Error: "; printf(ANSI_COLOR_RED "%s" ANSI_COLOR_RESET "\n", error.c_str());
cout << "Please see manual above... " << endl << endl;
}
exit(0);
}
void ParseCommandLineArguments(int argc, char* argv[])
{
cout << endl;
if(argc == 1 || string(argv[1]) == "-v" || string(argv[1]) == "--help" || string(argv[1]) == "help")
{
cout << "====================================================================================================" << endl;
printf("======= " ANSI_COLOR_YELLOW " CORA v" VERSION " by Deniz Yorukoglu (denizy@mit.edu, http://cora.csail.mit.edu/) " ANSI_COLOR_RESET " ========\n");
cout << "====================================================================================================" << endl << endl;
cout << "Usage: cora <command> [options]" << endl << endl;
cout << "Command: " << HOMINDEX << "\t Create a homology table for CORA." << endl;
cout << " " << FAIGENERATE << "\t Generate .fai file for reference." << endl;
cout << " " << MAPPERINDEX << "\t Index the reference genome for coarse mapper." << endl;
cout << " " << READFILEGEN << "\t Automatically generate CORA's read file list input." << endl;
cout << " " << SEARCH << "\t\t Run CORA's compressive read alignment pipeline." << endl;
cout << endl << "To print the manual for each command, run './cora <command>' without any options." << endl << endl;
exit(0);
}
string firstArg(argv[1]);
if(firstArg == HOMINDEX)
{
// k-mer length [no default, INT]
// Num Physical Splits [default 1]
// Num Parallel Splits [default 1]
// Mismatches per k-mer [default 2] // There are some constraints regarding read-mer length
homTableConstructionFlag = 1;
runMode = "0000";
if(argc <= 2 || string(argv[2]) == "--help" || string(argv[2]) == "help")
PrintHomManual("");
else
{
for(int i=2; i<argc;)
{
string argMark = string(argv[i]);
if(argMark[0] == '-' && argc < i+4)
{
PrintHomManual("Either missing parameter for argument " + argMark + " or last three arguments, <Reference> <ExactHom> <InexactHom>, are not set");
}
if(argMark == "-K")
{
kmerLen = atoi(argv[i+1]);
if(kmerLen <= 32)
PrintHomManual("-K argument needs to be an integer larger than 32");
i+=2;
}
else if(argMark == "-H")
{
numMismatchesPerReadMer = atoi(argv[i+1]);
if(numMismatchesPerReadMer < 1 || numMismatchesPerReadMer > 3)
PrintHomManual("-H argument parameter should be 1 <= INT <= 3");
i+=2;
}
else if(argMark == "-p")
{
numPhysicalSplits = atoi(argv[i+1]);
if(numPhysicalSplits < 1 || numPhysicalSplits > 10)
PrintHomManual("-p argument parameter should be: 1 <= INT <= 10");
i+=2;
}
else if(argMark == "-t")
{
numParallelSplits = atoi(argv[i+1]);
if(numParallelSplits < 1 || numParallelSplits > 24)
PrintHomManual("-t argument parameter should be: 1 <= INT <= 24");
i+=2;
}
else
{
if(argMark[0] == '-') //False command
PrintHomManual("Unknown command line argument: " + argMark);
//i is the reference
//i+1 is the exectHom
//i+2 is the inexactHom
if(argc != i+3)
PrintHomManual("<Reference> <ExactHom> <InexactHom> should be the last three arguments");
refFile = argv[i];
homTablePerfectMatchFile = argv[i+1];
homTableInexactMatchFile = argv[i+2];
cout << "refFile: " << refFile << "\thomTablePerfectMatchFile: " << homTablePerfectMatchFile << "\thomTableInexactMatchFile: " << homTableInexactMatchFile << endl;
if(homTablePerfectMatchFile == homTableInexactMatchFile)
PrintHomManual("<ExactHom> should be different than <InexactHom>");
VerifyRefFileAndFai();
i+=3;
}
}
if(refFile == "")
{
PrintHomManual("Missing <Reference> argument.");
}
if(kmerLen == 0)
PrintHomManual("-K argument is required.");