~ubuntu-branches/ubuntu/quantal/clustalo/quantal

« back to all changes in this revision

Viewing changes to src/squid/alignio.c

  • Committer: Package Import Robot
  • Author(s): Olivier Sallou
  • Date: 2011-12-14 11:21:56 UTC
  • Revision ID: package-import@ubuntu.com-20111214112156-y3chwm0t4yn2nevm
Tags: upstream-1.0.3
ImportĀ upstreamĀ versionĀ 1.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************
 
2
 * SQUID - a library of functions for biological sequence analysis
 
3
 * Copyright (C) 1992-2002 Washington University School of Medicine
 
4
 * 
 
5
 *     This source code is freely distributed under the terms of the
 
6
 *     GNU General Public License. See the files COPYRIGHT and LICENSE
 
7
 *     for details.
 
8
 *****************************************************************/
 
9
 
 
10
/* alignio.c
 
11
 * SRE, Mon Jul 12 11:57:37 1993
 
12
 * RCS $Id: alignio.c 217 2011-03-19 10:27:10Z andreas $ (Original squid RCS Id: alignio.c,v 1.11 2002/10/09 14:26:09 eddy Exp)
 
13
 * 
 
14
 * Input/output of sequence alignments.
 
15
 */
 
16
 
 
17
#include <stdio.h>
 
18
#include <stdlib.h>
 
19
#include <string.h>
 
20
#include <ctype.h>
 
21
#include "squid.h"
 
22
#include "sre_random.h"
 
23
 
 
24
/* Function: AllocAlignment()
 
25
 * 
 
26
 * Purpose:  Allocate space for an alignment, given the number
 
27
 *           of sequences and the alignment length in columns.
 
28
 *           
 
29
 * Args:     nseq     - number of sequences
 
30
 *           alen     - width of alignment
 
31
 *           ret_aseq - RETURN: alignment itself
 
32
 *           ainfo    - RETURN: other info associated with alignment
 
33
 *           
 
34
 * Return:   (void)
 
35
 *           aseq, ainfo free'd by caller: FreeAlignment(aseq, &ainfo).
 
36
 *           note that ainfo itself is alloc'ed in caller, usually
 
37
 *           just by a "AINFO ainfo" definition.
 
38
 */
 
39
void
 
40
AllocAlignment(int nseq, int alen, char ***ret_aseq, AINFO *ainfo)
 
41
{
 
42
  char **aseq;
 
43
  int idx;
 
44
 
 
45
  InitAinfo(ainfo);
 
46
 
 
47
  aseq = (char **) MallocOrDie (sizeof(char *) * nseq);
 
48
  for (idx = 0; idx < nseq; idx++)
 
49
    aseq[idx] = (char *) MallocOrDie (sizeof(char) * (alen+1));
 
50
 
 
51
  ainfo->alen  = alen;
 
52
  ainfo->nseq  = nseq;
 
53
 
 
54
  ainfo->wgt   = (float *) MallocOrDie (sizeof(float) * nseq);
 
55
  FSet(ainfo->wgt, nseq, 1.0);
 
56
 
 
57
  ainfo->sqinfo = (SQINFO *) MallocOrDie (sizeof(SQINFO) * nseq);
 
58
  for (idx = 0; idx < nseq; idx++)
 
59
    ainfo->sqinfo[idx].flags = 0;
 
60
 
 
61
  *ret_aseq = aseq;
 
62
}
 
63
 
 
64
 
 
65
/* Function: InitAinfo()
 
66
 * Date:     SRE, Tue Jan 19 10:16:02 1999 [St. Louis]
 
67
 *
 
68
 * Purpose:  Initialize the fields in ainfo structure to
 
69
 *           default (null) values. Does nothing with 
 
70
 *           fields that are dependent on nseq or alen.
 
71
 *
 
72
 * Args:     ainfo  - optional info structure for an alignment
 
73
 *
 
74
 * Returns:  (void). ainfo is modified.
 
75
 */
 
76
void
 
77
InitAinfo(AINFO *ainfo)
 
