void single_variant_flips(struct fragment* Flist, struct SNPfrags* snpfrag, struct BLOCK* clist, int k, int* slist, char* HAP1) { int t = 0, i = 0, f = 0; float newscore = clist[k].bestSCORE; for (t = 0; t < clist[k].phased; t++) { if (HAP1[slist[t]] == '1') HAP1[slist[t]] = '0'; else if (HAP1[slist[t]] == '0') HAP1[slist[t]] = '1'; for (i = 0; i < snpfrag[slist[t]].frags; i++) { f = snpfrag[slist[t]].flist[i]; newscore -= Flist[f].currscore; update_fragscore(Flist, f, HAP1); newscore += Flist[f].currscore; } if (newscore > clist[k].bestSCORE) // newMEC is not better than original MEC so we need to revert back to oldMEC for each fragment { if (HAP1[slist[t]] == '1') HAP1[slist[t]] = '0'; else if (HAP1[slist[t]] == '0') HAP1[slist[t]] = '1'; for (i = 0; i < snpfrag[slist[t]].frags; i++) { f = snpfrag[slist[t]].flist[i]; update_fragscore(Flist, f, HAP1); } } else { clist[k].SCORE = newscore; clist[k].bestSCORE = newscore; } } }
float cut_MEC(struct SNPfrags* snpfrag,struct fragment* Flist,char* hap,int* slist,int N,struct BLOCK* component) { int i=0,j=0,f=0; float newscore=0; for (i=0;i<N;i++) { // flip the alleles at sites for which parent == 0 (one shore of cut) if (snpfrag[slist[i]].parent == 0 && hap[slist[i]] == '1') hap[slist[i]] = '0'; else if (snpfrag[slist[i]].parent == 0 && hap[slist[i]] == '0') hap[slist[i]] = '1'; } for (j=0;j<component->frags;j++) { f = component->flist[j]; update_fragscore(Flist,f,hap); newscore += Flist[f].currscore; } // revert back for (i=0;i<N;i++) { if (snpfrag[slist[i]].parent == 0 && hap[slist[i]] == '1') hap[slist[i]] = '0'; else if (snpfrag[slist[i]].parent == 0 && hap[slist[i]] == '0') hap[slist[i]] = '1'; } for (j=0;j<component->frags;j++) { f = component->flist[j]; update_fragscore(Flist,f,hap); } return newscore; }
int evaluate_cut_component(struct fragment* Flist, struct SNPfrags* snpfrag, struct BLOCK* clist, int k, int* slist, char* HAP1) { if (clist[k].iters_since_improvement > CONVERGE) { return 1; // return 1 only if converged } int i = 0, j = 0, t = 0, count1, count2; float cutvalue; /* i=0;for (j=clist[k].offset;j<clist[k].offset+clist[k].length;j++) { if (snpfrag[clist[k].offset].component == snpfrag[j].component) { slist[i] = j; i++; } }*/ // slist is copied from clist[k].slist for (t = 0; t < clist[k].phased; t++) slist[t] = clist[k].slist[t]; // new way to determine slist // not required but we do it to avoid errors clist[k].SCORE = 0; for (i = 0; i < clist[k].frags; i++) { update_fragscore(Flist, clist[k].flist[i], HAP1); clist[k].SCORE += Flist[clist[k].flist[i]].currscore; } clist[k].bestSCORE = clist[k].SCORE; // evaluate the impact of flipping of each SNP on MEC score, loop needed to improve MEC score single_variant_flips(Flist, snpfrag, clist, k, slist, HAP1); clist[k].SCORE = 0; for (i = 0; i < clist[k].frags; i++) { update_fragscore(Flist, clist[k].flist[i], HAP1); clist[k].SCORE += Flist[clist[k].flist[i]].currscore; } clist[k].bestSCORE = clist[k].SCORE; cutvalue = 10; if (clist[k].SCORE > 0) cutvalue = compute_goodcut(snpfrag, HAP1, slist, &clist[k], Flist); // flip the subset of columns in slist with positive value //if (cutvalue <= 3 || MINCUTALGO == 2) { //getchar(); for (i = 0; i < clist[k].phased; i++) { if (slist[i] > 0 && HAP1[slist[i]] == '1') HAP1[slist[i]] = '0'; else if (slist[i] > 0 && HAP1[slist[i]] == '0') HAP1[slist[i]] = '1'; } clist[k].bestSCORE = clist[k].SCORE; clist[k].SCORE = 0; for (i = 0; i < clist[k].frags; i++) { update_fragscore(Flist, clist[k].flist[i], HAP1); clist[k].SCORE += Flist[clist[k].flist[i]].currscore; } count1 = 0; count2 = 0; // counts for size of each side of cut for (j = 0; j < clist[k].phased; j++){ if (slist[j] > 0){ count1++; }else{ count2++; } } if (clist[k].iters_since_improvement <= CONVERGE && clist[k].SCORE >= clist[k].bestSCORE){// revert to old haplotype // flip back the SNPs in the cut clist[k].iters_since_improvement++; for (i = 0; i < clist[k].phased; i++) { if (slist[i] > 0 && HAP1[slist[i]] == '1') HAP1[slist[i]] = '0'; else if (slist[i] > 0 && HAP1[slist[i]] == '0') HAP1[slist[i]] = '1'; } clist[k].SCORE = 0; for (i = 0; i < clist[k].frags; i++) { update_fragscore(Flist, clist[k].flist[i], HAP1); clist[k].SCORE += Flist[clist[k].flist[i]].currscore; } }else{ clist[k].bestSCORE = clist[k].SCORE; // update current haplotype clist[k].iters_since_improvement = 0; } if (VERBOSE && clist[k].SCORE > 0) fprintf_time(stdout, "component %d offset %d length %d phased %d LL %0.1f cutvalue %f bestLL %0.2f\n", k, clist[k].offset, clist[k].length, clist[k].phased, -1*clist[k].SCORE, cutvalue, -1*clist[k].bestSCORE); // return 0 to specify that this component hasn't converged. return 0; }
int maxcut_haplotyping(char* fragmentfile,char* variantfile,int snps,char* outputfile,int maxiter_hapcut) { // IMP NOTE: all SNPs start from 1 instead of 0 and all offsets are 1+ fprintf(stderr,"calling MAXCUT based haplotype assembly algorithm\n"); int fragments=0,iter=0,components=0; int i=0,j=0,k=0,t=0,component; int* slist; int flag =0; float bestscore_mec = 0,calls=0, miscalls=0,ll = 0; char buffer[MAXBUF]; /****************************** READ FRAGMENT MATRIX*************************************************/ struct fragment* Flist; FILE* ff = fopen(fragmentfile,"r"); if (ff == NULL) { fprintf(stderr,"couldn't open fragment file %s\n",fragmentfile); exit(0);} fragments =0; while ( fgets(buffer,MAXBUF,ff) != NULL) fragments++; fclose(ff); Flist = (struct fragment*)malloc(sizeof(struct fragment)*fragments); flag = read_fragment_matrix(fragmentfile,Flist,fragments); if (flag < 0) { fprintf(stderr,"unable to read fragment matrix file %s \n",fragmentfile); return -1; } if (VCFformat ==0) snps = count_variants(variantfile); else snps = count_variants_vcf(variantfile); if (snps < 0) { fprintf(stderr,"unable to read variant file %s \n",variantfile); return -1; } fprintf(stderr,"processed fragment file and variant file: fragments %d variants %d\n",fragments,snps); /****************************** READ FRAGMENT MATRIX*************************************************/ struct SNPfrags* snpfrag = (struct SNPfrags*)malloc(sizeof(struct SNPfrags)*snps); update_snpfrags(Flist,fragments,snpfrag,snps,&components); double MEM_ALLOC = 0; for (i=0;i<snps;i++) MEM_ALLOC += snpfrag[i].edges*0.002; MEM_ALLOC *= 0.016; fprintf(stderr,"%f MB memory needs to be allocated for graph edges\n",MEM_ALLOC); // size of struct edge is 16/1000 bytes if (MEM_ALLOC >= MAX_MEMORY) { fprintf(stderr,"\nstoring the HAPCUT graph structure requires more than %d MB of memory:\n 1. increase the maximum memory available using option \"--maxmem 12000\" where the memory is specified in megabytes OR \n 2. run the program with the options \"--longreads 1 \" to reduce the number of edges stored \n\n",MAX_MEMORY); return -1; } // too much memory allocated here for fosmid based data... for (i=0;i<snps;i++) snpfrag[i].elist = (struct edge*)malloc(sizeof(struct edge)*snpfrag[i].edges); for (i=0;i<snps;i++) snpfrag[i].telist = (struct edge*)malloc(sizeof(struct edge)*snpfrag[i].edges); if (FOSMIDS ==0) add_edges(Flist,fragments,snpfrag,snps,&components); else if (FOSMIDS >=1) add_edges_fosmids(Flist,fragments,snpfrag,snps,&components); // this considers only components with at least two nodes fprintf(stderr,"fragments %d snps %d component(blocks) %d\n",fragments,snps,components); struct BLOCK* clist = (struct BLOCK*)malloc(sizeof(struct BLOCK)*components); component =0; generate_clist_structure(Flist,fragments,snpfrag,snps,components,clist); /*****************************************************************************************************/ char* HAP1 = (char*)malloc(snps+1); char* besthap_mec = (char*)malloc(snps+1); char* HAP2 = (char*)malloc(snps+1); struct tm *ts1; char buf[80]; time_t now; slist = (int*)malloc(sizeof(int)*snps); char fn[1000]; if (VCFformat ==0) read_variantfile(variantfile,snpfrag,snps); else read_vcffile(variantfile,snpfrag,snps); /*****************************************************************************************************/ if (RANDOM_START ==1) { fprintf(stdout,"starting from a completely random solution SOLUTION \n"); for (i=0;i<snps;i++) { if (snpfrag[i].frags ==0) { HAP1[i] = '-'; HAP2[i] = '-'; } else { if (drand48() < 0.5) { HAP1[i] = '0'; HAP2[i] = '1'; } else {HAP1[i] = '1'; HAP2[i] = '0'; } } } } for (i=0;i<snps;i++) { besthap_mec[i] = HAP1[i]; } // for each block, we maintain best haplotype solution under MFR criterion // compute the component-wise score for 'initHAP' haplotype miscalls=0;bestscore_mec=0; for (k=0;k<components;k++) { clist[k].MEC =0; clist[k].bestMEC =0; clist[k].calls =0; clist[k].LL = 0; for (i=0;i<clist[k].frags;i++) { update_fragscore(Flist,clist[k].flist[i],HAP1); clist[k].MEC += Flist[clist[k].flist[i]].currscore; clist[k].LL += Flist[clist[k].flist[i]].ll; clist[k].calls += Flist[clist[k].flist[i]].calls; } clist[k].bestMEC = clist[k].MEC; bestscore_mec += clist[k].bestMEC; miscalls += clist[k].MEC; clist[k].bestLL = clist[k].LL; } // annealing_haplotyping(Flist,fragments,snpfrag,snps,maxiter,HAP1,HAP2,clist,components,slist); return 1; // annealing_haplotyping_full(Flist,fragments,snpfrag,snps,maxiter,HAP1,HAP2,0); return 1; /************************** RUN THE MAX_CUT ALGORITHM ITERATIVELY TO IMPROVE MEC SCORE*********************************/ for (iter=0;iter<maxiter_hapcut;iter++) { mecscore(Flist,fragments,HAP1,&ll,&calls,&miscalls); time(&now); ts1 = localtime(&now); strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", ts1); fprintf(stdout,"iter %d current haplotype MEC %f calls %d LL %f %s \n",iter,miscalls,(int)calls,ll,buf); fprintf(stderr,"iter %d current haplotype MEC %f calls %d LL %f %s \n",iter,miscalls,(int)calls,ll,buf); if ((iter%10==0 && iter > 0)) { // new code added april 7 2012 for (k=0;k<components;k++) find_bestvariant_segment(Flist,fragments,snpfrag,clist,k,HAP1,HAP2); sprintf(fn,"%s",outputfile); // newfile for every update to score.... //sprintf(fn,"%s.%f",outputfile,miscalls); // newfile for every update to score.... fprintf(stdout,"OUTPUTTING HAPLOTYPE ASSEMBLY TO FILE %s\n",fn); fprintf(stderr,"OUTPUTTING HAPLOTYPE ASSEMBLY TO FILE %s\n",fn); //if (VCFformat ==1) print_haplotypes_vcf(clist,components,HAP1,Flist,fragments,snpfrag,snps,fn); print_hapfile(clist,components,HAP1,Flist,fragments,snpfrag,variantfile,miscalls,fn); // do this only if some option is specified if (PRINT_FRAGMENT_SCORES ==1) { print_fragmentmatrix_MEC(Flist,fragments,HAP1,outputfile); //print_matrix(clist,components,HAP1,Flist,outputfile); } } for (k=0;k<components;k++) // COMPUTATION OF TREE FOR EACH COMPONENT { //if ((k*50)%components ==0) fprintf(stderr,"#"); if (iter ==0) fprintf(stdout,"\n component %d length %d phased %d %d...%d \n",k,clist[k].length,clist[k].phased,clist[k].offset,clist[k].lastvar); // call function for each component only if MEC > 0 april 17 2012 if (clist[k].MEC > 0) evaluate_cut_component(Flist,snpfrag,clist,k,slist,HAP1,iter); } for (i=0;i<snps;i++) { // commented out on april 6 4pm 2012 //if (HAP1[i] == '0') HAP2[i] = '1'; else if (HAP1[i] == '1') HAP2[i] = '0'; else HAP2[i] = HAP1[i]; } } /************************** RUN THE MAX_CUT ALGORITHM ITERATIVELY TO IMPROVE MEC SCORE*********************************/ // annealing_haplotyping_full(Flist,fragments,snpfrag,snps,maxiter+100,HAP1,HAP2,0); return 1; return 1; }
int maxcut_haplotyping(char* fragmentfile, char* variantfile, char* outputfile) { // IMP NOTE: all SNPs start from 1 instead of 0 and all offsets are 1+ fprintf_time(stderr, "Calling Max-Likelihood-Cut based haplotype assembly algorithm\n"); int snps = 0; int fragments = 0, iter = 0, components = 0; int i = 0, k = 0; int* slist; int flag = 0; float bestscore = 0, miscalls = 0; int hic_iter=0; struct SNPfrags* snpfrag = NULL; struct BLOCK* clist; char* HAP1; float HIC_LL_SCORE = -80; float OLD_HIC_LL_SCORE = -80; int converged_count=0, split_count, new_components, component; int new_fragments = 0; struct fragment* new_Flist; // READ FRAGMENT MATRIX fragments = get_num_fragments(fragmentfile); struct fragment* Flist; Flist = (struct fragment*) malloc(sizeof (struct fragment)* fragments); flag = read_fragment_matrix(fragmentfile, Flist, fragments); if (MAX_IS != -1){ // we are going to filter out some insert sizes new_fragments = 0; new_Flist = (struct fragment*) malloc(sizeof (struct fragment)* fragments); for(i = 0; i < fragments; i++){ if (Flist[i].isize < MAX_IS) new_Flist[new_fragments++] = Flist[i]; } Flist = new_Flist; fragments = new_fragments; } if (flag < 0) { fprintf_time(stderr, "unable to read fragment matrix file %s \n", fragmentfile); return -1; } //ADD EDGES BETWEEN SNPS snps = count_variants_vcf(variantfile); if (snps < 0) { fprintf_time(stderr, "unable to read variant file %s \n", variantfile); return -1; } snpfrag = (struct SNPfrags*) malloc(sizeof (struct SNPfrags)*snps); update_snpfrags(Flist, fragments, snpfrag, snps, &components); detect_long_reads(Flist,fragments); // 10/25/2014, edges are only added between adjacent nodes in each fragment and used for determining connected components... for (i = 0; i < snps; i++) snpfrag[i].elist = (struct edge*) malloc(sizeof (struct edge)*(snpfrag[i].edges+1)); if (LONG_READS ==0){ add_edges(Flist,fragments,snpfrag,snps,&components); }else if (LONG_READS >=1){ add_edges_fosmids(Flist,fragments,snpfrag,snps,&components); } for (i = 0; i < snps; i++) snpfrag[i].telist = (struct edge*) malloc(sizeof (struct edge)*(snpfrag[i].edges+1)); // this considers only components with at least two nodes fprintf_time(stderr, "fragments %d snps %d component(blocks) %d\n", fragments, snps, components); // BUILD COMPONENT LIST clist = (struct BLOCK*) malloc(sizeof (struct BLOCK)*components); generate_clist_structure(Flist, fragments, snpfrag, snps, components, clist); // READ VCF FILE read_vcffile(variantfile, snpfrag, snps); // INITIALIZE RANDOM HAPLOTYPES HAP1 = (char*) malloc(snps + 1); for (i = 0; i < snps; i++) { if (snpfrag[i].frags == 0 || (SNVS_BEFORE_INDELS && (strlen(snpfrag[i].allele0) != 1 || strlen(snpfrag[i].allele1) != 1))) { HAP1[i] = '-'; } else if (drand48() < 0.5) { HAP1[i] = '0'; } else { HAP1[i] = '1'; } } // for each block, we maintain best haplotype solution under MFR criterion // compute the component-wise score for 'initHAP' haplotype miscalls = 0; bestscore = 0; for (k = 0; k < components; k++) { clist[k].SCORE = 0; clist[k].bestSCORE = 0; for (i = 0; i < clist[k].frags; i++) { update_fragscore(Flist, clist[k].flist[i], HAP1); clist[k].SCORE += Flist[clist[k].flist[i]].currscore; } clist[k].bestSCORE = clist[k].SCORE; bestscore += clist[k].bestSCORE; miscalls += clist[k].SCORE; } fprintf_time(stderr, "processed fragment file and variant file: fragments %d variants %d\n", fragments, snps); int MAXIS = -1; if (HIC){ // determine the probability of an h-trans interaction for read for (i=0; i<fragments;i++){ Flist[i].htrans_prob = -80; if (Flist[i].isize > MAXIS) MAXIS = Flist[i].isize; } HTRANS_MAXBINS = MAXIS/HTRANS_BINSIZE + 1; }else{ HTRANS_MAXBINS = 0; } // read in file with estimated probabilities of Hi-C h-trans interactions with distance if (strcmp(HTRANS_DATA_INFILE, "None") != 0){ int num_bins = count_htrans_bins(HTRANS_DATA_INFILE); float* htrans_probs = (float*) malloc(sizeof(float) * num_bins); read_htrans_file(HTRANS_DATA_INFILE, htrans_probs, num_bins); for (i=0; i<fragments;i++){ Flist[i].htrans_prob = log10(htrans_probs[Flist[i].isize / HTRANS_BINSIZE]); } free(htrans_probs); } slist = (int*) malloc(sizeof (int)*snps); OLD_HIC_LL_SCORE = bestscore; for (hic_iter = 0; hic_iter < MAX_HIC_EM_ITER; hic_iter++){ if (VERBOSE) fprintf_time(stdout, "HIC ITER %d\n", hic_iter); for (k = 0; k < components; k++){ clist[k].iters_since_improvement = 0; } for (i=0; i<snps; i++){ snpfrag[i].post_hap = 0; } // RUN THE MAX_CUT ALGORITHM ITERATIVELY TO IMPROVE LIKELIHOOD for (iter = 0; iter < MAXITER; iter++) { if (VERBOSE) fprintf_time(stdout, "PHASING ITER %d\n", iter); converged_count = 0; for (k = 0; k < components; k++){ if(VERBOSE && iter == 0) fprintf_time(stdout, "component %d length %d phased %d %d...%d\n", k, clist[k].length, clist[k].phased, clist[k].offset, clist[k].lastvar); if (clist[k].SCORE > 0) converged_count += evaluate_cut_component(Flist, snpfrag, clist, k, slist, HAP1); else converged_count++; } if (converged_count == components) { //fprintf(stdout, "Haplotype assembly terminated early because no improvement seen in blocks after %d iterations\n", CONVERGE); break; } } // H-TRANS ESTIMATION FOR HIC if (MAX_HIC_EM_ITER > 1){ // Possibly break if we're done improving HIC_LL_SCORE = 0; for (k = 0; k < components; k++){ HIC_LL_SCORE += clist[k].bestSCORE; } if (HIC_LL_SCORE >= OLD_HIC_LL_SCORE){ break; } OLD_HIC_LL_SCORE = HIC_LL_SCORE; likelihood_pruning(snps, Flist, snpfrag, HAP1, 0); // prune for only very high confidence SNPs // estimate the h-trans probabilities for the next round estimate_htrans_probs(Flist, fragments, HAP1, snpfrag); } } // BLOCK SPLITTING new_components = components; if (SPLIT_BLOCKS){ split_count = 0; for (k=0; k<components; k++){ // attempt to split block split_count += split_block(HAP1, clist, k, Flist, snpfrag, &new_components); } if (split_count > 0){ // regenerate clist if necessary free(clist); clist = (struct BLOCK*) malloc(sizeof (struct BLOCK)*new_components); generate_clist_structure(Flist, fragments, snpfrag, snps, new_components, clist); } components = new_components; }else if(ERROR_ANALYSIS_MODE && !HIC){ for (k=0; k<components; k++){ // run split_block but don't actually split, just get posterior probabilities split_block(HAP1, clist, k, Flist, snpfrag, &new_components); } } // PRUNE SNPS if (!SKIP_PRUNE){ discrete_pruning(snps, fragments, Flist, snpfrag, HAP1); likelihood_pruning(snps, Flist, snpfrag, HAP1, CALL_HOMOZYGOUS); } // PRINT OUTPUT FILE fprintf_time(stderr, "OUTPUTTING PRUNED HAPLOTYPE ASSEMBLY TO FILE %s\n", outputfile); print_hapfile(clist, components, HAP1, Flist, fragments, snpfrag, variantfile, miscalls, outputfile); char assignfile[4096]; sprintf(assignfile,"%s.fragments",outputfile); if (OUTPUT_RH_ASSIGNMENTS ==1) fragment_assignments(Flist,fragments,snpfrag,HAP1,assignfile); // added 03/10/2018 to output read-haplotype assignments char outvcffile[4096]; sprintf(outvcffile,"%s.phased.VCF",outputfile); if (OUTPUT_VCF ==1) { fprintf_time(stderr, "OUTPUTTING PHASED VCF TO FILE %s\n", outvcffile); output_vcf(variantfile,snpfrag,snps,HAP1,Flist,fragments,outvcffile,0); } // FREE UP MEMORY for (i = 0; i < snps; i++) free(snpfrag[i].elist); for (i = 0; i < snps; i++) free(snpfrag[i].telist); component = 0; for (i = 0; i < snps; i++) { free(snpfrag[i].flist); free(snpfrag[i].alist); free(snpfrag[i].jlist); free(snpfrag[i].klist); if (snpfrag[i].component == i && snpfrag[i].csize > 1) // root node of component { free(clist[component].slist); component++; } } for (i = 0; i < components; i++) free(clist[i].flist); free(snpfrag); free(clist); free(Flist); return 0; }