forked from otaken120/CSIMAC
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathcPRFCluster.cpp
More file actions
2275 lines (2131 loc) · 107 KB
/
Copy pathcPRFCluster.cpp
File metadata and controls
2275 lines (2131 loc) · 107 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
/*
To change: multiple hits considered poisson rate
ZMZ 07/20/2016
Fixed bug: output Scale;
if (output_format_num==1 || (output_format_num==0 && Scale>1)) //(output_format_num==0 and Scale==3) and (output_format_num==1 and Scale==1) are exactly the same output position
{
if (output_format_num==0 and Scale>1) {Scale=Scale/3;}//for amino acid, scale it down 3 times to make it comparable to nucleotide Scale
for(long i=0; i<N; i++) {//each position after scaled
for (long j=0;j<Scale;j++){ // JT: fix this Scale/3 = 1/3 - ZMZ fixed adjusting amino acid scales down 3 times to be comparable to nucleotide and expanding each position i to i*Scale+j (0<j<Scale).
cout.width(width);cout<<Scale*i+j+1<<"\t"; //convert to the real amino acid or nucleotide position of the gene, if Scale==1, i; if Scale=6, i=10, new position would be 60-65.
Fixed Seven compiling warnings:
changed from unassigned to int for int position1 = str.find(" ");
|| and && parenthesis
deleted (k,tmp_l,tmp_u)=(0,0.0,0.0); use k=0; tmp_l=tmp_u=0.0;
Added output error messages and updated codes in parseParameters
Changed p=0, r=0 in CIr_stochastic_threaded and CIs_rc_PRF: CIr_stochastic_threaded p=0, r=0; CIs_rc_PRF, dr=0, r=0.
Excluded one site cluster:
In ClusterSubSeq, added ce-cs>1 in 'if (cri <= cri0 && ce-cs>1) {//add the condition to exclude the cluster of one site'
Modified: Used only subregional models to calculate gamma.
Modified: p=0, gamma=0; and remove conditions of vec_r_c[i*3]==0 or vec_r_c[i]==0, that gives NULL gamma
Added GeneLength public parameter, when n=0 and N=GeneLength, quit cluster; else keep all cluster models for sub-regions.
Modified: In LogLikelihoodNonCluster and LogLikelihoodCluster, return 0 when n=0 and lambda=0.
EachSiteModels: all models from the regions with clusters are kept, including models from divide and conquer ClusterSubSeq
//pointer[i].sms.clear();// silent pointer[i].sms.clear() in EachSiteModels, since cumulative models are used in ClusterSubSeq for each site.
ModelAveraging and MS_only==0:
Removed the option MS_only==0 as a condition in ClusterSubSeq, since site models are calculated anyway.
Changed ModelAveraging to EachSiteModels to be more accurate and intuitive.
//ZMZ 07/18/2016.
//Modified: In LogLikelihoodNonCluster and LogLikelihoodCluster, to prevent log(0) case, get the pseudo-lambda: when n=0, lambda = (double)1/(N_cluster_ScaledBack+1);
Fixed bug:
added symbol in LogLikelihoodNonCluster and LogLikelihoodCluster - bug in Synonymous count in likelihood calculation
LogLikelihoodNonCluster(long cs, long ce, long start, long end, char symbol)
LogLikelihoodCluster(long cs, long ce, long start, long end, char symbol)
Fixed bug in Recurrent count in LogLikelihoodNonCluster, from && to ||, (Recurrents[i].sites < cs || Recurrents[i].sites > ce)
Fixed bug in LogLikelihoodCluster and LogLikelihoodNonCluster: added double, or it will be 0. lambda = (double)1/(N_cluster_ScaledBack+1);
Fixed Bug in LogLikelihoodCluster and LogLikelihoodNonCluster: for synonymous, recurrent is not considered; or the replacement recurrent M will be calculated, and create a bug.
*/
#include "cPRFCluster.h"
#include <string>
#include <list>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <thread>
using namespace std;
#ifdef __linux__
unsigned int NUM_CPU = get_nprocs_conf();
#else
unsigned int NUM_CPU = std::thread::hardware_concurrency();
#endif
/***************************************************
* Function: Initialization of parameters
***************************************************/
//Declare and initiate variables for the function cPRFCluster
cPRFCluster::cPRFCluster() {
flag_N_pol=0; //polymorphism
flag_N_div=0; //divergence
confidence_interval=0.95;
quantile_for_CI=(1.0-confidence_interval)/2.0; //0.025
flag_found_pr=0; //polymorphism replacement
flag_found_dr=0; //divergence replacement
flag_found_ps=0; //polymorphism sysnonymous
flag_found_ds=0; //divergence synonymous
//Initiate parameters, require inputs from the user
pol_cons_seqfile = ""; // required user input with the option '-pc file_name', the polymorphism file name with sequences in format of R, S, *.
div_cons_seqfile = ""; // required user input with the option '-dc file_name', the divergence file name with sequences in format of R, S, *.
SilentRate = 0.0;
SilentRate_flag=0;
polymorphism_num_s =""; // required user input with the option '-pn polymorphism_seq_number'.
tumor_num_s =""; // required user input with the option '-dn divergence_seq_number'.
polymorphism_num =-299;
tumor_num =-299;
output_format_num=0;
genetic_code = 1;
criterion_type = 0;
Do_Synonymous_Cluster=0; // By default, option for clustering Synonymous sites in the polymorphism and divergence sequence is off. Users need to use '-s 1' to turn it on.
MS_only=0;
ci_ma=0; // confidence interval for model average
Div_time=0.0; // Species divergent time; can be initiate by the user using prior species divergent time, or it will be estimated based on the given sequence, and it may be biased by the gene.
Do_r_estimate=1; // variable for the estimated selection coefficient r.
Do_ci_r=1; // confidence intervals for selection coefficient
Do_ci_r_exact=0; //exact algorithm estimated r confidence interval
//ZMZ 04/28/2016 added option - regional gamma only
regional_gamma_only=0; //regional only gamma option when regional_gamma_only=1, default weighted gamma
Nuc_replace=1;
NI_estimate=0; // By default, Nuetrality Index will not be estimated. The user can turn it on with '-NI 1'.
TotalRecurrentCount=0;
TotalRecurrentSite=0;
TotalReplacementSite=0;
TotalSilentSite=0;
}
/***************************************************
* Function: remove elements in the vector
***************************************************/
cPRFCluster::~cPRFCluster() {
div_cons_seq.clear();
div_cons_seqname.clear();
vec_r_c.clear();
vec_r_c_r.clear();
vec_rModels_c.clear();
vec_lower_r_c.clear();
vec_upper_r_c.clear();
vec_lower_r_c_r.clear();
vec_upper_r_c_r.clear();
vec_lower_rate_ds.clear();
vec_lower_rate_dr.clear();
vec_upper_rate_ds.clear();
vec_upper_rate_dr.clear();
vec_MA_rate_ds.clear();
vec_MA_rate_dr.clear();
vec_MS_rate_ds.clear();
vec_MS_rate_dr.clear();
vec_SelectedModels.clear();
vec_SelectedModels_ds.clear();
vec_SelectedModels_dr.clear();
vec_AllModels.clear();
vec_AllModels_ds.clear();
vec_AllModels_dr.clear();
}
/***************************************************
* Function: initialization; change the size of the vectors based on gene length and empty the vector
***************************************************/
int cPRFCluster::init(long N){
vec_r_c.resize(N,0.0);
vec_r_c_r.resize(N,0.0);
//vec_rModels_c.resize(N,0.0);
vec_lower_r_c.resize(N,0.0);
vec_upper_r_c.resize(N,0.0);
vec_lower_r_c_r.resize(N,0.0);
vec_upper_r_c_r.resize(N,0.0);
vec_MS_rate_ds.resize(N,0.0);
vec_MS_rate_dr.resize(N,0.0);
vec_MA_rate_ds.resize(N,0.0);
vec_MA_rate_dr.resize(N,0.0);
vec_lower_rate_ds.resize(N,0.0);
vec_lower_rate_dr.resize(N,0.0);
vec_upper_rate_ds.resize(N,0.0);
vec_upper_rate_dr.resize(N,0.0);
vec_SelectedModels_ds.clear();
vec_SelectedModels_dr.clear();
vec_AllModels_ds.clear();
vec_AllModels_dr.clear();
vec_SelectedModels.clear();
vec_AllModels.clear();
vec_MA_rate.resize(N,0.0);
vec_lower_rate.resize(N,0.0);
vec_upper_rate.resize(N,0.0);
return 1;
}
/***************************************************
* Function: Read the input files and execute the main function RunML, and screen output;
* Input Parameter: required divergence file names, and the number of sequences in divergence
***************************************************/
int cPRFCluster::Run(int argc, const char*argv[]) {
int i, flag=1;
srand(1234); // to fix random number generator, to make sure the program is repeatable; need to remove for the final version of the program
try {
//Write in the output file with program name, Version, LastUpdate, and Reference.
cout<<endl<<NAME<<", Version: "<<VERSION<<" [Last Update: "<<LASTUPDATE<<"]"<<endl;
cout<<"Reference: "<<REFERENCE<<endl<<endl;
static time_t time_start = time(NULL); // Record the start time
//Parse input parameters
if (parseParameter(argc, argv)!=1) throw "Error in parsing parameters!";
//Check for presence of the input file and whether the number of tumors is specified
if(div_cons_seqfile=="" || tumor_num_s=="") throw "Failed to specify the input file and/or the number of tumors! Use -H to find out.";
//convert the format for the sequence number from string to int
tumor_num=CONVERT<int>(tumor_num_s);
cout<<"Read cancer divergence consensus input file: "<<div_cons_seqfile<<endl<<endl;
if (readFasta(div_cons_seqfile, div_cons_seqname, div_cons_seq)!=1) throw "Error in reading divergent sequence.";
//Print the divergence consensus sequence and the gene name
cout<<endl<<"Divergence Consensus Sequence:"<<endl<<">"<<div_cons_seqname[0].c_str()<<endl;
cout<<div_cons_seq[0].c_str()<<endl<<endl<<endl;
//Check sequence length for divergence
if(div_cons_seq[0].size()%3!=0) cout<< "Warning: the length of the specified divergence sequence cannot be divided by 3 (codon size)."<<endl;
//Get the recurrent position and count in Recurrents by taking recurrent.txt as an input as the seq file, flag
cout<<"Recurrent positions and counts: "<<endl;
GetRecurrentList(recurrent_file); // JT: rename as GetRecurrentList - ZMZ fixed
cout<<"Number of recurrent positions: "<<Recurrents.size()<<endl;
long jj;
for (jj=0;jj<Recurrents.size();jj++){
cout<<"Recurrent Site:\t"<<Recurrents[jj].sites<<"\tCount: "<<Recurrents[jj].counts<<endl;
int count=Recurrents[jj].counts;
TotalRecurrentCount+=count;
TotalRecurrentSite+=1;
}
//Calculate the gamma and 95% CI gamma for each recurrent site, using 2r/(1-e^(-2r))=RecurrentNumber/(ReplacementRate*TumorNumber)
//Get the lookup table read for CI for all different k
//ZMZ 06/16/2016 update LookupTable_CSIMAC_CI_Recurrent_v10.dat from v9, now with 1000 recur counts
string input_lookup_file="LookupTable_CSIMAC_CI_Recurrent_v10.dat";
LambdaCIs.clear();
LambdaCILookupTable(input_lookup_file);
cout<<"Maximum recurrent count currently permitted by CSIMAC: "<<LambdaCIs.size()<<endl;
if (LambdaCIs.size()==0)
{
cout<<"Error: The LambdaCILookupTable "<<input_lookup_file<<" is empty...\n"; // JT: fix this with a stringconcat or something - ZMZ fixed
throw;
}
//**** Main Step: Run the main function Maximum Likelihood for cancer divergence sequences, to get site specific gamma and 95% CI gamma
RunML(div_cons_seq);
//Display on screen after finish running the program and print out the time used.
cout<<endl<<"Mission accomplished. (Time elapsed: ";
time_t t = time(NULL)-time_start;
int h=t/3600, m=(t%3600)/60, s=t-(t/60)*60;
if(h) cout<<h<<":"<<m<<":"<<s<<")"<<endl;
else cout<<m<<":"<<s<<")"<<endl;
}
catch (const char* e) {
cout<<e<<endl;
flag = 0;
}
catch (...) {
flag = 0;
}
return flag;
}
/***************************************************
* Function: Print out the cluster information and gamma values for replacement divergence by default; and information for synonymous divergence can be printed out if the user assign '-s 1'.
***************************************************/
int cPRFCluster::output(long N){
cout<<endl<<"//Results based on model selection: "<<endl;
cout<<"Cancer divergence synonymous mutation rate (ucs): "<<ucs<<endl;
cout<<"Cancer divergence replacement mutation rate (ucr): "<<ucr<<endl;
// Print out cluster information for synonymous sites in the Divergence sequence if the user assigns '-s 1'.
if(Do_Synonymous_Cluster==1){
cout<<endl<<"Clusters of synonymous divergence:"<<endl;
if(vec_SelectedModels_ds.size()==0){
cout<<"Note: Synonymous divergence (DS) = 1 or 0. There are not enough synonymous divergent sites for clustering!"<<endl<<endl;
}else if(vec_SelectedModels_ds.size()==1 && vec_SelectedModels_ds[0].pos_start==vec_SelectedModels_ds[0].cs && vec_SelectedModels_ds[0].pos_end==vec_SelectedModels_ds[0].ce){
cout<<"Note: CSIMAC identified no clustering of synonymous sites in this gene."<<endl<<endl;
}else{
// JT: to debug vec_SelectedModels_dr and vec_SelectedModels_ds output models. - ZMZ fixed.
for(long i=0; i<vec_SelectedModels_ds.size(); i++){
if (output_format_num==1)
{
cout<<"\nNucleotide\nStart_Position = "<<(vec_SelectedModels_ds[i].pos_start*Scale+1)<<"\tEnd_Position = "<<(vec_SelectedModels_ds[i].pos_end*Scale+1);
cout<<"\tCluster_Start_Position = "<<(vec_SelectedModels_ds[i].cs*Scale+1)<<"\tCluster_End_Position = "<<(vec_SelectedModels_ds[i].ce*Scale+1);
}
else if (output_format_num==0)
{
cout<<"\nAmino Acid\nStart_Position = "<<(vec_SelectedModels_ds[i].pos_start*Scale/3+1)<<"\tEnd_Position = "<<(vec_SelectedModels_ds[i].pos_end*Scale/3+1);
cout<<"\tCluster_Start_Position= "<<(vec_SelectedModels_ds[i].cs*Scale/3+1)<<"\tCluster_End_Position= "<<(vec_SelectedModels_ds[i].ce*Scale/3+1);
}
cout<<endl;
cout<<"InL_0= "<<vec_SelectedModels_ds[i].InL0<<"\tInL= "<<vec_SelectedModels_ds[i].InL;
cout<<"\tAIC_0= "<<vec_SelectedModels_ds[i].AIC0<<"\tAIC= "<<vec_SelectedModels_ds[i].AIC;
cout<<"\tAICc_0= "<<vec_SelectedModels_ds[i].AICc0<<"\tAICc= "<<vec_SelectedModels_ds[i].AICc;
cout<<"\tBIC_0= "<<vec_SelectedModels_ds[i].BIC0<<"\tBIC= "<<vec_SelectedModels_ds[i].BIC;
cout<<endl;
cout<<"P0_DivergenceSynonymous= "<<vec_SelectedModels_ds[i].p0<<"\tPc_DivergenceSynonymous= "<<vec_SelectedModels_ds[i].pc;
cout<<endl<<endl;
}
}
}
// Print out cluster information for Replacement sites in the Divergence sequence by default.
cout<<endl<<"Clusters of replacement divergence:"<<endl;
if(vec_SelectedModels_dr.size()==0){
cout<<"Note: Replacement divergence (DR) = 0. There is no replacement divergent sites for clustering!"<<endl<<endl;
}else if(vec_SelectedModels_dr.size()==1 && vec_SelectedModels_dr[0].pos_start==vec_SelectedModels_dr[0].cs && vec_SelectedModels_dr[0].pos_end==vec_SelectedModels_dr[0].ce){
cout<<"Note: There is no cluster of replacement sites in this gene."<<endl<<endl;
}else{
// JT: to debug vec_SelectedModels_dr and vec_SelectedModels_ds output models. - ZMZ fixed
for(long i=0; i<vec_SelectedModels_dr.size(); i++){
if (output_format_num==1) //0: amino acid output || 1: nucleotide output, default=0
{
cout<<"\nNucleotide\nStart_Position = "<<(vec_SelectedModels_dr[i].pos_start*Scale+1)<<"\tEnd_Position = "<<(vec_SelectedModels_dr[i].pos_end*Scale+1);
cout<<"\tCluster_Start_Position= "<<(vec_SelectedModels_dr[i].cs*Scale+1)<<"\tCluster_End_Position= "<<(vec_SelectedModels_dr[i].ce*Scale+1);
}
else if (output_format_num==0) //0: amino acid output || 1: nucleotide output, default=0
{
cout<<"\nAmino Acid\nStart_Position = "<<(vec_SelectedModels_dr[i].pos_start*Scale/3+1)<<"\tEnd_Position = "<<(vec_SelectedModels_dr[i].pos_end*Scale/3+1);
cout<<"\tCluster_Start_Position= "<<(vec_SelectedModels_dr[i].cs*Scale/3+1)<<"\tCluster_End_Position= "<<(vec_SelectedModels_dr[i].ce*Scale/3+1);
}
cout<<endl;
cout<<"InL_0= "<<vec_SelectedModels_dr[i].InL0<<"\tInL= "<<vec_SelectedModels_dr[i].InL;
cout<<"\tAIC_0= "<<vec_SelectedModels_dr[i].AIC0<<"\tAIC= "<<vec_SelectedModels_dr[i].AIC;
cout<<"\tAICc_0= "<<vec_SelectedModels_dr[i].AICc0<<"\tAICc= "<<vec_SelectedModels_dr[i].AICc;
cout<<"\tBIC_0= "<<vec_SelectedModels_dr[i].BIC0<<"\tBIC= "<<vec_SelectedModels_dr[i].BIC;
cout<<endl;
cout<<"P0_DivergenceReplacement= "<<vec_SelectedModels_dr[i].p0<<"\tPc_DivergenceReplacement= "<<vec_SelectedModels_dr[i].pc;
cout<<endl<<endl;
}
}
if (N*Scale%3!=0) { cout<< "Warning: the length of divergence sequence cannot be divided by 3 (codon size)."<<endl;}
//Print the results of Model Averaging for each position
if (MS_only==0) {
cout<<endl<<"//Results based on model averaging: "<<endl;
cout.setf(ios::left);
int width=15;
//Output the title
cout.width(width); cout<<"Position\t";
if(Do_Synonymous_Cluster==1){ // JT: could we change to Do_Syn_cluster or Do_SynSite_Cluster or Do_Synonymous_Cluster? - ZMZ fixed
cout.width(width); cout<<"MS_DivRep\t";
cout.width(width); cout<<"MA_DivRep\t";
cout.width(width); cout<<"MS_DivSys\t";
cout.width(width); cout<<"MA_DivSys\t";
if(ci_ma==1){
cout.width(width); cout<<"Lower_CI_DivRep\t";
cout.width(width); cout<<"Upper_CI_DivRep\t";
cout.width(width); cout<<"Lower_CI_DivSys\t";
cout.width(width); cout<<"Upper_CI_DivSys\t";
}
}
if(Do_r_estimate==1){ // JT: change to Do_r_estimate - ZMZ fixed
cout.width(width); cout<<"Gamma_Cancer";
if(Do_ci_r==1){ // JT: change do Do_ci_r - ZMZ fixed
cout.width(width); cout<<"\tLower_CI_Gamma_c\t";
cout.width(width); cout<<"Upper_CI_Gamma_c";
cout.width(width); cout<<"\tMutSymbol_Q2_D-2_R1_S-1_*0\t"; //Q stands for Recurrent using 2; D stands for Damaging using -2; R stands for Replacement using 1; S stands for Silent using -1; * stands for conserved using 0
cout.width(width); cout<<"MutationStatus"; // MutationStatus: Q (recurrent), D (Damaging), R (replacement), S (silent) or *(no mutation);
}
}
cout<<endl;//End of the title line of the output values.
//Output the data in the format of nucleotide or amino acid sequence, 0: amino acid output || 1: nucleotide output, default=0
if (output_format_num==1 || (output_format_num==0 && Scale>1)) //(output_format_num==0 and Scale==3) and (output_format_num==1 and Scale==1) are exactly the same output position
{
if (output_format_num==0 and Scale>1) {Scale=Scale/3;}//for amino acid, scale it down 3 times to make it comparable to nucleotide Scale
for(long i=0; i<N; i++) {//each position after scaled
for (long j=0;j<Scale;j++){ // JT: fix this Scale/3 = 1/3 - ZMZ fixed adjusting amino acid scales down 3 times to be comparable to nucleotide and expanding each position i to i*Scale+j (0<j<Scale).
cout.width(width);cout<<Scale*i+j+1<<"\t"; //convert to the real amino acid or nucleotide position of the gene, if Scale==1, i; if Scale=6, i=10, new position would be 60-65.
if(Do_Synonymous_Cluster==1){
cout.width(width);cout<<vec_MS_rate_dr[i]<<"\t";
cout.width(width);cout<<vec_MA_rate_dr[i]<<"\t";
cout.width(width);cout<<vec_MS_rate_ds[i]<<"\t";
cout.width(width);cout<<vec_MA_rate_ds[i]<<"\t";
if(ci_ma==1){
cout.width(width);cout<<vec_lower_rate_dr[i]<<"\t";
cout.width(width);cout<<vec_upper_rate_dr[i]<<"\t";
cout.width(width);cout<<vec_lower_rate_ds[i]<<"\t";
cout.width(width);cout<<vec_upper_rate_ds[i]<<"\t";
}
}
//Do_r_estimate: choose the option of outputting gamma, and 95% confidence intervals of gamma
if(Do_r_estimate==1){
cout.width(width); //cancer gamma
//gamma for site i
if(vec_r_c[i]==299){
cout.width(width);cout<<"INF";
}else if (vec_r_c[i]==-299){
cout.width(width);cout<<"N-INF";
}else if (vec_r_c[i]==-199){
cout.width(width);cout<<"NULL";
}else{
cout.width(width);cout<<vec_r_c[i];
}
//Lower confidence interval of gamma for site i
if(vec_lower_r_c[i]==299){
cout<<"\t";cout.width(width);cout<<"INF"<<"\t";
}else if(vec_lower_r_c[i]==-299){
cout<<"\t";cout.width(width);cout<<"N-INF"<<"\t";
}else if(vec_lower_r_c[i]==-199){
cout<<"\t";cout.width(width);cout<<"NULL"<<"\t";
}else{
cout<<"\t";cout.width(width);cout<<vec_lower_r_c[i]<<"\t";
}
//Upper confidence interval of gamma for site i
if(vec_upper_r_c[i]==299){
cout.width(width);cout<<"INF";
}else if(vec_upper_r_c[i]==-299){
cout.width(width);cout<<"N-INF";
}else if(vec_upper_r_c[i]==-199){
cout.width(width);cout<<"NULL";
}else{
cout.width(width);cout<<vec_upper_r_c[i];
}
}//end of if(Do_r_estimate==1)
//Site labels using number 0, -1, 1, 2, 3
if (div_codon_consensus[i]=='*') { cout.width(width);cout<<"\t"<<0; }
else if (div_codon_consensus[i]=='S') { cout.width(width);cout<<"\t"<<-1; } //Re-ordered
else if (div_codon_consensus[i]=='R') { cout.width(width);cout<<"\t"<<1; }
else if (div_codon_consensus[i]=='Q') { cout.width(width);cout<<"\t"<<2; } //recurrent sites
else if (div_codon_consensus[i]=='D') { cout.width(width);cout<<"\t"<<-2; } //Added Damaging mutation records
else { throw 1;}
cout<<"\t"<<div_codon_consensus[i];
cout<<endl;
}//end of the inside for loop
}//end of the outside for loop
cout<<endl;
}//end of if (output_format_num==1 or (output_format_num==0 and Scale!=1))
//Output the data in the format of amino acids without scaling
if (output_format_num==0 and Scale==1) // 0: amino acid output || 1: nucleotide output, default=0
{
for(long i=0; i<N/3; i++) {
cout.width(width);cout<<i+1<<"\t";
if(Do_Synonymous_Cluster==1){
cout.width(width);cout<<(vec_MS_rate_dr[i*3]+vec_MS_rate_dr[i*3+1]+vec_MS_rate_dr[i*3+2])/3<<"\t";
cout.width(width);cout<<(vec_MA_rate_dr[i*3]+vec_MA_rate_dr[i*3+1]+vec_MA_rate_dr[i*3+2])/3<<"\t";
cout.width(width);cout<<(vec_MS_rate_ds[i*3]+vec_MS_rate_ds[i*3+1]+vec_MS_rate_ds[i*3+2])/3<<"\t";
cout.width(width);cout<<(vec_MA_rate_ds[i*3]+vec_MA_rate_ds[i*3+1]+vec_MA_rate_ds[i*3+2])/3<<"\t";
if(ci_ma==1){
cout.width(width);cout<<(vec_lower_rate_dr[i*3]+vec_lower_rate_dr[i*3+1]+vec_lower_rate_dr[i*3+2])/3<<"\t";
cout.width(width);cout<<(vec_upper_rate_dr[i*3]+vec_upper_rate_dr[i*3+1]+vec_upper_rate_dr[i*3+2])/3<<"\t";
cout.width(width);cout<<(vec_lower_rate_ds[i*3]+vec_lower_rate_ds[i*3+1]+vec_lower_rate_ds[i*3+2])/3<<"\t";
cout.width(width);cout<<(vec_upper_rate_ds[i*3]+vec_upper_rate_ds[i*3+1]+vec_upper_rate_ds[i*3+2])/3<<"\t";
}
}//end of if(Do_Synonymous_Cluster==1)
//Do_r_estimate: choose the option of outputting gamma, and 95% confidence intervals of gamma
if(Do_r_estimate==1){
cout.width(width);
//gamma for site i
if(vec_r_c[i*3]==299 or vec_r_c[i*3+1]==299 or vec_r_c[i*3+2]==299){
cout.width(width);cout<<"INF";
}else if (vec_r_c[i*3]==-299 or vec_r_c[i*3+1]==-299 or vec_r_c[i*3+2]==-299){
cout.width(width);cout<<"N-INF";
}else if (vec_r_c[i*3]==-199 || vec_r_c[i*3+1]==-199 || vec_r_c[i*3+2]==-199){
cout.width(width);cout<<"NULL";
}else{
cout.width(width);cout<<(vec_r_c[i*3]+vec_r_c[i*3+1]+vec_r_c[i*3+2])/3;
}
//Lower confidence interval of gamma for site i
if(vec_lower_r_c[i*3]==299 or vec_lower_r_c[i*3+1]==299 or vec_lower_r_c[i*3+2]==299){
cout<<"\t";cout.width(width);cout<<"INF"<<"\t";
}else if(vec_lower_r_c[i*3]==-299 or vec_lower_r_c[i*3+1]==-299 or vec_lower_r_c[i*3+2]==-299){
cout<<"\t";cout.width(width);cout<<"N-INF"<<"\t";
}else if(vec_lower_r_c[i*3]==-199 || vec_lower_r_c[i*3+1]==-199 || vec_lower_r_c[i*3+2]==-199){
cout<<"\t";cout.width(width);cout<<"NULL"<<"\t";
}else{
cout<<"\t";cout.width(width);cout<<(vec_lower_r_c[i*3]+vec_lower_r_c[i*3+1]+vec_lower_r_c[i*3+2])/3<<"\t";
}
//Upper confidence interval of gamma for site i
if(vec_upper_r_c[i*3]==299 or vec_upper_r_c[i*3+1]==299 or vec_upper_r_c[i*3+2]==299){
cout.width(width);cout<<"INF";
}else if(vec_upper_r_c[i*3]==-299 or vec_upper_r_c[i*3+1]==-299 or vec_upper_r_c[i*3+2]==-299){
cout.width(width);cout<<"N-INF";
}else if(vec_upper_r_c[i*3]==-199 || vec_upper_r_c[i*3+1]==-199 || vec_upper_r_c[i*3+2]==-199){
cout.width(width);cout<<"NULL";
}else{
cout.width(width);cout<<(vec_upper_r_c[i*3]+vec_upper_r_c[i*3+1]+vec_upper_r_c[i*3+2])/3;
}
} //end of if(Do_r_estimate==1)
//Site labels using number 0, -1, 1, 2, 3
if (div_codon_consensus[i*3]=='*' and div_codon_consensus[i*3+1]=='*' and div_codon_consensus[i*3+2]=='*') { cout.width(width);cout<<"\t"<<0; }
else if (div_codon_consensus[i*3]=='S' or div_codon_consensus[i*3+1]=='S' or div_codon_consensus[i*3+2]=='S') { cout.width(width);cout<<"\t"<<-1; } // Reordered; S first, can be overwritten by laters
else if (div_codon_consensus[i*3]=='R' or div_codon_consensus[i*3+1]=='R' or div_codon_consensus[i*3+2]=='R') { cout.width(width);cout<<"\t"<<1; }
else if (div_codon_consensus[i*3]=='Q' or div_codon_consensus[i*3+1]=='Q' or div_codon_consensus[i*3+2]=='Q') { cout.width(width);cout<<"\t"<<2; }
else if (div_codon_consensus[i*3]=='D' or div_codon_consensus[i*3+1]=='D' or div_codon_consensus[i*3+2]=='D') { cout.width(width);cout<<"\t"<<-2; } // Added Damaging mutation records
else { throw 1;}
//Site labels using characters *, S, R, Q, D
if (div_codon_consensus[i*3]=='*' and div_codon_consensus[i*3+1]=='*' and div_codon_consensus[i*3+2]=='*') { cout<<"\t*"; }
else if (div_codon_consensus[i*3]=='S' or div_codon_consensus[i*3+1]=='S' or div_codon_consensus[i*3+2]=='S') { cout<<"\tS"; }
else if (div_codon_consensus[i*3]=='R' or div_codon_consensus[i*3+1]=='R' or div_codon_consensus[i*3+2]=='R') { cout<<"\tR"; }
else if (div_codon_consensus[i*3]=='Q' or div_codon_consensus[i*3+1]=='Q' or div_codon_consensus[i*3+2]=='Q') { cout<<"\tQ"; }
else if (div_codon_consensus[i*3]=='D' or div_codon_consensus[i*3+1]=='D' or div_codon_consensus[i*3+2]=='D') { cout<<"\tD"; }
else { throw 1;}
cout<<endl;//end of site i, go to next site in the for loop
}//end of the for loop, for(long i=0; i<N/3; i++)
}//end of if (output_format_num==0 and Scale==1)
}// end of if (MS_only==0)
else if (MS_only==1){
cout<<endl<<"*************"<<endl;
cout<<"Warning:"<<endl<<"Check the parameter -m. If only model selection is used to find the probability of the site being a variant is performed, there is no estimate of the selection coefficient (gamma) and its confidence intervals. Please check tutorial for more details!"<<endl;
cout<<"*************"<<endl;
return 1;
}
cout<<endl<<"Abbreviation: MS=Model Selection; MA=Model Averaging; CI=Confidence Interval; ds=Divergence Synonymous; dr=Divergence Replacement; Gamma=N*s (Gamma: scaled selection coefficient (selection intensity); s: selection coefficient); gamma >1 Negative selection, <1 Positive selection); INF=Infinite; N-INF=Negative Infinite; NULL=Not enough information for this site"<<endl;
cout<<"Abbreviation: MutSymbol_Q2_D-2_R1_S-1_*0: Q stands for Recurrent using 2; D stands for Damaging using -2; R stands for Replacement using 1; S stands for Silent using -1; * stands for conserved using 0."<<endl;
cout<<endl<<"#End of clustering"<<endl<<endl;
return 1;
}
/***************************************************
* Function: Main function for Clustering by Maximum likelihood for synonymous and replacement sites in the polymorphism and divergence sequences.
* Input Parameter: polymorphism sequence, divergence sequence
* Output:
* Return Value:
***************************************************/
int cPRFCluster::RunML(vector<string> div_cons_seq) {
//use only one format of input for the final version
div_codon_consensus = div_cons_seq[0]; // Get divergence sequence with synonymous (S) and replacement (R) sites labeled
long N=div_codon_consensus.length(); //polymorphism and divergence sequence length, the two are equal.
init(N); //initialization subfunction: change the size of the vectors based on gene length and empty the vector
GeneLength=N;
double ds=0.0;// initializing synonymous divergence at zero
double dr=0.0;// initializing replacement divergence at zero
// Count synonymous divergent sites by finding symbol 'S' in the divergent sequence from start position 0 to the end position N-1
ds=getDifference(div_codon_consensus,0,N-1,'S');
// Count replacement divergent sites by finding symbol 'R' in the divergent sequence from start position 0 to the end position N-1
dr=getDifference(div_codon_consensus,0,N-1,'R');
TotalReplacementSite=dr;
TotalSilentSite=ds;
//Print the # of divergent synonymous and replacement sites labeled with 'S' and 'R'
cout<<"Synonymous divergent count (DS): "<<ds<<endl;
cout<<"Replacement divergent count (DR): "<<dr<<endl;
cout<<"Number of tumor samples: "<<tumor_num<<endl;
long N_ScaledBack=N*Scale; //Scale the gene length back
cout<<"Gene length before scaling: "<<GeneLength<<"\tAfter scaling: "<<N_ScaledBack<<" bp"<<endl;
//Get the synonymous mutation rate (ucs) based on the number of silent mutations in the gene or from user-input (MutSigCV SilentRate). The latter is preferred.
ucs=CancerSynonymousRate(tumor_num, N);
//double ratio_NS=CalculateNS(ref_seq_gene); // calculate the ratio of replacement and synonymous N/S
double ratio_NS= 0.345291479; //the ratio is (0.77/2.23), assuming that the first and third position will be nonsynonymous 5% and 72% of the time. See Nei and Gojobori's paper 1986
cout<<"The ratio of replacement mutations to synonymous mutations is "<<ratio_NS<<endl;
ucr=ReplacementRate(ratio_NS, ucs); // Get replacement rate for cancer divergence (ucr)
cout<<"Cancer replacement divergence mutation rate: "<<ucr<<endl;
// Fixed bug due to the new OS X 10.9 system [error: variable length array of non-POD element type 'struct SiteModels']. Solution: use a very large number instead of the parameter N for the gene length, for keeping all models for each gene site, to make sure the number is larger than the gene length.
// struct SiteModels sm_pol[N];
struct SiteModels sm_div[10000];
if (N>10000) { cout<<"The length of the gene exceeds 10000. Scale it down or revise the SiteModels upper-boundary array size!"<<endl; throw 1;}
//cout<<" Estimated time: "<<(12*N/1000+8)<<" minutes for this gene with 20000 models."<<endl;
cout<<"CSIMAC is conducting the two time-consuming steps, ClusterSubSeq and Do_ci_r_stochastic."<<endl;
//cout<<" ClusterSubSeq depends on the model number, rate: ~4 minutes for each additional 10000 models, ~6 hours for 1 million models"<<endl;
//cout<<" Do_ci_r_stochastic is determined by gene length, with the speed rate 12 minutes per 1000 sites."<<endl;
// Clustering and 95% CI for the clusters, this will be calculated for Silent divergence if (Do_Synonymous_Cluster==1)
if(Do_Synonymous_Cluster==1){
//Initialize for DS
vec_SelectedModels.clear();
vec_MS_rate.clear();
vec_MA_rate.clear();
vec_lower_rate.clear();
vec_upper_rate.clear();
vec_MS_rate.resize(N,0.0);
vec_MA_rate.resize(N,0.0);
vec_lower_rate.resize(N,0.0);
vec_upper_rate.resize(N,0.0);
vec_MS_rate_ds.clear();
vec_MA_rate_ds.clear();
vec_MS_rate_ds.resize(N,0.0);
vec_MA_rate_ds.resize(N,0.0);
// Major Step: Find cluster and calculate probability using multiple models for synonymous divergence
cout<<endl<<"Starting the clustering of synonymous variants"<<endl;
ClusterSubSeq(0, N-1,'S',sm_div); // Major subroutine for clustering of synonymous variants
cout<<"Finished clustering of synonymous variants."<<endl;
vec_SelectedModels_ds=vec_SelectedModels;
vec_MS_rate_ds=vec_MS_rate;
vec_MA_rate_ds=vec_MA_rate;
if(MS_only==0 && ci_ma==1 && ds >0){
CI_MA(sm_div,N); // Major subroutine for 95% CI for probability of synonymous variant for each site
}
vec_lower_rate_ds=vec_lower_rate;
vec_upper_rate_ds=vec_upper_rate;
}
//Empty vectors and re-size for replacement divergence (DR)
vec_SelectedModels.clear();
vec_SelectedModels_dr.clear();
vec_MS_rate.clear();
vec_MA_rate.clear();
vec_lower_rate.clear();
vec_upper_rate.clear();
vec_MS_rate.resize(N,0.0);
vec_MA_rate.resize(N,0.0);
vec_lower_rate.resize(N,0.0);
vec_upper_rate.resize(N,0.0);
vec_MS_rate_dr.clear();
vec_MA_rate_dr.clear();
vec_MS_rate_dr.resize(N,0.0);
vec_MA_rate_dr.resize(N,0.0);
//Major Step: Find cluster and calculate probability using multiple models for replacement divergence
cout<<endl<<"Starting the clustering of replacement variants"<<endl;
time_t time_start1 = time(NULL); // Record the start time
ClusterSubSeq(0, N-1,'R',sm_div); //find clusters in the sequence
cout<<"Finished clustering of replacement variants."<<endl;
cout<<"Time elapsed during clustering of replacement variants: ";
time_t t2 = time(NULL)-time_start1;
int h=t2/3600, m=(t2%3600)/60, s=t2-(t2/60)*60;
if(h) cout<<h<<":"<<m<<":"<<s<<")"<<endl;
else cout<<m<<":"<<s<<")"<<endl;
vec_SelectedModels_dr=vec_SelectedModels; // all selected models for the clustering
vec_MS_rate_dr=vec_MS_rate; // selected model rate for the clustering rate
vec_MA_rate_dr=vec_MA_rate; // model averaged rate for the clustering rate
// Calculate the 95% CI for the clustering probability
if(MS_only==0 && ci_ma==1 && dr>0){
cout<<endl<<"Starting model-averaging analysis to yield CIs for replacement divergence"<<endl;
time_t time_start1 = time(NULL); // Record the start time
CI_MA(sm_div,N);
cout<<endl<<"Finished model-averaging analysis to yield CIs for replacement divergence"<<endl;
cout<<"Time elapsed during model-averaging analysis to yield CIs: ";
time_t t2 = time(NULL)-time_start1;
int h=t2/3600, m=(t2%3600)/60, s=t2-(t2/60)*60;
if(h) cout<<h<<":"<<m<<":"<<s<<")"<<endl;
else cout<<m<<":"<<s<<")"<<endl;
}
vec_lower_rate_dr=vec_lower_rate; // lower 95% CI rate for the clustering probability
vec_upper_rate_dr=vec_upper_rate; // upper 95% CI rate for the clustering probability
//Estimate gamma for Replacement sites
if (MS_only==0 && Do_r_estimate==1) {
//If dr == 0, r can't be estimated.
if(dr>0){
cout<<endl<<"Starting estimation of gamma for human cancer replacement divergence."<<endl;
time_t time_start1 = time(NULL); // Record the start time
rc_SitePRF(tumor_num,ucr, N); //estimate gamma for cancer divergence
cout<<"Estimation of gamma for human cancer replacement divergence completed."<<endl;
cout<<"Time elapsed during estimation of gamma for human cancer replacement divergence: ";
time_t t2 = time(NULL)-time_start1;
int h=t2/3600, m=(t2%3600)/60, s=t2-(t2/60)*60;
if(h) cout<<h<<":"<<m<<":"<<s<<")"<<endl;
else cout<<m<<":"<<s<<")"<<endl;
}else{
cout<<endl<<"*************"<<endl;
cout<<"There are no replacement sites to estimate gamma!"<<endl;
cout<<"*************"<<endl;
}
// Calculate confidence intervals for r using the exact or stochastic algorithm.
if(dr>0 && Do_ci_r==1){
if(Do_ci_r_exact==1){ // Use exact algorithm to calculate confidence intervals for r
cout<<endl<<"Starting the estimation of CIs for Gamma by the exact algorithm."<<endl;
time_t time_start1 = time(NULL); // Record the start time
CIr_exact(sm_div,N);
cout<<endl<<"Estimation of CIs for Gamma by exact algorithm complete."<<endl;
cout<<"Time elapsed during estimation of CIs for Gamma by exact algorithm: ";
time_t t2 = time(NULL)-time_start1;
int h=t2/3600, m=(t2%3600)/60, s=t2-(t2/60)*60;
if(h) cout<<h<<":"<<m<<":"<<s<<")"<<endl;
else cout<<m<<":"<<s<<")"<<endl;
}else{ // Use stochastic algorithm to calculate r Confidence Intervals
cout<<endl<<"Starting the estimation of CIs for Gamma by stochastic algorithm."<<endl;
time_t time_start1 = time(NULL); // Record the start time
CIr_stochastic(sm_div,N);
cout<<endl<<"Estimation of CIs for Gamma by stochastic algorithm complete."<<endl;
cout<<"CIr_stochastic (Time elapsed: ";
time_t t2 = time(NULL)-time_start1;
int h=t2/3600, m=(t2%3600)/60, s=t2-(t2/60)*60;
if(h) cout<<h<<":"<<m<<":"<<s<<")"<<endl;
else cout<<m<<":"<<s<<")"<<endl;
}
}
//for cases replacement sites and divergence sequences are too few.
else if(Do_ci_r==1){
cout<<endl<<"*************"<<endl;
cout<<"There are no replacement sites to estimate CIs for gamma!"<<endl;
cout<<"*************"<<endl;
}
}//end of if (MS_only==0 && Do_r_estimate==1)
if(MS_only==1){
cout<<endl<<"*************"<<endl;
cout<<"Warning:"<<endl<<"Check the parameter -m. If only model selection is used to find the probability of the site being a variant is performed, there is no estimate of the selection coefficient (gamma) and its confidence intervals. Please check tutorial for more details!"<<endl;
cout<<"*************"<<endl;
}
int rs=0;
int RecurSize=Recurrents.size();
for (rs=0;rs<RecurSize;rs++)
{
int pos=Recurrents[rs].sites;
div_codon_consensus[pos]='Q'; //Record recurrent sites as Q
}
//print CSIMAC main results (gamma, 95% CI gamma) to the output file
output(N);
return 1;
}
/***************************************************
Subfunction - open and read the recurrent file
Input: the file name, use the same format of the Recurrent.txt
Output: recurrent list
***************************************************/
int cPRFCluster::GetRecurrentList(string input_f){
ifstream myfileFn2(input_f.c_str());
if (!myfileFn2) throw "Error in opening Recurrent File for GetRecurrentList...\n";
//Read the file; remove the empty lines at the end of the file
string str;
while ( myfileFn2.good()) {
getline(myfileFn2,str);
// cout<<"Each line: "<<str<<endl;
int position1 = str.find(" => ");
if (position1!=std::string::npos)
{
//cout<<"The position1: "<<position1<<endl;
}
else {cout<<"Error! Failed to find the marker => in the recurrent file for GetRecurrentList!\n";}
int position2=str.find(" ", position1+2);
//Get the recurrent position and recurrent count
if (position1<20 and position1>0)
{
string e1 = str.substr(0, position1);
string e2 = str.substr(position1 + 4,
str.length() - position1 - 4);
//cout<<e1<<"\t**"<<e2<<"$$\t***"<<endl;
int pos=CONVERT<int>(e1);
int count=CONVERT<int>(e2);
RecurrentSitesCounts tmp_rc(pos, count);
Recurrents.push_back(tmp_rc);
//Compact into one site for each codon
}
}
myfileFn2.close();
/*
cout<<"***The size of the recurrent: "<<Recurrents.size()<<endl;
cout<<"RecurrentSite: "<<Recurrents[0].sites<<"\tCount: ";
cout<<Recurrents[0].counts<<endl;
*/
return 1;
}
/***************************************************
* Function: Count the number for Synonymous or Replacement
* Input Parameter: seq - polymorphism or divergence sequence;start position; end position; symbol - Synonymous (S) or Replacement (R)
* Output: the number of symbols (Synonymous or Replacement)
* Return Value: the number of symbols (Synonymous or Replacement)
***************************************************/
long cPRFCluster::getDifference(string seq, int pos_start, int pos_end, char symbol) {
long i, n = 0;
for (i=pos_start; i<=pos_end; i++) {
if (seq[i]==symbol) n++;
}
if (symbol == 'S')
return n;
else if (symbol == 'R')
{
for (long i = 0; i < Recurrents.size(); i++)
{
if (Recurrents[i].sites >= pos_start and Recurrents[i].sites <= pos_end)
{
n += (Recurrents[i].counts - 1);
}
}
return n;
}
else return -1;
}
/***************************************************
* Function: calculate the likelihood of Binomial Probability i*log(p)+(n-i)*log(1-p); p=i/n; Log likelihood of Bernoulli distribution. BernoulliProb= (i/n)^i*[(n-i)/n]^(n-i); prob=Log(BernoulliProb)=i*log(i/n)+(n-i)*log[(n-i)/n]
* Input Parameter: total number n and occurence i
* Output: probability
* Return Value: probability
***************************************************/
double cPRFCluster::BinomialProb(long n, long i) {
double prob = 0.0;
prob += (i==0)?0:i*log(double(i)/n);
prob += (n-i==0)?0:(n-i)*log(double(n-i)/n);
return prob;
}
/***************************************************
* Function: Calculate the log of factorial, to prevent the large number.
***************************************************/
double cPRFCluster::factorial(int n) {
//ZMZ added 04/26/2016
double ans = 1;
//ZMZ added 04/25/2016
if (n<1) {
cout<<"\nRecurrent Count in Factorial: "<<n<<endl;
throw "Error in Factorial with negative values from Recurrent!\n";}
for (int i = 1; i <=n; i++)
ans += log(i);
return ans;
}
/***************************************************
* Function: Calculate loglikelihood for the cluster using the poisson rate
***************************************************/
double cPRFCluster::LogLikelihoodCluster(long cs, long ce, long start, long end, char symbol) {
//ZMZ added 04/26/2016
double M = 0;
long N_cluster_ScaledBack = (ce - cs + 1)*Scale;
long n = getDifference(div_codon_consensus,cs,ce,symbol);
double lambda = (double)n/N_cluster_ScaledBack; //poisson rate
double likelihood;
if (n==0) { //To prevent log(0) case, get the pseudo-lambda
lambda = (double)1/(N_cluster_ScaledBack+1); //ZMZ 07/18/2016. Fixed bug, added double, or it will be 0. lambda = (double)1/(N_cluster_ScaledBack+1);
likelihood=lambda * N_cluster_ScaledBack * log(lambda) - N_cluster_ScaledBack * lambda;
//cout<<"\nTest LogLikelihoodCluster, lambda:\t"<<lambda<<"\tlog(lambda):\t"<<log(lambda)<<"likelihood:"<<likelihood<<"\t- n:"<<-n<<endl;
//return likelihood;
return 0;
}
if (symbol=='S') {//for synonymous, recurrent is not considered; or the replacement recurrent M will be calculated, and create a bug.
M=0;
likelihood=n * log(lambda) - n - M;
return likelihood;
}
for (long i = 0; i < Recurrents.size(); i++)
{
if (Recurrents[i].sites >= cs and Recurrents[i].sites <= ce)
{
//ZMZ added 04/26/2016
int RecCount=CONVERT<int>(Recurrents[i].counts);
//n += (Recurrents[i].counts - 1); calculation moved to getDifference
M += factorial(RecCount);
//ZMZ added 04/26/2016
if (RecCount<2) {
cout<<"\nLogLikelihoodCluster: Recurrent Count:$"<<Recurrents[i].counts<<"$Converted Recurrent Count:$"<<RecCount<<"$Recurrent Factorial:$"<<M<<endl;
throw "LogLikelihoodCluster: Error in Recurrent Factorial: not integer Recurrent Count!\n";
}
}
}
likelihood=n * log(lambda) - n - M;
//cout<<"\nTest LogLikelihoodCluster, lambda:\t"<<lambda<<"likelihood:"<<likelihood<<"\tlog(lambda):\t"<<log(lambda)<<"\t- n:"<<-n<<"\t-M:"<<-M<<endl;
return likelihood;
}
/***************************************************
* Function: Calculate loglikelihood for the non-clusters using the poisson rate
***************************************************/
double cPRFCluster::LogLikelihoodNonCluster(long cs, long ce, long start, long end, char symbol) {
//ZMZ added 04/26/2016
double M = 0;
long N_noncluster_ScaledBack = ((end-start + 1)-(ce - cs + 1))*Scale;
long n = getDifference(div_codon_consensus,start,cs-1,symbol) + getDifference(div_codon_consensus,ce+1,end,symbol);
double lambda = (double)n/N_noncluster_ScaledBack;
double likelihood;
if (n==0) { //To prevent log(0) case, get the pseudo-lambda
lambda = (double)1/(N_noncluster_ScaledBack+1);
likelihood=lambda * N_noncluster_ScaledBack * log(lambda) - N_noncluster_ScaledBack * lambda;
//return likelihood;
return 0;
}
if (symbol=='S') {//for synonymous, recurrent is not considered; or the replacement recurrent M will be calculated, and create a bug.
M=0;
likelihood=n * log(lambda) - n - M;
return likelihood;
}
for (long i = 0; i < Recurrents.size(); i++)
{
if (Recurrents[i].sites < cs || Recurrents[i].sites > ce)
{
//ZMZ added 04/26/2016
int RecCount=CONVERT<int>(Recurrents[i].counts);
//n += (Recurrents[i].counts - 1); calculation moved to getDifference
M += factorial(RecCount);
//ZMZ added 04/26/2016
if (RecCount<2) {
cout<<"\nLogLikelihoodNonCluster: Recurrent Count:$"<<Recurrents[i].counts<<"$Converted Recurrent Count:$"<<RecCount<<"$Recurrent Factorial:$"<<M<<endl;
throw "nLogLikelihoodNonCluster: Error in Recurrent Factorial: not integer Recurrent Count!\n";
}
}
}
likelihood=n * log(lambda) - n - M;
//cout<<"\nTest LogLikelihoodNonCluster, lambda:\t"<<lambda<<"likelihood:"<<likelihood<<"\tlog(lambda):\t"<<log(lambda)<<"\t- n:"<<-n<<"\t-M:"<<-M<<endl;
return likelihood;
}
/***************************************************
* Function: Determine the hot and cold spots by calculating the percentage of symbol counts in the cluster (nc/cent_len) and non-cluster regions (nw-nc)/non_cent_len.
* Input Parameter: sequence start and end as pos_start, pos_end;cluster start and end as cs and ce; probablity of cluster and non-cluster region as pc and p0; number of symbol (Synonymous or Replacement) counts in the whole sequence and in the cluster only (nw and nc)
* Output: percentage of symbols in the cluster and non-cluster regions
* Return Value:
***************************************************/
double cPRFCluster::getp0pc_MK(int pos_start, int pos_end, int cs, int ce, float &p0, float &pc, int nw, int nc) {
int non_cent_len=pos_end-pos_start-ce+cs; //the length for non-cluster sequence.
int non_cent_len_ScaledBack=non_cent_len*Scale; //Scale the length for non-cluster sequence back
if(cs==pos_start && ce==pos_end){
p0=0.0; //rate of variants in the non-cluster region is 0 if the cluster part is the whole sequence and the non-cluster sequence is empty.
}else{
//nw means the total number of variants in the whole sequence; nc means the number of variants in the cluster region.
p0=(float)(nw-nc)/non_cent_len_ScaledBack; // rate of variants in the non-cluster region
}
//pc means the cluster part; nc means number of symbols (Synonymous or Replacement) in the cluster region
int cent_len=ce-cs+1; // the length for the cluster
int cent_len_ScaledBack=cent_len*Scale; //Scale the length for the cluster back
pc=(float)nc/cent_len_ScaledBack; // rate of variants in the cluster region
return 1;
}
/***************************************************
* Function: Find cluster and calculate likelihood of sites being variant under different models AIC, BIC, AICc
* Input Parameter: start position, end position, symbol - synonymous or replacement,?SiteModels *pointer?
* Output: vectors vec_AllModels; vec_SelectedModels
* Return Value:
***************************************************/
int cPRFCluster::ClusterSubSeq(int pos_start, int pos_end, char symbol, struct SiteModels *pointer) {
time_t time_start1 = time(NULL); // Record the start time
long N = pos_end - pos_start + 1; // total region length
long N_ScaledBack=N*Scale; // Scale the gene length back
long symbol_n = 0; // declare the counts of variant sites
symbol_n=getDifference(div_codon_consensus, pos_start, pos_end, symbol); // Get the counts of variant sites
if (N==0 || N==1)
{
cout<<"No cluster; quit ClusterSubSeq for the region "<<pos_start<<"\tto\t"<<pos_end<<"\tTotalVariant\t"<<symbol_n<<endl;
return 1; // return if the sequence length is 0/1 or the count of variant sites is 0
}
if (symbol_n==0 && flag_found_dr==0) //when n=0 and no cluster found ever, quit cluster; else keep all cluster models for sub-regions.
{
cout<<"No cluster; quit ClusterSubSeq for the gene "<<pos_start<<"\tto\t"<<pos_end<<"\tTotalVariant\t"<<symbol_n<<endl;
return 1; // return if the sequence length is 0/1 or the count of variant sites is 0
}
double InL0 = LogLikelihoodCluster(0, N-1, 0, N-1,symbol); // the background likelihood for the whole gene/region
double InL_cluster_max, InL_noncluster_max; // for cases with 0 variant log(0)
InL_cluster_max=InL_noncluster_max=InL0;
double AIC0,AICc0,BIC0,cri0;
cri0=AIC0=AICc0=BIC0=-2*InL0; // the overall weight for the whole region
double InL,AIC,AICc,BIC;
InL = InL0;
AIC = AICc = BIC = AIC0; // Initialization based on the whole region, parameter is 0 for the whole region with the cluster in the whole region.
double min_cri = 10000000; // a big value for an initial of the minimal criteria to keep the best model, the smaller cri, the better the model.
int para=2; // the number of parameters, cs and ce
long cs, ce, cs_max, ce_max; //cluster start and end positions
double lambda_0_max,lambda_c_max;
lambda_0_max=0;
lambda_c_max=symbol_n/N_ScaledBack;
int found=0; // means the absence of the cluster; found =1, found the lowest AIC/BIC, as the best model
vec_AllModels.clear(); // empty the vec_AllModels for the new region
//ZMZ debugging 04/27/2016
//cout<<"Model Information\npos_start\tpos_end\tcs\tce\tp0\tpc\tsymbol_n\tsymbol_cn\tInL_tmp\tInL_tmp_cluster\tInL_tmp_noncluster\tcri\tcri0\tLnL0"<<endl;
cout<<"Within the clustering subfunction ClusterSubSeq, start of the region: "<<pos_start<<"\tEnd: "<<pos_end<<"\tTotalVariant\t"<<symbol_n<<endl;
//Slide window across the whole sequence for the cluster start and end position to find the cluster with the window size as 1.
for (cs=pos_start; cs<=pos_end; cs+=1) {
for(ce=cs; ce<=pos_end; ce+=1) {
para=2;
if (cs==pos_start && ce==pos_end) para = 0;//the number of parameters is zero, since both cs and ce are known
else if(ce==pos_end || cs==pos_start) para=1; //the number of parameters is one, since one of cs and ce is known
long symbol_cn = 0; //declare the counts of variant sites in the cluster region only.
symbol_cn = getDifference(div_codon_consensus, cs, ce, symbol);//Get the counts of variant sites in the cluster region only.
long symbol_ncn = 0; //declare the counts of variant sites in the non-cluster region only.
symbol_ncn = getDifference(div_codon_consensus, pos_start, cs, symbol)+ getDifference(div_codon_consensus, ce, pos_end, symbol);//Get the counts of variant sites in the non-cluster region only.
long total_variant=symbol_cn + symbol_ncn;
//Calculate log likelihood of the sites being variant in the cluster & Non-cluster
double InL_tmp_cluster = LogLikelihoodCluster(cs, ce, pos_start, pos_end,symbol);
double InL_tmp_noncluster = LogLikelihoodNonCluster(cs, ce, pos_start, pos_end,symbol);
//if (symbol_ncn==0) {InL_tmp_noncluster=InL0;}
//if (symbol_cn==0) {InL_tmp_cluster=InL0;}
double InL_tmp = InL_tmp_cluster + InL_tmp_noncluster;
double AIC_tmp = -2*InL_tmp + 2*para; // AIC=-2ln(L)+2k
double AIC_weight=AIC_tmp; // AIC weight
double AICc_tmp = AIC_tmp;
if (N_ScaledBack-para-1>0.0) AICc_tmp += 2*para*(para+1)/(N_ScaledBack-para-1); //calculate AICc=AIC+2k(k+1)/(l-k-1)
else AICc_tmp = 2*AIC_tmp;
double BIC_tmp = -2*InL_tmp + para*log(double(N_ScaledBack)); //calculate BIC=-2ln(L)+kln(l)
double cri; //criteria for the model selection
//AIC, default
if (criterion_type==0){
cri = AIC_tmp;
cri0=AIC; //update with the best model
}
//BIC
else if (criterion_type==1){
cri = BIC_tmp;
cri0=BIC; //update with the best model
}
//AICc
else if (criterion_type==2){
cri = AICc_tmp;
cri0=AICc; //update with the best model
}
if(cri < min_cri) min_cri=cri;//Get the minimal value of the selected model or criteria, which corresponds to the best model.
float p0, pc; // p0 and pc are the percentage of symbols in the non-cluster and cluster regions; they are used to determined if the cluster is under a hot (p0<pc) or cold (p0>pc) spot.
getp0pc_MK(pos_start, pos_end, cs, ce, p0, pc, symbol_n, symbol_cn);
CandidateModels tmp_CM(AIC_weight, cri, pos_start, pos_end, cs, ce, p0, pc,InL_tmp);// each model contains all parameters
vec_AllModels.push_back(tmp_CM); // all models
/*
if (cs==170 and ce==289){
cout<<"Cluster region 170 to 289."<<endl;
cout<<"Position Start: "<<pos_start<<"\tEnd: "<<pos_end<<"\tCluster start: "<<cs<<"\tend: "<<ce<<"\tp0: "<<p0<<"\tpc: "<<pc<<"\tvariant#Total\t"<<symbol_n<<"\tVariant#InCluster:\t"<<symbol_cn<<"\tInL0:\t"<<InL0<<"\tInL_tmp:\t"<<InL_tmp<<"\tInL_tmp_cluster:\t"<<InL_tmp_cluster<<"\tInL_tmp_noncluster:\t"<<InL_tmp_noncluster<<endl;