78
{
 
79
  ainfo->name  = NULL;
 
80
  ainfo->desc  = NULL;
 
81
  ainfo->cs    = NULL;
 
82
  ainfo->rf    = NULL;
 
83
  ainfo->acc   = NULL;
 
84
  ainfo->au    = NULL;
 
85
  ainfo->flags = 0;
 
86
 
 
87
  ainfo->tc1  = ainfo->tc2 = 0.0;
 
88
  ainfo->nc1  = ainfo->nc2 = 0.0;
 
89
  ainfo->ga1  = ainfo->ga2 = 0.0;
 
90
}
 
91
 
 
92
 
 
93
/* Function: FreeAlignment()
 
94
 * 
 
95
 * Purpose:  Free the space allocated to alignment, names, and optional
 
96
 *           information. 
 
97
 *           
 
98
 * Args:     aseqs - sequence alignment
 
99
 *           ainfo - associated alignment data.
 
100
 */                  
 
101
void
 
102
FreeAlignment(char **aseqs, AINFO *ainfo)
 
103
{
 
104
  int i;
 
105
 
 
106
  for (i = 0; i < ainfo->nseq; i++)
 
107
    {
 
108
      if (ainfo->sqinfo[i].flags & SQINFO_SS) free(ainfo->sqinfo[i].ss);
 
109
      if (ainfo->sqinfo[i].flags & SQINFO_SA) free(ainfo->sqinfo[i].sa);
 
110
    }
 
111
  if (ainfo->cs   != NULL) free(ainfo->cs);
 
112
  if (ainfo->rf   != NULL) free(ainfo->rf);
 
113
  if (ainfo->name != NULL) free(ainfo->name);
 
114
  if (ainfo->desc != NULL) free(ainfo->desc);
 
115
  if (ainfo->acc  != NULL) free(ainfo->acc);
 
116
  if (ainfo->au   != NULL) free(ainfo->au);
 
117
 
 
118
  free(ainfo->sqinfo);
 
119
  free(ainfo->wgt);
 
120
  Free2DArray((void **) aseqs, ainfo->nseq);
 
121
}
 
122
 
 
123
 
 
124
 
 
125
/* Function: SAMizeAlignment()
 
126
 * Date:     SRE, Tue Jun 30 09:49:40 1998 [St. Louis]
 
127
 *
 
128
 * Purpose:  Make a "best effort" attempt to convert an alignment
 
129
 *           to SAM gap format: - in delete col, . in insert col.
 
130
 *           Only works if alignment adheres to SAM's upper/lower
 
131
 *           case convention, which is true for instance of old
 
132
 *           HMMER alignments.
 
133
 *
 
134
 * Args:     aseq  - alignment to convert
 
135
 *           nseq  - number of seqs in alignment
 
136
 *           alen  - length of alignment
 
137
 *
 
138
 * Returns:  (void)
 
139
 */
 
140
void
 
141
SAMizeAlignment(char **aseq, int nseq, int alen)
 
142
{
 
143
  int col;                      /* counter for aligned columns */
 
144
  int i;                        /* counter for seqs */
 
145
  int sawlower, sawupper, sawgap;
 
146
  char gapchar;
 
147
 
 
148
  for (col = 0; col < alen; col++)
 
149
    {
 
150
      sawlower = sawupper = sawgap = 0;
 
151
                                /* pass 1: do we see only upper or lower? */
 
152
      for (i = 0; i < nseq; i++)
 
153
        {
 
154
          if (isgap(aseq[i][col]))         { sawgap   = 1; continue; }
 
155
          if (isupper((int) aseq[i][col])) { sawupper = 1; continue; }
 
156
          if (islower((int) aseq[i][col]))   sawlower = 1;
 
157
        }
 
158
                                /* select gap character for column */
 
159
      gapchar = '-';            /* default */
 
160
      if (sawlower && ! sawupper) gapchar = '.';
 
161
 
 
162
                                /* pass 2: set gap char */
 
163
      for (i = 0; i < nseq; i++)
 
164
        if (isgap(aseq[i][col])) aseq[i][col] = gapchar;
 
165
    }
 
166
}
 
