Esempio n. 1
0
// we know that this "node" is a node that has either no neighbors on
// one side -or- connects to a chain of nodes that leads to a single node.
static bool
check_for_tip_removal(SeqGraph *graph, SeqNode *node, bool moving_right, bool singlecopy_tip, unsigned length)
{
    // XXX: performance optimization not correctness, right?
#ifdef VELOUR_TBB
    if (atomic_isNodeDead<SeqNode>(node)) { return false; }
#else
    if (isNodeDead<SeqNode>(node)) { return false; }
#endif

	length += node->sequence.get_length() - g__FULLKMER_LENGTH + 1;
    singlecopy_tip &= (isNodeWeight_None(node) || isNodeWeight_AllSingleCopy(node));

	if (length >= TIP_REMOVAL_LENGTH && !singlecopy_tip) { // FIXME? singlecopy_tip might be incorrect as didn't consider forward arc???
		return false;  // can't remove a tip that is too long
	}

	// find out if this tip can be extended.  This has two conditions:
	// CONDITION 1: there is a single neighbor in the extension direction
#ifdef VELOUR_TBB
    union {
        counter_t count[4];
        four_counter_t side;
    } local_counters;
    local_counters.side = moving_right ? ATOMIC_LOAD(node->right_side) : ATOMIC_LOAD(node->left_side);
	counter_t   *counters = local_counters.count;
#else
	counter_t   *counters = moving_right ? node->right_count : node->left_count;
#endif

	int valid_dir = valid_single_successor(counters);

	if (valid_dir == MULTIPLE_SUCCESSORS) {  
		return false; // can't remove a tip with two outgrowths (the base of a Y)
	}

	if (valid_dir == NO_SUCCESSORS) {
#ifdef VELOUR_TBB
        atomic_setNodeDead<SeqNode>(node);
        ATOMIC_STORE(node->connections) = 0;
        ATOMIC_STORE(node->left_side_colors) = 0;
        ATOMIC_STORE(node->right_side_colors) = 0;
        ATOMIZE(DISCONNECTED_CHUNKS).fetch_and_increment();
#else
        setNodeDead<SeqNode>(node);
		node->connections = 0;
        node->left_side_colors = 0;
        node->right_side_colors = 0;
        ++ DISCONNECTED_CHUNKS;
#endif
		// printf("a disconnected chunk of length %d\n", length);
		return true;
	}

	// a single successor
	// CONDITION 2: the node in the extension direction has a single
	// neighbor in the direction facing this node
	assert((valid_dir >= 0) && (valid_dir < 4));
	bool sense_changed;
#ifdef VELOUR_TBB
    union {
        color_t color[4];
        four_color_t side;
    } local_colors;
    local_colors.side = moving_right ? ATOMIC_LOAD(node->right_side_colors) : ATOMIC_LOAD(node->left_side_colors);
    color_t *colors = local_colors.color;
#else
    color_t *colors = moving_right ? node->right_color : node->left_color;
#endif
    SeqNode *next = NULL;
    if (colors[valid_dir] == 0) {
        next = graph->findNextNode(node, valid_dir, moving_right, &sense_changed);
    } else {
        return false;
	}
    assert( next != NULL );

	bool next_moving_right = moving_right ^ sense_changed;
#ifdef VELOUR_TBB
    union {
        counter_t count[4];
        four_counter_t side;
    } local_back_counters;
    local_back_counters.side = next_moving_right ? ATOMIC_LOAD(next->left_side) : ATOMIC_LOAD(next->right_side);
	counter_t *next_back_counters = local_back_counters.count;
#else
	counter_t *next_back_counters = next_moving_right ? next->left_count : next->right_count;
#endif

	int next_back_valid = valid_single_successor(next_back_counters);

	if (next_back_valid != MULTIPLE_SUCCESSORS) {
        bool forceclip = (abs(next_back_counters[next_back_valid]) == CLIP_SINGLECOPY_COUNTER_VALUE);
        singlecopy_tip &= cnorm(counters[valid_dir]) == 1;
		bool remove = check_for_tip_removal(graph, next, next_moving_right, singlecopy_tip, length);
		if (remove || singlecopy_tip || forceclip) {
#ifdef VELOUR_TBB
            atomic_setNodeDead<SeqNode>(node);
            ATOMIC_STORE(node->connections) = 0;
            ATOMIC_STORE(node->left_side_colors) = 0;
            ATOMIC_STORE(node->right_side_colors) = 0;
#else
            setNodeDead<SeqNode>(node);
			node->connections = 0;
            node->left_side_colors = 0;
            node->right_side_colors = 0;
#endif
        }
        
        if (!remove && (singlecopy_tip || forceclip)) {
#ifdef VELOUR_TBB
            ATOMIC_STORE( (next_moving_right ? next->left_count : next->right_count)[next_back_valid] ) = 0;
            ATOMIC_STORE( (next_moving_right?next->left_color:next->right_color)[next_back_valid] ) = 0;
#else
            next_back_counters[next_back_valid] = 0;
            (next_moving_right?next->left_color:next->right_color)[next_back_valid] = 0;
#endif
        }
        return remove || singlecopy_tip || forceclip;
	}

	// can't extend.  Need to determine if we should trim.
	counter_t max_value = get_counter_max(next_back_counters);
	counter_t value = abs(counters[valid_dir]);
    if (value == CLIP_SINGLECOPY_COUNTER_VALUE) value = 1;
	if ((value >= g_minimum_edge_weight) && (value == max_value)) {
		// printf("dominant connection: length %d, weight %d\n", length, abs(counters[valid_dir]));
		return false;   // can't remove the dominant connection
	}

  // check for multiple single-copy predecessors in next node; mark those arcs as potential clips
  if (value == 1 && value == max_value) {
    for (int i = 0 ; i < 4 ; ++ i) {
        if (next_back_counters[i] == 1) {
#ifdef VELOUR_TBB
            ATOMIC_STORE( (next_moving_right ? next->left_count : next->right_count)[i] ) = CLIP_SINGLECOPY_COUNTER_VALUE;
#else
            next_back_counters[i] = CLIP_SINGLECOPY_COUNTER_VALUE;
#endif
        } else if (next_back_counters[i] == -1) {
#ifdef VELOUR_TBB
            ATOMIC_STORE( (next_moving_right ? next->left_count : next->right_count)[i] ) = - CLIP_SINGLECOPY_COUNTER_VALUE;
#else
            next_back_counters[i] = - CLIP_SINGLECOPY_COUNTER_VALUE;
#endif
        }
    }
  }

	// if we are clipping the tip, then mark the current "node" for
	// removal and disconnect the "next" node from the tip.  

/*
#ifdef VERIFY
  verify_node(node, HASHTABLE, g__FULLKMER_LENGTH);     // FINE, BEFORE WE LET IT GET INCONSISTENT.
  verify_node(next, HASHTABLE, g__FULLKMER_LENGTH);
#endif
*/

	// Note: we remove the link from "next", but not from "node".  The
	// reason why is that we don't want code to start on the other side
	// thinking that it is a tip that might need removal.  This means 
	// that from "node's" perspective, the graph looks inconsistent, but
	// that is okay, since we're going to remove "node" shortly.
#ifdef VELOUR_TBB
    atomic_setNodeDead<SeqNode>(node);
    ATOMIC_STORE(node->connections) = 0;
    ATOMIC_STORE(node->left_side_colors) = 0;
    ATOMIC_STORE(node->right_side_colors) = 0;
#else
    setNodeDead<SeqNode>(node);
	node->connections = 0;
    node->left_side_colors = 0;
    node->right_side_colors = 0;
#endif
	// printf("removal candidate: length %d, weight %d\n", length, abs(counters[valid_dir]));

	Nucleotide head_rightmost_base = node->sequence.GetHeadKmerRightmostBase(g__FULLKMER_LENGTH);
	Nucleotide tail_leftmost_base = node->sequence.GetTailKmerLeftmostBase(g__FULLKMER_LENGTH);
	next_back_valid = moving_right ? tail_leftmost_base : head_rightmost_base;

	if (sense_changed) { next_back_valid ^= 0x3; } // FIXME: i.e. complement??
           
#ifdef VELOUR_TBB 
    ATOMIC_STORE( (next_moving_right?next->left_color:next->right_color)[next_back_valid] ) = 0;
#else
    (next_moving_right?next->left_color:next->right_color)[next_back_valid] = 0;
#endif
  
#ifdef VELOUR_TBB
    ATOMIC_STORE( (next_moving_right ? next->left_count : next->right_count)[next_back_valid] ) = 0;
#else
	next_back_counters[next_back_valid] = 0;
#endif

#ifdef VELOUR_TBB
    ATOMIZE(TIP_DETACHED).fetch_and_increment();
#else
	++ TIP_DETACHED;
#endif

/*
#ifdef VERIFY
	// verify_node(node, g__FULLKMER_LENGTH);  // THIS VALIDATION WOULD FAIL, SINCE WE DON'T MODIFY NODE
	verify_node(next, HASHTABLE, g__FULLKMER_LENGTH);
#endif
*/

  	return true;
}
Esempio n. 2
0
static inline bool coopClaimNode(SeqNode *node)
{
    bool claimed = (ATOMIZE(node->claim_tid).compare_and_swap(1, 0) == 0);
    return claimed;
}