Program Listing for File NeighborhoodSearchSpatialHashing.cpp

Return to documentation for file (Simulation/NeighborhoodSearchSpatialHashing.cpp)

#include "NeighborhoodSearchSpatialHashing.h"

using namespace PBD;
using namespace Utilities;

NeighborhoodSearchSpatialHashing::NeighborhoodSearchSpatialHashing(const unsigned int numParticles, const Real radius, const unsigned int maxNeighbors, const unsigned int maxParticlesPerCell) :
    m_gridMap(numParticles*2)
{
    m_cellGridSize = radius;
    m_radius2 = radius*radius;
    m_numParticles = numParticles;
    m_maxParticlesPerCell = maxParticlesPerCell;
    m_maxNeighbors = maxNeighbors;

    m_numNeighbors = NULL;
    m_neighbors = NULL;

    if (numParticles != 0)
    {
        m_numNeighbors = new unsigned int[m_numParticles];
        m_neighbors = new unsigned int*[m_numParticles];
        for (unsigned int i = 0; i < m_numParticles; i++)
            m_neighbors[i] = new unsigned int[m_maxNeighbors];
    }

    m_currentTimestamp = 0;
}

NeighborhoodSearchSpatialHashing::~NeighborhoodSearchSpatialHashing()
{
    cleanup();
}

void NeighborhoodSearchSpatialHashing::cleanup()
{
    for (unsigned int i=0; i < m_numParticles; i++)
        delete [] m_neighbors[i];
    delete [] m_neighbors;
    delete [] m_numNeighbors;
    m_numParticles = 0;

    for (unsigned int i=0; i < m_gridMap.bucket_count(); i++)
    {
        Hashmap<NeighborhoodSearchCellPos*, NeighborhoodSearchSpatialHashing::HashEntry*>::KeyValueMap *kvMap = m_gridMap.getKeyValueMap(i);
        if (kvMap)
        {
            for (Hashmap<NeighborhoodSearchCellPos*, NeighborhoodSearchSpatialHashing::HashEntry*>::KeyValueMap::iterator iter=kvMap->begin(); iter != kvMap->end(); iter++)
            {
                NeighborhoodSearchSpatialHashing::HashEntry* entry = iter->second;
                delete entry;
                iter->second = NULL;
            }
        }
    }
}

unsigned int ** NeighborhoodSearchSpatialHashing::getNeighbors() const
{
    return m_neighbors;
}

unsigned int * NeighborhoodSearchSpatialHashing::getNumNeighbors() const
{
    return m_numNeighbors;
}

unsigned int NeighborhoodSearchSpatialHashing::getNumParticles() const
{
    return m_numParticles;
}

void NeighborhoodSearchSpatialHashing::setRadius(const Real radius)
{
    m_cellGridSize = radius;
    m_radius2 = radius*radius;
}

Real NeighborhoodSearchSpatialHashing::getRadius() const
{
    return sqrt(m_radius2);
}

void NeighborhoodSearchSpatialHashing::update()
{
    m_currentTimestamp++;
}