167
 
 
168
 
 
169
/* Function: SAMizeAlignmentByGapFrac()
 
170
 * Date:     SRE, Tue Jun 30 10:58:38 1998 [St. Louis]
 
171
 *
 
172
 * Purpose:  Convert an alignment to SAM's gap and case
 
173
 *           conventions, using gap fraction in a column
 
174
 *           to choose match versus insert columns. In match columns,
 
175
 *           residues are upper case and gaps are '-'.
 
176
 *           In insert columns, residues are lower case and
 
177
 *           gaps are '.'
 
178
 *
 
179
 * Args:     aseq   - aligned sequences
 
180
 *           nseq   - number of sequences
 
181
 *           alen   - length of alignment
 
182
 *           maxgap - if more gaps than this fraction, column is insert.
 
183
 *
 
184
 * Returns:  (void) Characters in aseq may be altered.
 
185
 */
 
186
void
 
187
SAMizeAlignmentByGapFrac(char **aseq, int nseq, int alen, float maxgap)
 
188
{
 
189
  int apos;                     /* counter over columns */
 
190
  int idx;                      /* counter over sequences */
 
191
  int ngap;                     /* number of gaps seen */
 
192
 
 
193
  for (apos = 0; apos < alen; apos++)
 
194
    {
 
195
                                /* count gaps */
 
196
      ngap = 0;
 
197
      for (idx = 0; idx < nseq; idx++)
 
198
        if (isgap(aseq[idx][apos])) ngap++;
 
199
      
 
200
                                /* convert to SAM conventions */
 
201
      if ((float) ngap / (float) nseq > maxgap)
 
202
        {                       /* insert column */
 
203
          for (idx = 0; idx < nseq; idx++)
 
204
            if (isgap(aseq[idx][apos])) aseq[idx][apos] = '.';
 
205
            else aseq[idx][apos] = (char) tolower((int) aseq[idx][apos]);
 
206
        }
 
207
      else                      
 
208
        {                       /* match column */
 
209
          for (idx = 0; idx < nseq; idx++)
 
210
            if (isgap(aseq[idx][apos])) aseq[idx][apos] = '-';
 
211
            else aseq[idx][apos] = (char) toupper((int) aseq[idx][apos]);
 
212
        }
 
213
    }
 
214
}
 
215
 
 
216
 
 
217
 
 
218
 
 
219
/* Function: MakeAlignedString()
 
220
 * 
 
221
 * Purpose:  Given a raw string of some type (secondary structure, say),
 
222
 *           align it to a given aseq by putting gaps wherever the
 
223
 *           aseq has gaps. 
 
224
 *           
 
225
 * Args:     aseq:  template for alignment
 
226
 *           alen:  length of aseq
 
227
 *           ss:    raw string to align to aseq
 
228
 *           ret_s: RETURN: aligned ss
 
229
 *           
 
230
 * Return:   1 on success, 0 on failure (and squid_errno is set.)
 
231
 *           ret_ss is malloc'ed here and must be free'd by caller.
 
232
 */
 
233
int
 
234
MakeAlignedString(char *aseq, int alen, char *ss, char **ret_s)
 
235
{
 
236
  char *new; 
 
237
  int   apos, rpos;
 
238
 
 
239
  new = (char *) MallocOrDie ((alen+1) * sizeof(char));
 
240
  for (apos = rpos = 0; apos < alen; apos++)
 
241
    if (! isgap(aseq[apos]))
 
242
      {
 
243
        new[apos] = ss[rpos];
 
244
        rpos++;
 
245
      }
 
246
    else
 
247
      new[apos] = '.';
 
248
  new[apos] = '\0';
 
249
 
 
250
  if (rpos != strlen(ss))
 
251
    { squid_errno = SQERR_PARAMETER; free(new); return 0; }
 
252
  *ret_s = new;
 
253
  return 1;
 
254
}
 
255
 
 
256
 
 
257
/* Function: MakeDealignedString()
 
258
 * 
 
259
 * Purpose:  Given an aligned string of some type (either sequence or 
 
260
 *           secondary structure, for instance), dealign it relative
 
261
 *           to a given aseq. Return a ptr to the new string.
 
262
 *           
 
263
 * Args:     aseq  : template alignment 
 
264
 *           alen  : length of aseq
 
265
 *           ss:   : string to make dealigned copy of; same length as aseq
 
266
 *           ret_s : RETURN: dealigned copy of ss
 
267
 *           
 
268
 * Return:   1 on success, 0 on failure (and squid_errno is set)
 
269
 *           ret_s is alloc'ed here and must be freed by caller
 
270
 */
 
271
int
 
272
MakeDealignedString(char *aseq, int alen, char *ss, char **ret_s)
 
