Exemplo n.º 1
0
/**
 * Create the masks for sources and targets based on the contiguous
 * ranges given in sources and targets. We need to do some index
 * translation here, as the CG expects indices from 0..n for both
 * source and target populations, while the RangeSets sources and
 * targets contain NEST global indices (gids).
 *
 * The masks for the sources must contain all nodes (local+remote).
 * The skip of the mask was set to 1 in cg_set_masks(). The same
 * source mask is stored n_proc times on each process.
 *
 * The masks for the targets must only contain local nodes. This is
 * achieved by first setting skip to num_processes upon creation of
 * the mask in cg_set_masks(), and second by the fact that for each
 * contiguous range of nodes in a mask, each of them contains the
 * index-translated id of the first local neuron as the first
 * entry. If this renders the range empty (i.e. because the first
 * local id is beyond the last element of the range), the range is
 * not added to the mask.
 *
 * \param masks The std::vector of Masks to populate
 * \param sources The source ranges to create the source masks from
 * \param targets The target ranges to create the target masks from
 *
 * \note Each process computes the full set of source and target
 * masks, i.e. one mask per rank will be created on each rank.
 *
 * \note Setting the masks for all processes on each process might
 * become a memory bottleneck when going to very large numbers of
 * processes. Especially so for the source masks, which are all the
 * same. This could be solved by making the ConnectionGenerator
 * interface MPI aware and communicating the masks during connection
 * setup.
*/
void
cg_create_masks( std::vector< ConnectionGenerator::Mask >* masks,
  RangeSet& sources,
  RangeSet& targets )
{
  // The index of the left border of the currently looked at range
  // (counting from 0). This is used for index translation.
  size_t cg_idx_left = 0;

  // For sources, we only need to translate from NEST to CG indices.
  for ( RangeSet::iterator source = sources.begin(); source != sources.end(); ++source )
  {
    size_t num_elements = source->last - source->first;
    size_t right = cg_idx_left + num_elements;
    for ( size_t proc = 0; proc < static_cast< size_t >( Communicator::get_num_processes() );
          ++proc )
      ( *masks )[ proc ].sources.insert( cg_idx_left, right );
    cg_idx_left += num_elements + 1;
  }

  // Reset the index of the left border of the range for index
  // translation for the targets.
  cg_idx_left = 0;

  for ( RangeSet::iterator target = targets.begin(); target != targets.end(); ++target )
  {
    size_t num_elements = target->last - target->first;
    for ( size_t proc = 0; proc < static_cast< size_t >( Communicator::get_num_processes() );
          ++proc )
    {
      // Make sure that the range is only added on as many ranks as
      // there are elements in the range, or exactly on every rank,
      // if there are more elements in the range.
      if ( proc <= num_elements )
      {
        // For the different ranks, left will take on the CG indices
        // of all first local nodes that are contained in the range.
        // The rank, where this mask is to be used is determined
        // below when inserting the mask.
        size_t left = cg_idx_left + proc;

        // right is set to the CG index of the right border of the
        // range. This is the same for all ranks.
        size_t right = cg_idx_left + num_elements;

        // We index the masks according to the modulo distribution
        // of neurons in NEST. This ensures that the mask is set for
        // the rank where left acutally is the first neuron fromt
        // the currently looked at range.
        ( *masks )[ ( proc + target->first ) % Communicator::get_num_processes() ].targets.insert(
          left, right );
      }
    }

    // Update the CG index of the left border of the next range to
    // be one after the current range.
    cg_idx_left += num_elements + 1;
  }
}
Exemplo n.º 2
0
  void cg_create_masks(std::vector<ConnectionGenerator::Mask>* masks, RangeSet& sources, RangeSet& targets)
  {
    // We need to do some index translation here as the CG expects
    // indices from 0..n for both source and target populations.

    size_t length = 0;
    for (RangeSet::iterator source = sources.begin(); source != sources.end(); ++source)
    {
      for (size_t proc = 0; proc < static_cast<size_t>(Communicator::get_num_processes()); ++proc)
      {
        size_t last = source->last - source->first;
        if (proc <= last)
        {
          size_t left = proc + length;
          size_t right = last + length;
          (*masks)[(proc + source->first) % Communicator::get_num_processes()].sources.insert(left, right);
        }
      }
      length += source->last - source->first + 1;
    }

    length = 0;
    for (RangeSet::iterator target = targets.begin(); target != targets.end(); ++target)
    {
      for (size_t proc = 0; proc < static_cast<size_t>(Communicator::get_num_processes()); ++proc)
      {
        size_t last = target->last - target->first;
        if (proc <= last)
        {
          size_t left = proc + length;
          size_t right = last + length;
          (*masks)[(proc + target->first) % Communicator::get_num_processes()].targets.insert(left, right);
        }
      }
      length += target->last - target->first + 1;
    }
  }