void NeighborhoodSearchSpatialHashing::neighborhoodSearch(Vector3r *x)
{
    const Real factor = static_cast<Real>(1.0)/m_cellGridSize;
    for (int i=0; i < (int) m_numParticles; i++)
    {
        const int cellPos1 = NeighborhoodSearchSpatialHashing::floor(x[i][0] * factor)+1;
        const int cellPos2 = NeighborhoodSearchSpatialHashing::floor(x[i][1] * factor)+1;
        const int cellPos3 = NeighborhoodSearchSpatialHashing::floor(x[i][2] * factor)+1;
        NeighborhoodSearchCellPos cellPos(cellPos1, cellPos2, cellPos3);
        HashEntry *&entry = m_gridMap[&cellPos];

        if (entry != NULL)
        {
            if (entry->timestamp != m_currentTimestamp)
            {
                entry->timestamp = m_currentTimestamp;
                entry->particleIndices.clear();
            }
        }
        else
        {
            HashEntry *newEntry = new HashEntry();
            newEntry->particleIndices.reserve(m_maxParticlesPerCell);
            newEntry->timestamp = m_currentTimestamp;
            entry = newEntry;
        }
        entry->particleIndices.push_back(i);
    }

    // loop over all 27 neighboring cells
    #pragma omp parallel default(shared)
    {
        #pragma omp for schedule(static)
        for (int i=0; i < (int) m_numParticles; i++)
        {
            m_numNeighbors[i] = 0;
            const int cellPos1 = NeighborhoodSearchSpatialHashing::floor(x[i][0] * factor);
            const int cellPos2 = NeighborhoodSearchSpatialHashing::floor(x[i][1] * factor);
            const int cellPos3 = NeighborhoodSearchSpatialHashing::floor(x[i][2] * factor);
            for(unsigned char j=0; j < 3; j++)
            {
                for(unsigned char k=0; k < 3; k++)
                {
                    for(unsigned char l=0; l < 3; l++)
                    {
                        NeighborhoodSearchCellPos cellPos(cellPos1+j, cellPos2+k, cellPos3+l);
                        HashEntry * const *entry = m_gridMap.query(&cellPos);

                        if ((entry != NULL) && (*entry != NULL) && ((*entry)->timestamp == m_currentTimestamp))
                        {
                            for (unsigned int m=0; m < (*entry)->particleIndices.size(); m++)
                            {
                                const unsigned int pi = (*entry)->particleIndices[m];
                                if (pi != i)
                                {
                                    const Real dist2 = (x[i]-x[pi]).squaredNorm();
                                    if (dist2 < m_radius2)
                                    {
                                        if (m_numNeighbors[i] < m_maxNeighbors)
                                            m_neighbors[i][m_numNeighbors[i]++] = pi;
//                                  else
//                                          std::cout << "too many neighbors detected\n";
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

void NeighborhoodSearchSpatialHashing::neighborhoodSearch(Vector3r *x, const unsigned int numBoundaryParticles, Vector3r *boundaryX)
{
    const Real factor = static_cast<Real>(1.0)/m_cellGridSize;
    for (int i=0; i < (int) m_numParticles; i++)
    {
        const int cellPos1 = NeighborhoodSearchSpatialHashing::floor(x[i][0] * factor)+1;
        const int cellPos2 = NeighborhoodSearchSpatialHashing::floor(x[i][1] * factor)+1;
        const int cellPos3 = NeighborhoodSearchSpatialHashing::floor(x[i][2] * factor)+1;
        NeighborhoodSearchCellPos cellPos(cellPos1, cellPos2, cellPos3);
        HashEntry *&entry = m_gridMap[&cellPos];

        if (entry != NULL)
        {
            if (entry->timestamp != m_currentTimestamp)
            {
                entry->timestamp = m_currentTimestamp;
                entry->particleIndices.clear();
            }
        }
        else
        {
            HashEntry *newEntry = new HashEntry();
            newEntry->particleIndices.reserve(m_maxParticlesPerCell);
            newEntry->timestamp = m_currentTimestamp;
            entry = newEntry;
        }
        entry->particleIndices.push_back(i);
    }

    for (int i = 0; i < (int)numBoundaryParticles; i++)
    {
        const int cellPos1 = NeighborhoodSearchSpatialHashing::floor(boundaryX[i][0] * factor) + 1;
        const int cellPos2 = NeighborhoodSearchSpatialHashing::floor(boundaryX[i][1] * factor) + 1;
        const int cellPos3 = NeighborhoodSearchSpatialHashing::floor(boundaryX[i][2] * factor) + 1;
        NeighborhoodSearchCellPos cellPos(cellPos1, cellPos2, cellPos3);
        HashEntry *&entry = m_gridMap[&cellPos];

        if (entry != NULL)
        {
            if (entry->timestamp != m_currentTimestamp)
            {
                entry->timestamp = m_currentTimestamp;
                entry->particleIndices.clear();
            }
        }
        else
        {
            HashEntry *newEntry = new HashEntry();
            newEntry->particleIndices.reserve(m_maxParticlesPerCell);
            newEntry->timestamp = m_currentTimestamp;
            entry = newEntry;
        }
        entry->particleIndices.push_back(m_numParticles + i);
    }

    // loop over all 27 neighboring cells
    #pragma omp parallel default(shared)
    {
        #pragma omp for schedule(static)
        for (int i=0; i < (int) m_numParticles; i++)
        {
            m_numNeighbors[i] = 0;
            const int cellPos1 = NeighborhoodSearchSpatialHashing::floor(x[i][0] * factor);
            const int cellPos2 = NeighborhoodSearchSpatialHashing::floor(x[i][1] * factor);
            const int cellPos3 = NeighborhoodSearchSpatialHashing::floor(x[i][2] * factor);
            for(unsigned char j=0; j < 3; j++)
            {
                for(unsigned char k=0; k < 3; k++)
                {
                    for(unsigned char l=0; l < 3; l++)
                    {
                        NeighborhoodSearchCellPos cellPos(cellPos1+j, cellPos2+k, cellPos3+l);
                        HashEntry * const *entry = m_gridMap.query(&cellPos);

                        if ((entry != NULL) && (*entry != NULL) && ((*entry)->timestamp == m_currentTimestamp))
                        {
                            for (unsigned int m=0; m < (*entry)->particleIndices.size(); m++)
                            {
                                const unsigned int pi = (*entry)->particleIndices[m];
                                if (pi != i)
                                {
                                    Real dist2;
                                    if (pi < m_numParticles)
                                        dist2 = (x[i]-x[pi]).squaredNorm();
                                    else
                                        dist2 = (x[i] - boundaryX[pi - m_numParticles]).squaredNorm();

                                    if (dist2 < m_radius2)
                                    {
                                        if (m_numNeighbors[i] < m_maxNeighbors)
                                            m_neighbors[i][m_numNeighbors[i]++] = pi;
//                                      else
//                                          std::cout << "too many neighbors detected\n";
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}