273
{
 
274
  char *new; 
 
275
  int   apos, rpos;
 
276
 
 
277
  new = (char *) MallocOrDie ((alen+1) * sizeof(char));
 
278
  for (apos = rpos = 0; apos < alen; apos++)
 
279
    if (! isgap(aseq[apos]))
 
280
      {
 
281
        new[rpos] = ss[apos];
 
282
        rpos++;
 
283
      }
 
284
  new[rpos] = '\0';
 
285
  if (alen != strlen(ss))
 
286
    { squid_errno = SQERR_PARAMETER; free(new); return 0; }
 
287
  *ret_s = new;
 
288
  return 1;
 
289
}
 
290
 
 
291
 
 
292
/* Function: DealignedLength()
 
293
 *
 
294
 * Purpose:  Count the number of non-gap symbols in seq.
 
295
 *           (i.e. find the length of the unaligned sequence)
 
296
 * 
 
297
 * Args:     aseq - aligned sequence to count symbols in, \0 terminated
 
298
 * 
 
299
 * Return:   raw length of seq.
 
300
 */
 
301
int
 
302
DealignedLength(char *aseq)
 
303
{
 
304
  int rlen; 
 
305
  for (rlen = 0; *aseq; aseq++)
 
306
    if (! isgap(*aseq)) rlen++;
 
307
  return rlen;
 
308
}
 
309
 
 
310
 
 
311
/* Function: WritePairwiseAlignment()
 
312
 * 
 
313
 * Purpose:  Write a nice formatted pairwise alignment out,
 
314
 *           with a BLAST-style middle line showing identities
 
315
 *           as themselves (single letter) and conservative
 
316
 *           changes as '+'.
 
317
 *           
 
318
 * Args:     ofp          - open fp to write to (stdout, perhaps)
 
319
 *           aseq1, aseq2 - alignments to write (not necessarily 
 
320
 *                          flushed right with gaps)
 
321
 *           name1, name2 - names of sequences
 
322
 *           spos1, spos2 - starting position in each (raw) sequence
 
323
 *           pam          - PAM matrix; positive values define
 
324
 *                          conservative changes
 
325
 *           indent       - how many extra spaces to print on left
 
326
 *           
 
327
 * Return:  1 on success, 0 on failure
 
328
 */
 
329
int
 
330
WritePairwiseAlignment(FILE *ofp,
 
331
                       char *aseq1, char *name1, int spos1,
 
332
                       char *aseq2, char *name2, int spos2,
 
333
                       int **pam, int indent)
 
