1 /*
2 Copyright 2007, 2008 Daniel Zerbino (zerbino@ebi.ac.uk)
3
4 This file is part of Velvet.
5
6 Velvet is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 Velvet is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Velvet; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
20 */
21 #include <stdlib.h>
22 #include <stdio.h>
23 #ifdef _OPENMP
24 #include <omp.h>
25 #endif
26
27 #include "globals.h"
28 #include "allocArray.h"
29 #include "graph.h"
30 #include "recycleBin.h"
31 #include "passageMarker.h"
32 #include "tightString.h"
33 #include "utility.h"
34
35 typedef struct passage_st PassageMarker;
36
37 struct passage_st {
38 struct node_st *node;
39 PassageMarkerI nextInNode;
40 PassageMarkerI previousInNode;
41 PassageMarkerI twinMarker;
42 PassageMarkerI nextInSequence;
43 IDnum start;
44 IDnum finishOffset;
45 IDnum sequenceID;
46 boolean status;
47 } ATTRIBUTE_PACKED;
48
49 static AllocArray *markerMemory = NULL;
50 DECLARE_FAST_ACCESSORS (PM, PassageMarker, markerMemory)
51
52 static RecycleBin *listMemory = NULL;
53 static const int LISTBLOCKSIZE = 10000;
54
allocatePassageMarker()55 PassageMarkerI allocatePassageMarker()
56 {
57 if (markerMemory == NULL){
58 char passagemarker[50] = "PassageMarker";
59 markerMemory =
60 newAllocArray (sizeof(PassageMarker), passagemarker);
61 }
62
63 return allocArrayAllocate (markerMemory);
64 }
65
deallocatePassageMarker(PassageMarkerI marker)66 static void deallocatePassageMarker(PassageMarkerI marker)
67 {
68 allocArrayFree(markerMemory, marker);
69 }
70
allocatePassageMarkerList()71 PassageMarkerList *allocatePassageMarkerList()
72 {
73 if (listMemory == NULL)
74 listMemory =
75 newRecycleBin(sizeof(PassageMarkerList),
76 LISTBLOCKSIZE);
77
78 return (PassageMarkerList *) allocatePointer(listMemory);
79 }
80
deallocatePassageMarkerList(PassageMarkerList * marker)81 void deallocatePassageMarkerList(PassageMarkerList * marker)
82 {
83 deallocatePointer(listMemory, marker);
84 }
85
setNextInSequence(PassageMarkerI previous,PassageMarkerI next)86 void setNextInSequence(PassageMarkerI previous, PassageMarkerI next)
87 {
88 if (previous == NULL_IDX)
89 return;
90
91 PM_FI2P (previous)->nextInSequence = next;
92 }
93
extractPassageMarker(PassageMarkerI marker)94 void extractPassageMarker(PassageMarkerI marker)
95 {
96 PassageMarker *twin;
97 PassageMarker *markerVal;
98
99 if (marker == NULL_IDX)
100 return;
101
102 markerVal = PM_FI2P (marker);
103 if (markerVal->node == NULL_IDX)
104 return;
105
106 if (markerVal->previousInNode == marker)
107 setMarker(markerVal->node, markerVal->nextInNode);
108 else
109 setNextInNode(markerVal->previousInNode, markerVal->nextInNode);
110
111 markerVal->previousInNode = NULL_IDX;
112 markerVal->nextInNode = NULL_IDX;
113 markerVal->node = NULL_IDX;
114
115 twin = PM_FI2P (markerVal->twinMarker);
116 twin->nextInNode = NULL_IDX;
117 twin->previousInNode = NULL_IDX;
118 twin->node = NULL_IDX;
119 }
120
destroyPassageMarker(PassageMarkerI marker)121 void destroyPassageMarker(PassageMarkerI marker)
122 {
123 PassageMarker *markerVal;
124 PassageMarker *twinVal;
125 PassageMarkerI twin;
126
127 if (marker == NULL_IDX)
128 return;
129
130 markerVal = PM_FI2P (marker);
131 twin = markerVal->twinMarker;
132 extractPassageMarker(marker);
133
134 if (markerVal->nextInSequence != NULL_IDX
135 && PM_FI2P (PM_FI2P (markerVal->nextInSequence)->twinMarker)->nextInSequence == twin)
136 PM_FI2P (PM_FI2P (markerVal->nextInSequence)->twinMarker)->nextInSequence = NULL_IDX;
137
138 twinVal = PM_FI2P (twin);
139 if (twinVal->nextInSequence != NULL_IDX
140 && PM_FI2P (PM_FI2P (twinVal->nextInSequence)->twinMarker)->nextInSequence == marker)
141 PM_FI2P (PM_FI2P (twinVal->nextInSequence)->twinMarker)->nextInSequence = NULL_IDX;
142
143 deallocatePassageMarker(twin);
144 deallocatePassageMarker(marker);
145
146 //velvetLog("Done destroying passage marker\n");
147 }
148
destroyAllPassageMarkers()149 void destroyAllPassageMarkers()
150 {
151 if (markerMemory != NULL)
152 destroyAllocArray(markerMemory);
153 if (listMemory != NULL)
154 destroyRecycleBin(listMemory);
155 }
156
157
setPreviousInSequence(PassageMarkerI previous,PassageMarkerI next)158 void setPreviousInSequence(PassageMarkerI previous, PassageMarkerI next)
159 {
160 if (next == NULL_IDX)
161 return;
162 else if (previous == NULL_IDX)
163 PM_FI2P (PM_FI2P (next)->twinMarker)->nextInSequence = NULL_IDX;
164 else
165 PM_FI2P (PM_FI2P (next)->twinMarker)->nextInSequence = PM_FI2P (previous)->twinMarker;
166 }
167
disconnectNextPassageMarker(PassageMarkerI marker,Graph * graph)168 void disconnectNextPassageMarker(PassageMarkerI marker, Graph * graph)
169 {
170 PassageMarkerI middle = getNextInSequence(marker);
171 PassageMarkerI next = getNextInSequence(middle);
172
173 setPreviousInSequence(marker, next);
174 concatenatePassageMarkers(marker, middle);
175 setNextInSequence(middle, NULL_IDX);
176 setPreviousInSequence(NULL_IDX, middle);
177 }
178
deleteNextPassageMarker(PassageMarkerI marker,Graph * graph)179 void deleteNextPassageMarker(PassageMarkerI marker, Graph * graph)
180 {
181 PassageMarkerI middle = getNextInSequence(marker);
182 PassageMarkerI next = getNextInSequence(middle);
183
184 setPreviousInSequence(marker, next);
185 setNextInSequence(marker, next);
186 setNextInSequence(middle, NULL_IDX);
187 setPreviousInSequence(NULL_IDX, middle);
188 }
189
getNextInNode(PassageMarkerI marker)190 PassageMarkerI getNextInNode(PassageMarkerI marker)
191 {
192 if (marker == NULL_IDX)
193 return NULL_IDX;
194
195 return PM_FI2P (marker)->nextInNode;
196 }
197
setNextInNode(PassageMarkerI marker,PassageMarkerI next)198 void setNextInNode(PassageMarkerI marker, PassageMarkerI next)
199 {
200 PassageMarker *markerVal;
201
202 // DEBUG
203 if (next == marker || next == getTwinMarker(marker))
204 abort();
205
206 if (marker == NULL_IDX)
207 return;
208
209 markerVal = PM_FI2P (marker);
210 if (next == NULL_IDX) {
211 markerVal->nextInNode = NULL_IDX;
212 PM_FI2P (markerVal->twinMarker)->nextInNode = NULL_IDX;
213 } else {
214 PassageMarker *nextVal;
215
216 if (markerVal->twinMarker == NULL_IDX) {
217 velvetLog("Dead marker in node %li %li\n",
218 (long) getNodeID(getNode(marker)),
219 (long) getPassageMarkerSequenceID(marker));
220 abort();
221 }
222 nextVal = PM_FI2P (next);
223 markerVal->nextInNode = next;
224 PM_FI2P (markerVal->twinMarker)->nextInNode = nextVal->twinMarker;
225 nextVal->previousInNode = marker;
226 PM_FI2P (nextVal->twinMarker)->previousInNode = markerVal->twinMarker;
227 }
228 }
229
setTopOfTheNode(PassageMarkerI marker)230 void setTopOfTheNode(PassageMarkerI marker)
231 {
232 if (marker == NULL_IDX)
233 return;
234
235 PM_FI2P (marker)->previousInNode = marker;
236 }
237
getNextInSequence(PassageMarkerI marker)238 PassageMarkerI getNextInSequence(PassageMarkerI marker)
239 {
240 if (marker != NULL_IDX)
241 {
242 PassageMarker *markerVal;
243
244 markerVal = PM_FI2P (marker);
245 if (markerVal->nextInSequence == NULL_IDX)
246 return NULL_IDX;
247 return markerVal->nextInSequence;
248 }
249 return NULL_IDX;
250 }
251
getPreviousInSequence(PassageMarkerI marker)252 PassageMarkerI getPreviousInSequence(PassageMarkerI marker)
253 {
254 PassageMarker *twinVal;
255
256 if (marker == NULL_IDX)
257 return NULL_IDX;
258
259 twinVal = PM_FI2P (PM_FI2P (marker)->twinMarker);
260 if (twinVal->nextInSequence == NULL_IDX)
261 return NULL_IDX;
262
263 return PM_FI2P (twinVal->nextInSequence)->twinMarker;
264 }
265
266 void
connectPassageMarkers(PassageMarkerI previous,PassageMarkerI next,Graph * graph)267 connectPassageMarkers(PassageMarkerI previous, PassageMarkerI next,
268 Graph * graph)
269 {
270 if (previous != NULL_IDX)
271 setNextInSequence(previous, next);
272
273 if (next != NULL_IDX)
274 setPreviousInSequence(previous, next);
275 }
276
readPassageMarker(PassageMarkerI marker)277 char *readPassageMarker(PassageMarkerI marker)
278 {
279 PassageMarker *markerVal;
280 char *s = mallocOrExit(100, char);
281
282 if (marker == NULL_IDX)
283 return s;
284
285 markerVal = PM_FI2P (marker);
286 sprintf(s, "MARKER %ld (%lld -> %lld):", (long) markerVal->sequenceID,
287 (long long) markerVal->start, (long long) getPassageMarkerFinish(marker));
288
289 if (getPreviousInSequence(marker) == NULL_IDX)
290 sprintf(s, "%s START -> %ld", s,
291 (long) getNodeID(getNode(marker)));
292 else
293 sprintf(s, "%s %ld -> %ld", s,
294 (long) getNodeID(getNode(getPreviousInSequence(marker))),
295 (long) getNodeID(getNode(marker)));
296
297 if (getNextInSequence(marker) == NULL_IDX)
298 sprintf(s, "%s -> FINISH", s);
299 else
300 sprintf(s, "%s -> %ld ", s,
301 (long) getNodeID(getNode(getNextInSequence(marker))));
302
303 return s;
304 }
305
addPassageMarker(IDnum sequenceID,Coordinate start,Node * node)306 PassageMarkerI addPassageMarker(IDnum sequenceID, Coordinate start,
307 Node * node)
308 {
309 PassageMarkerI marker = allocatePassageMarker();
310 PassageMarkerI twinMarker = allocatePassageMarker();
311 PassageMarker *markerVal;
312 PassageMarker *twinVal;
313
314 markerVal = PM_FI2P (marker);
315 twinVal = PM_FI2P (twinMarker);
316
317 markerVal->sequenceID = sequenceID;
318 markerVal->start = start;
319 markerVal->node = node;
320 markerVal->nextInSequence = NULL_IDX;
321 markerVal->finishOffset = 0;
322 markerVal->twinMarker = twinMarker;
323 markerVal->status = false;
324
325 twinVal->sequenceID = -sequenceID;
326 twinVal->start = start + getNodeLength(node);
327 twinVal->node = getTwinNode(node);
328 twinVal->nextInSequence = NULL_IDX;
329 twinVal->finishOffset = 0;
330 twinVal->twinMarker = marker;
331 twinVal->status = false;
332
333 setNextInNode(marker, getMarker(node));
334 setMarker(node, marker);
335
336 return marker;
337 }
338
copyPassageMarkerList(PassageMarkerList * list)339 PassageMarkerList *copyPassageMarkerList(PassageMarkerList * list)
340 {
341 PassageMarkerList *copy;
342 PassageMarkerList *result = NULL;
343 PassageMarkerList *pointer;
344
345 if (list == NULL)
346 return NULL;
347
348 for (pointer = list; pointer != NULL; pointer = pointer->next) {
349 copy = allocatePassageMarkerList();
350 copy->marker = pointer->marker;
351 copy->next = result;
352 result = copy;
353 }
354
355 return result;
356 }
357
incrementFinishOffset(PassageMarkerI marker,Coordinate offset)358 void incrementFinishOffset(PassageMarkerI marker, Coordinate offset)
359 {
360 PM_FI2P (marker)->finishOffset += offset;
361 }
362
incrementStartOffset(PassageMarkerI marker,Coordinate offset)363 void incrementStartOffset(PassageMarkerI marker, Coordinate offset)
364 {
365 PM_FI2P (PM_FI2P (marker)->twinMarker)->finishOffset += offset;
366 }
367
getFinishOffset(PassageMarkerI marker)368 Coordinate getFinishOffset(PassageMarkerI marker)
369 {
370 return PM_FI2P (marker)->finishOffset;
371 }
372
setFinishOffset(PassageMarkerI marker,Coordinate offset)373 void setFinishOffset(PassageMarkerI marker, Coordinate offset)
374 {
375 PM_FI2P (marker)->finishOffset = offset;
376 }
377
getStartOffset(PassageMarkerI marker)378 Coordinate getStartOffset(PassageMarkerI marker)
379 {
380 return PM_FI2P (PM_FI2P (marker)->twinMarker)->finishOffset;
381 }
382
setStartOffset(PassageMarkerI marker,Coordinate offset)383 void setStartOffset(PassageMarkerI marker, Coordinate offset)
384 {
385 PM_FI2P (PM_FI2P (marker)->twinMarker)->finishOffset = offset;
386 }
387
transposePassageMarker(PassageMarkerI marker,Node * node)388 void transposePassageMarker(PassageMarkerI marker, Node * node)
389 {
390 PassageMarker *markerVal;
391 PassageMarker *twinMarkerVal;
392
393 markerVal = PM_FI2P (marker);
394 twinMarkerVal = PM_FI2P (markerVal->twinMarker);
395 insertPassageMarker(marker, node);
396 markerVal->node = node;
397 insertPassageMarker(markerVal->twinMarker, getTwinNode(node));
398 twinMarkerVal->node = getTwinNode(node);
399 }
400
getTwinMarker(PassageMarkerI marker)401 PassageMarkerI getTwinMarker(PassageMarkerI marker)
402 {
403 return PM_FI2P (marker)->twinMarker;
404 }
405
getPassageMarkerSequenceID(PassageMarkerI marker)406 IDnum getPassageMarkerSequenceID(PassageMarkerI marker)
407 {
408 return PM_FI2P (marker)->sequenceID;
409 }
410
getAbsolutePassMarkerSeqID(PassageMarkerI marker)411 IDnum getAbsolutePassMarkerSeqID(PassageMarkerI marker)
412 {
413 IDnum ID = PM_FI2P (marker)->sequenceID;
414
415 if (ID > 0)
416 return ID;
417 else
418 return -ID;
419 }
420
getNode(PassageMarkerI marker)421 Node *getNode(PassageMarkerI marker)
422 {
423 if (marker == NULL_IDX)
424 return NULL;
425
426 return PM_FI2P (marker)->node;
427 }
428
concatenatePassageMarkers(PassageMarkerI marker,PassageMarkerI next)429 void concatenatePassageMarkers(PassageMarkerI marker,
430 PassageMarkerI next)
431 {
432 PassageMarker *markerVal;
433 PassageMarker *nextVal;
434
435 if (marker == NULL_IDX || next == NULL_IDX)
436 return;
437
438 markerVal = PM_FI2P (marker);
439 nextVal = PM_FI2P (next);
440
441 markerVal->finishOffset = nextVal->finishOffset;
442 PM_FI2P (markerVal->twinMarker)->start = PM_FI2P (nextVal->twinMarker)->start;
443 markerVal->nextInSequence = nextVal->nextInSequence;
444 }
445
getPassageMarkerStatus(PassageMarkerI marker)446 boolean getPassageMarkerStatus(PassageMarkerI marker)
447 {
448 return PM_FI2P (marker)->status;
449 }
450
setPassageMarkerStatus(PassageMarkerI marker,boolean status)451 void setPassageMarkerStatus(PassageMarkerI marker, boolean status)
452 {
453 PassageMarker *markerVal = PM_FI2P (marker);
454
455 markerVal->status = status;
456 PM_FI2P (markerVal->twinMarker)->status = status;
457 }
458
isDestinationToMarker(PassageMarkerI marker,Node * node)459 boolean isDestinationToMarker(PassageMarkerI marker, Node * node)
460 {
461 PassageMarker *markerVal = PM_FI2P (marker);
462
463 if (markerVal->nextInSequence == NULL_IDX)
464 return false;
465
466 return PM_FI2P (markerVal->nextInSequence)->node == node;
467 }
468
isTerminal(PassageMarkerI marker)469 boolean isTerminal(PassageMarkerI marker)
470 {
471 PassageMarker *markerVal;
472
473 if (marker == NULL_IDX)
474 return false;
475
476 markerVal = PM_FI2P (marker);
477 return markerVal->nextInSequence == NULL_IDX;
478 }
479
isInitial(PassageMarkerI marker)480 boolean isInitial(PassageMarkerI marker)
481 {
482 PassageMarker *markerVal;
483
484 if (marker == NULL_IDX)
485 return false;
486
487 markerVal = PM_FI2P (marker);
488 if (markerVal->twinMarker == NULL_IDX) {
489 velvetLog("Unpaired marker seq %ld start %lld node %ld\n",
490 (long) markerVal->sequenceID, (long long) markerVal->start,
491 (long) getNodeID(markerVal->node));
492 velvetLog("SNAFU\n");
493 abort();
494 }
495
496 return PM_FI2P (markerVal->twinMarker)->nextInSequence == NULL_IDX;
497 }
498
getPassageMarkerStart(PassageMarkerI marker)499 Coordinate getPassageMarkerStart(PassageMarkerI marker)
500 {
501 return PM_FI2P (marker)->start;
502 }
503
setPassageMarkerStart(PassageMarkerI marker,Coordinate start)504 void setPassageMarkerStart(PassageMarkerI marker, Coordinate start)
505 {
506 PM_FI2P (marker)->start = start;
507 }
508
getPassageMarkerFinish(PassageMarkerI marker)509 Coordinate getPassageMarkerFinish(PassageMarkerI marker)
510 {
511 PassageMarker *twinMarkerVal;
512
513 twinMarkerVal = PM_FI2P (PM_FI2P (marker)->twinMarker);
514 if (twinMarkerVal->start == -10)
515 return -10;
516
517 return twinMarkerVal->start;
518 }
519
setPassageMarkerFinish(PassageMarkerI marker,Coordinate finish)520 void setPassageMarkerFinish(PassageMarkerI marker, Coordinate finish)
521 {
522 PassageMarker *twinMarkerVal;
523
524 twinMarkerVal = PM_FI2P (PM_FI2P (marker)->twinMarker);
525 if (finish == -10)
526 twinMarkerVal->start = -10;
527
528 twinMarkerVal->start = finish;
529 }
530
getPassageMarkerLength(PassageMarkerI marker)531 Coordinate getPassageMarkerLength(PassageMarkerI marker)
532 {
533 PassageMarker *markerVal;
534 PassageMarker *twinMarkerVal;
535
536 markerVal = PM_FI2P (marker);
537 twinMarkerVal = PM_FI2P (markerVal->twinMarker);
538 if (markerVal->start == -10 || twinMarkerVal->start == -10)
539 return 0;
540
541 else if (markerVal->sequenceID > 0)
542 return twinMarkerVal->start - markerVal->start;
543 else
544 return markerVal->start - twinMarkerVal->start;
545 }
546
passageMarkerDirection(PassageMarkerI marker)547 int passageMarkerDirection(PassageMarkerI marker)
548 {
549 if (PM_FI2P (marker)->sequenceID > 0)
550 return 1;
551 else
552 return -1;
553 }
554
addUncertainPassageMarker(IDnum sequenceID,Node * node)555 PassageMarkerI addUncertainPassageMarker(IDnum sequenceID, Node * node)
556 {
557 PassageMarkerI marker = allocatePassageMarker();
558 PassageMarkerI twinMarker = allocatePassageMarker();
559 PassageMarker *markerVal = PM_FI2P (marker);
560 PassageMarker *twinMarkerVal = PM_FI2P (twinMarker);
561
562 markerVal->sequenceID = sequenceID;
563 markerVal->start = -10;
564 markerVal->node = node;
565 markerVal->nextInSequence = NULL_IDX;
566 markerVal->finishOffset = 0;
567 markerVal->twinMarker = twinMarker;
568 markerVal->status = false;
569
570 twinMarkerVal->sequenceID = -sequenceID;
571 twinMarkerVal->start = -10;
572 if (node == NULL)
573 twinMarkerVal->node = NULL;
574 else
575 twinMarkerVal->node = getTwinNode(node);
576 twinMarkerVal->nextInSequence = NULL_IDX;
577 twinMarkerVal->finishOffset = 0;
578 twinMarkerVal->twinMarker = marker;
579 twinMarkerVal->status = false;
580
581 if (node != NULL) {
582 setNextInNode(marker, getMarker(node));
583 setMarker(node, marker);
584 }
585
586 return marker;
587 }
588
newPassageMarkerList(PassageMarkerI marker,PassageMarkerList * next)589 PassageMarkerList *newPassageMarkerList(PassageMarkerI marker,
590 PassageMarkerList * next)
591 {
592 PassageMarkerList *list = allocatePassageMarkerList();
593 list->marker = marker;
594 list->next = next;
595 return list;
596 }
597
newPassageMarker(IDnum seqID,Coordinate start,Coordinate finish,Coordinate startOffset,Coordinate finishOffset)598 PassageMarkerI newPassageMarker(IDnum seqID, Coordinate start,
599 Coordinate finish, Coordinate startOffset,
600 Coordinate finishOffset)
601 {
602 PassageMarkerI marker;
603 PassageMarkerI twinMarker;
604 PassageMarker *markerVal;
605 PassageMarker *twinMarkerVal;
606
607 #ifdef _OPENMP
608 #pragma omp critical
609 {
610 #endif
611 marker = allocatePassageMarker();
612 twinMarker = allocatePassageMarker();
613 #ifdef _OPENMP
614 }
615 #endif
616 markerVal = PM_FI2P (marker);
617 twinMarkerVal = PM_FI2P (twinMarker);
618
619 // velvetLog("Values %d\t%d\t%d\t%d\t%d\n", seqID, start, finish, startOffset, finishOffset);
620
621 markerVal->sequenceID = seqID;
622 markerVal->node = NULL;
623 markerVal->nextInSequence = NULL_IDX;
624 markerVal->twinMarker = twinMarker;
625 markerVal->nextInNode = NULL_IDX;
626 markerVal->status = false;
627
628 twinMarkerVal->sequenceID = -seqID;
629 twinMarkerVal->node = NULL;
630 twinMarkerVal->nextInSequence = NULL_IDX;
631 twinMarkerVal->twinMarker = marker;
632 twinMarkerVal->nextInNode = NULL_IDX;
633 twinMarkerVal->status = false;
634
635 setPassageMarkerStart(marker, start);
636 setPassageMarkerFinish(marker, finish);
637 setStartOffset(marker, startOffset);
638 setFinishOffset(marker, finishOffset);
639
640 if (getPassageMarkerLength(marker) < 0) {
641 velvetLog("Negative marker %ld %lld %lld %lld\n",
642 (long) getPassageMarkerSequenceID(marker),
643 (long long) getPassageMarkerStart(marker),
644 (long long) getPassageMarkerFinish(marker),
645 (long long) getPassageMarkerLength(marker));
646 abort();
647 }
648
649 return marker;
650 }
651
exportMarker(FILE * outfile,PassageMarkerI marker,TightString * sequences,int WORDLENGTH)652 void exportMarker(FILE * outfile, PassageMarkerI marker,
653 TightString * sequences, int WORDLENGTH)
654 {
655 PassageMarker *markerVal = PM_FI2P (marker);
656 PassageMarkerI current;
657
658 if (markerVal->sequenceID > 0) {
659 if (!isInitial(marker)) {
660 return;
661 }
662 current = marker;
663 } else {
664 if (!isTerminal(marker)) {
665 return;
666 }
667 current = markerVal->twinMarker;
668 }
669
670 velvetFprintf(outfile, "SEQ\t%li\n", (long) PM_FI2P (current)->sequenceID);
671 for (; current != NULL_IDX; current = PM_FI2P (current)->nextInSequence) {
672 velvetFprintf(outfile, "%ld\t%lld\t%lld\t%lld\t%lld",
673 (long) getNodeID(PM_FI2P (current)->node), (long long) getStartOffset(current),
674 (long long) getPassageMarkerStart(current),
675 (long long) getPassageMarkerFinish(current),
676 (long long) getFinishOffset(current));
677 velvetFprintf(outfile, "\n");
678 }
679 }
680