Exemplo n.º 3
0
/**
 * Splits the selected segments by inserting new nodes in the middle. The
 * selected segments are defined by each pair of consecutive \a indexRanges.
 *
 * This method can deal with both polygons as well as polylines. For polygons,
 * pass <code>true</code> for \a closed.
 */
static QPolygonF splitPolygonSegments(const QPolygonF &polygon,
                                      const RangeSet<int> &indexRanges,
                                      bool closed)
{
    if (indexRanges.isEmpty())
        return polygon;

    const int n = polygon.size();

    QPolygonF result = polygon;

    RangeSet<int>::Range firstRange = indexRanges.begin();
    RangeSet<int>::Range it = indexRanges.end();
    // assert: firstRange != it

    if (closed) {
        RangeSet<int>::Range lastRange = it;
        --lastRange; // We know there is at least one range

        // Handle the case where the first and last nodes are selected
        if (firstRange.first() == 0 && lastRange.last() == n - 1) {
            const QPointF splitPoint = (result.first() + result.last()) / 2;
            result.append(splitPoint);
        }
    }

    do {
        --it;

        for (int i = it.last(); i > it.first(); --i) {
            const QPointF splitPoint = (result.at(i) + result.at(i - 1)) / 2;
            result.insert(i, splitPoint);
        }
    } while (it != firstRange);

    return result;
}
Exemplo n.º 4
0
/**
 * Joins the nodes at the given \a indexRanges. Each consecutive sequence
 * of nodes will be joined into a single node at the average location.
 *
 * This method can deal with both polygons as well as polylines. For polygons,
 * pass <code>true</code> for \a closed.
 */
static QPolygonF joinPolygonNodes(const QPolygonF &polygon,
                                  const RangeSet<int> &indexRanges,
                                  bool closed)
{
    if (indexRanges.isEmpty())
        return polygon;

    // Do nothing when dealing with a polygon with less than 3 points
    // (we'd no longer have a polygon)
    const int n = polygon.size();
    if (n < 3)
        return polygon;

    RangeSet<int>::Range firstRange = indexRanges.begin();
    RangeSet<int>::Range it = indexRanges.end();

    RangeSet<int>::Range lastRange = it;
    --lastRange; // We know there is at least one range

    QPolygonF result = polygon;

    // Indexes need to be offset when first and last range are joined.
    int indexOffset = 0;

    // Check whether the first and last ranges connect
    if (firstRange.first() == 0 && lastRange.last() == n - 1) {
        // Do nothing when the selection spans the whole polygon
        if (firstRange == lastRange)
            return polygon;

        // Join points of the first and last range when the polygon is closed
        if (closed) {
            QPointF averagePoint;
            for (int i = firstRange.first(); i <= firstRange.last(); i++)
                averagePoint += polygon.at(i);
            for (int i = lastRange.first(); i <= lastRange.last(); i++)
                averagePoint += polygon.at(i);
            averagePoint /= firstRange.length() + lastRange.length();

            result.remove(lastRange.first(), lastRange.length());
            result.remove(1, firstRange.length() - 1);
            result.replace(0, averagePoint);

            indexOffset = firstRange.length() - 1;

            // We have dealt with these ranges now
            // assert: firstRange != lastRange
            ++firstRange;
            --it;
        }
    }

    while (it != firstRange) {
        --it;

        // Merge the consecutive nodes into a single average point
        QPointF averagePoint;
        for (int i = it.first(); i <= it.last(); i++)
            averagePoint += polygon.at(i - indexOffset);
        averagePoint /= it.length();

        result.remove(it.first() + 1 - indexOffset, it.length() - 1);
        result.replace(it.first() - indexOffset, averagePoint);
    }

    return result;
}