334
{
 
335
  char sname1[11];              /* shortened name               */
 
336
  char sname2[11];             
 
337
  int  still_going;             /* True if writing another block */
 
338
  char buf1[61];                /* buffer for writing seq1; CPL+1*/
 
339
  char bufmid[61];              /* buffer for writing consensus  */
 
340
  char buf2[61];
 
341
  char *s1, *s2;                /* ptrs into each sequence          */
 
342
  int  count1, count2;          /* number of symbols we're writing  */
 
343
  int  rpos1, rpos2;            /* position in raw seqs             */
 
344
  int  rawcount1, rawcount2;    /* number of nongap symbols written */
 
345
  int  apos;
 
346
 
 
347
  strncpy(sname1, name1, 10);
 
348
  sname1[10] = '\0';
 
349
  strtok(sname1, WHITESPACE);
 
350
 
 
351
  strncpy(sname2, name2, 10);
 
352
  sname2[10] = '\0';
 
353
  strtok(sname2, WHITESPACE);
 
354
 
 
355
  s1 = aseq1; 
 
356
  s2 = aseq2;
 
357
  rpos1 = spos1;
 
358
  rpos2 = spos2;
 
359
 
 
360
  still_going = TRUE;
 
361
  while (still_going)
 
362
    {
 
363
      still_going = FALSE;
 
364
      
 
365
                                /* get next line's worth from both */
 
366
      strncpy(buf1, s1, 60); buf1[60] = '\0';
 
367
      strncpy(buf2, s2, 60); buf2[60] = '\0';
 
368
      count1 = strlen(buf1);
 
369
      count2 = strlen(buf2);
 
370
 
 
371
                                /* is there still more to go? */
 
372
      if ((count1 == 60 && s1[60] != '\0') ||
 
373
          (count2 == 60 && s2[60] != '\0'))
 
374
        still_going = TRUE;
 
375
 
 
376
                                /* shift seq ptrs by a line */
 
377
      s1 += count1;
 
378
      s2 += count2;
 
379
 
 
380
                                /* assemble the consensus line */
 
381
      for (apos = 0; apos < count1 && apos < count2; apos++)
 
382
        {
 
383
          if (!isgap(buf1[apos]) && !isgap(buf2[apos]))
 
384
            {
 
385
              if (buf1[apos] == buf2[apos])
 
386
                bufmid[apos] = buf1[apos];
 
387
              else if (pam[buf1[apos] - 'A'][buf2[apos] - 'A'] > 0)
 
388
                bufmid[apos] = '+';
 
389
              else
 
390
                bufmid[apos] = ' ';
 
391
            }
 
392
          else
 
393
            bufmid[apos] = ' ';
 
394
        }
 
395
      bufmid[apos] = '\0';
 
396
 
 
397
      rawcount1 = 0;
 
398
      for (apos = 0; apos < count1; apos++)
 
399
        if (!isgap(buf1[apos])) rawcount1++;
 
400
      
 
401
      rawcount2 = 0;
 
402
      for (apos = 0; apos < count2; apos++)
 
403
        if (!isgap(buf2[apos])) rawcount2++;
 
404
 
 
405
      (void) fprintf(ofp, "%*s%-10.10s %5d %s %5d\n", indent, "", 
 
406
                     sname1, rpos1, buf1, rpos1 + rawcount1 -1);
 
407
      (void) fprintf(ofp, "%*s                 %s\n", indent, "",
 
408
                     bufmid);
 
409
      (void) fprintf(ofp, "%*s%-10.10s %5d %s %5d\n", indent, "", 
 
410
                     sname2, rpos2, buf2, rpos2 + rawcount2 -1);
 
411
      (void) fprintf(ofp, "\n");
 
412
 
 
413
      rpos1 += rawcount1;
 
414
      rpos2 += rawcount2;
 
415
    }
 
416
 
 
417
  return 1;
 
418
}
 
419
 
 
420
 
 
421
/* Function: MingapAlignment()
 
422
 * 
 
423
 * Purpose:  Remove all-gap columns from a multiple sequence alignment
 
424
 *           and its associated data. The alignment is assumed to be
 
425
 *           flushed (all aseqs the same length).
 
426
 */
 
427
int
 
428
MingapAlignment(char **aseqs, AINFO *ainfo)
 
429
{
 
430
  int apos;                     /* position in original alignment */
 
431
  int mpos;                     /* position in new alignment      */
 
432
  int idx;
 
433
 
 
434
  /* We overwrite aseqs, using its allocated memory.
 
435
   */
 
436
  for (apos = 0, mpos = 0; aseqs[0][apos] != '\0'; apos++)
 
437
    {
 
438
                                /* check for all-gap in column */
 
439
      for (idx = 0; idx < ainfo->nseq; idx++)
 
440
        if (! isgap(aseqs[idx][apos]))
 
441
          break;
 
442
      if (idx == ainfo->nseq) continue;
 
443
        
 
444
                                /* shift alignment and ainfo */
 
445
      if (mpos != apos)
 
446
        {
 
447
          for (idx = 0; idx < ainfo->nseq; idx++)
 
448
            aseqs[idx][mpos] = aseqs[idx][apos];
 
449
          
 
450
          if (ainfo->cs != NULL) ainfo->cs[mpos] = ainfo->cs[apos];
 
451
          if (ainfo->rf != NULL) ainfo->rf[mpos] = ainfo->rf[apos];
 
452
        }
 
453
      mpos++;
 
454
    }
 
455
                                /* null terminate everything */
 
456
  for (idx = 0; idx < ainfo->nseq; idx++)
 
457
    aseqs[idx][mpos] = '\0';
 
458
  ainfo->alen = mpos;   /* set new length */
 
459
  if (ainfo->cs != NULL) ainfo->cs[mpos] = '\0';
 
460
  if (ainfo->rf != NULL) ainfo->rf[mpos] = '\0';
 
461
  return 1;
 
462
}
 
