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