463
 
 
464
 
 
465
 
 
466
/* Function: RandomAlignment()
 
467
 * 
 
468
 * Purpose:  Create a random alignment from raw sequences.
 
469
 * 
 
470
 *           Ideally, we would like to sample an alignment from the
 
471
 *           space of possible alignments according to its probability,
 
472
 *           given a prior probability distribution for alignments.
 
473
 *           I don't see how to describe such a distribution, let alone
 
474
 *           sample it.
 
475
 *           
 
476
 *           This is a rough approximation that tries to capture some
 
477
 *           desired properties. We assume the alignment is generated
 
478
 *           by a simple HMM composed of match and insert states.
 
479
 *           Given parameters (pop, pex) for the probability of opening
 
480
 *           and extending an insertion, we can find the expected number
 
481
 *           of match states, M, in the underlying model for each sequence.
 
482
 *           We use an average M taken over all the sequences (this is
 
483
 *           an approximation. The expectation of M given all the sequence
 
484
 *           lengths is a nasty-looking summation.)
 
485
 *           
 
486
 *           M = len / ( 1 + pop ( 1 + 1/ (1-pex) ) ) 
 
487
 *           
 
488
 *           Then, we assign positions in each raw sequence onto the M match
 
489
 *           states and M+1 insert states of this "HMM", by rolling random
 
490
 *           numbers and inserting the (rlen-M) inserted positions randomly
 
491
 *           into the insert slots, taking into account the relative probability
 
492
 *           of open vs. extend.
 
493
 *           
 
494
 *           The resulting alignment has two desired properties: insertions
 
495
 *           tend to follow the HMM-like exponential distribution, and
 
496
 *           the "sparseness" of the alignment is controllable through
 
497
 *           pop and pex.
 
498
 *           
 
499
 * Args:     rseqs     - raw sequences to "align", 0..nseq-1
 
500
 *           sqinfo    - array of 0..nseq-1 info structures for the sequences
 
501
 *           nseq      - number of sequences   
 
502
 *           pop       - probability to open insertion (0<pop<1)
 
503
 *           pex       - probability to extend insertion (0<pex<1)
 
504
 *           ret_aseqs - RETURN: alignment (flushed)
 
505
 *           ainfo     - fill in: alignment info
 
506
 * 
 
507
 * Return:   1 on success, 0 on failure. Sets squid_errno to indicate cause
 
508
 *           of failure.
 
509
 */                      
 
510
int
 
511
RandomAlignment(char **rseqs, SQINFO *sqinfo, int nseq, float pop, float pex,
 
512
                char ***ret_aseqs, AINFO *ainfo)
 
513
{
 
514
  char **aseqs;                 /* RETURN: alignment   */
 
515
  int    alen;                  /* length of alignment */
 
516
  int   *rlen;                  /* lengths of each raw sequence */
 
517
  int    M;                     /* length of "model"   */
 
518
  int  **ins;                   /* insertion counts, 0..nseq-1 by 0..M */
 
519
  int   *master_ins;            /* max insertion counts, 0..M */
 
520
  int    apos, rpos, idx;
 
521
  int    statepos;
 
522
  int    count;
 
523
  int    minlen;
 
524
 
 
525
  /* calculate expected length of model, M
 
526
   */
 
527
  rlen = (int *) MallocOrDie (sizeof(int) * nseq);
 
528
  M = 0;
 
529
  minlen = 9999999;
 
530
  for (idx = 0; idx < nseq; idx++)
 
531
    {
 
532
      rlen[idx] = strlen(rseqs[idx]);
 
533
      M += rlen[idx];
 
534
      minlen = (rlen[idx] < minlen) ? rlen[idx] : minlen;
 
535
    }
 
536
  M = (int) ((float) M / (1.0 + pop * (1.0 + 1.0 / (1.0 - pex))));
 
537
  M /= nseq;
 
538
  if (M > minlen) M = minlen;
 
539
 
 
540
  /* make arrays that count insertions in M+1 possible insert states
 
541
   */
 
542
  ins = (int **) MallocOrDie (sizeof(int *) * nseq);
 
543
  master_ins = (int *) MallocOrDie (sizeof(int) * (M+1));
 
544
  for (idx = 0; idx < nseq; idx++)
 
545
    {
 
546
      ins[idx] = (int *) MallocOrDie (sizeof(int) * (M+1));
 
547
      for (rpos = 0; rpos <= M; rpos++)
 
548
        ins[idx][rpos] = 0;
 
549
    }
 
550
                                /* normalize */
 
551
  pop = pop / (pop+pex);
 
552
  pex = 1.0 - pop;
 
553
                                /* make insertions for individual sequences */
 
554
  for (idx = 0; idx < nseq; idx++)
 
555
    {
 
556
      apos = -1;
 
557
      for (rpos = 0; rpos < rlen[idx]-M; rpos++)
 
558
        {
 
559
          if (sre_random() < pop || apos == -1) /* open insertion */
 
560
            apos = CHOOSE(M+1);        /* choose 0..M */
 
561
          ins[idx][apos]++;
 
562
        }
 
563
    }
 
564
                                /* calculate master_ins, max inserts */
 
565
  alen = M;
 
566
  for (apos = 0; apos <= M; apos++)
 
567
    {
 
568
      master_ins[apos] = 0;
 
569
      for (idx = 0; idx < nseq; idx++)
 
570
        if (ins[idx][apos] > master_ins[apos])
 
571
          master_ins[apos] = ins[idx][apos];
 
572
      alen += master_ins[apos];
 
573
    }
 
574
 
 
575
 
 
576
  /* Now, construct alignment
 
577
   */
 
578
  aseqs = (char **) MallocOrDie (sizeof (char *) * nseq);
 
579
  for (idx = 0; idx < nseq; idx++)
 
580
    aseqs[idx] = (char *) MallocOrDie (sizeof(char) * (alen+1));
 
581
  for (idx = 0; idx < nseq; idx++)
 
582
    {
 
583
      apos = rpos = 0;
 
584
 
 
585
      for (statepos = 0; statepos <= M; statepos++)
 
586
        {
 
587
          for (count = 0; count < ins[idx][statepos]; count++)
 
588
            aseqs[idx][apos++] = rseqs[idx][rpos++];
 
589
          for (; count < master_ins[statepos]; count++)
 
590
            aseqs[idx][apos++] = ' ';
 
591
 
 
592
          if (statepos != M)
 
593
            aseqs[idx][apos++] = rseqs[idx][rpos++];
 
594
        }
 
595
      aseqs[idx][alen] = '\0';
 
596
    }
 
597
  ainfo->flags = 0;
 
598
  ainfo->alen  = alen; 
 
599
  ainfo->nseq  = nseq;
 
600
  ainfo->sqinfo = (SQINFO *) MallocOrDie (sizeof(SQINFO) * nseq);
 
601
  for (idx = 0; idx < nseq; idx++)
 
602
    SeqinfoCopy(&(ainfo->sqinfo[idx]), &(sqinfo[idx]));
 
603
 
 
604
  free(rlen);
 
605
  free(master_ins);
 
606
  Free2DArray((void **) ins, nseq);
 
607
  *ret_aseqs = aseqs;
 
608
  return 1;
 
609
}
 
610
 
 
611
/* Function: AlignmentHomogenousGapsym()
 
612
 * Date:     SRE, Sun Mar 19 19:37:12 2000 [wren, St. Louis]
 
613
 *
 
614
 * Purpose:  Sometimes we've got to convert alignments to 
 
615
 *           a lowest common denominator, and we need
 
616
 *           a single specific gap character -- for example,
 
617
 *           PSI-BLAST blastpgp -B takes a very simplistic
 
618
 *           alignment input format which appears to only
 
619
 *           allow '-' as a gap symbol.
 
620
 *           
 
621
 *           Anything matching the isgap() macro is
 
622
 *           converted.
 
623
 *
 
624
 * Args:     aseq   - aligned character strings, [0..nseq-1][0..alen-1]
 
625
 *           nseq   - number of aligned strings
 
626
 *           alen   - length of alignment
 
627
 *           gapsym - character to use for gaps.         
 
628
 *
 
629
 * Returns:  void ("never fails")
 
630
 */
 
631
void
 
632
AlignmentHomogenousGapsym(char **aseq, int nseq, int alen, char gapsym)
 
633
{
 
634
  int i, apos;
 
635
 
 
636
  for (i = 0; i < nseq; i++)
 
637
    for (apos = 0; apos < alen; apos++)
 
638
      if (isgap(aseq[i][apos])) aseq[i][apos] = gapsym;
 
639
}