/// \details /// Finds the appropriate link cell for an atom based on the spatial /// coordinates and stores data in that link cell. /// \param [in] gid The global of the atom. /// \param [in] iType The species index of the atom. /// \param [in] x The x-coordinate of the atom. /// \param [in] y The y-coordinate of the atom. /// \param [in] z The z-coordinate of the atom. /// \param [in] px The x-component of the atom's momentum. /// \param [in] py The y-component of the atom's momentum. /// \param [in] pz The z-component of the atom's momentum. void putAtomInBox(LinkCell* boxes, Atoms* atoms, const int gid, const int iType, const real_t x, const real_t y, const real_t z, const real_t px, const real_t py, const real_t pz) { real_t xyz[3] = {x,y,z}; // Find correct box. int iBox = getBoxFromCoord(boxes, xyz); int iOff = iBox*MAXATOMS; iOff += boxes->nAtoms[iBox]; // assign values to array elements if (iBox < boxes->nLocalBoxes) atoms->nLocal++; boxes->nAtoms[iBox]++; atoms->gid[iOff] = gid; atoms->iSpecies[iOff] = iType; atoms->r[iOff][0] = x; atoms->r[iOff][1] = y; atoms->r[iOff][2] = z; atoms->p[iOff][0] = px; atoms->p[iOff][1] = py; atoms->p[iOff][2] = pz; }
/// \details /// This is the first step in returning data structures to a consistent /// state after the atoms move each time step. First we discard all /// atoms in the halo link cells. These are all atoms that are /// currently stored on other ranks and so any information we have about /// them is stale. Next, we move any atoms that have crossed link cell /// boundaries into their new link cells. It is likely that some atoms /// will be moved into halo link cells. Since we have deleted halo /// atoms from other tasks, it is clear that any atoms that are in halo /// cells at the end of this routine have just transitioned from local /// to halo atoms. Such atom must be sent to other tasks by a halo /// exchange to avoid being lost. /// \see redistributeAtoms void updateLinkCells(LinkCell* boxes, Atoms* atoms) { emptyHaloCells(boxes); for (int iBox=0; iBox<boxes->nLocalBoxes; ++iBox) { int iOff = iBox*MAXATOMS; int ii=0; while (ii < boxes->nAtoms[iBox]) { int jBox = getBoxFromCoord(boxes, atoms->r[iOff+ii]); if (jBox != iBox) moveAtom(boxes, atoms, ii, iBox, jBox); else ++ii; } } }
//The correctness of the task dependencies here depends on the assumption that there are no //dependencies between this function and the function that last wrote the position void updateLinkCells(LinkCell* boxes, LinkCell* boxesBuffer, Atoms* atoms, Atoms* atomsBuffer) { real3 *atomF = atoms->f; real3 *atomR = atoms->r; real3 *atomP = atoms->p; real3 *atomsBufferR = atomsBuffer->r; int dep[9]; for(int z=0; z < sim->boxes->gridSize[2]; z++) { for(int y=0; y < sim->boxes->gridSize[1]; y++) { int rowBox = z*sim->boxes->gridSize[1]*sim->boxes->gridSize[0]+y*sim->boxes->gridSize[0]; getNeighborRows(boxes, y, z, dep); #pragma omp task depend(out: atomsBufferR[rowBox*MAXATOMS]) \ depend( in: atomR[dep[0]*MAXATOMS], atomR[dep[1]*MAXATOMS], atomR[dep[2]*MAXATOMS], \ atomR[dep[3]*MAXATOMS], atomR[dep[4]*MAXATOMS], atomR[dep[5]*MAXATOMS], \ atomR[dep[6]*MAXATOMS], atomR[dep[7]*MAXATOMS], atomR[dep[8]*MAXATOMS] ) { //This task pulls all atoms that belong in cell iBox from multiple cells in the main buffer to cell iBox in the secondary buffer startTimer(redistributeTimer); for(int iBox=rowBox; iBox < rowBox + sim->boxes->gridSize[0]; iBox++) { boxesBuffer->nAtoms[iBox] = 0; int firstCopy = 0; for(int i=0; i<27; i++) { int neighborBox = boxes->nbrBoxes[iBox][i]; if(neighborBox != iBox || firstCopy == 0) { if(neighborBox == iBox) firstCopy = 1; for(int atomNum = 0; atomNum < boxes->nAtoms[neighborBox]; atomNum++) { real3 tempPosition; for(int i=0; i<3; i++) { tempPosition[i] = atoms->r[neighborBox*MAXATOMS + atomNum][i]; if(tempPosition[i] >= boxes->localMax[i]) { tempPosition[i] -= boxes->localMax[i]; } else if(tempPosition[i] <= boxes->localMin[i]) { tempPosition[i] += boxes->localMax[i]; } } if(iBox == getBoxFromCoord(boxes, tempPosition)) { copyAtom(atoms, atomsBuffer, atomNum, neighborBox, boxesBuffer->nAtoms[iBox], iBox); for(int i=0; i<3; i++) { atomsBuffer->r[iBox*MAXATOMS + boxesBuffer->nAtoms[iBox]][i] = tempPosition[i]; } boxesBuffer->nAtoms[iBox]++; } } } } } stopTimer(redistributeTimer); } } } //This loop copies the cells from the buffer back to the main buffer while sorting them. for(int z=0; z < sim->boxes->gridSize[2]; z++) { for(int y=0; y < sim->boxes->gridSize[1]; y++) { int rowBox = z*sim->boxes->gridSize[1]*sim->boxes->gridSize[0]+y*sim->boxes->gridSize[0]; int *nAtoms = &sim->boxes->nAtoms[rowBox]; #pragma omp task depend(in : atomsBufferR[rowBox*MAXATOMS]) \ depend(out: nAtoms, \ atomF[rowBox*MAXATOMS], atomR[rowBox*MAXATOMS],\ atomP[rowBox*MAXATOMS] ) { startTimer(redistributeSortTimer); for(int iBox=rowBox; iBox < rowBox + sim->boxes->gridSize[0]; iBox++) { copySortedCell(boxesBuffer, boxes, atomsBuffer, atoms, iBox); } stopTimer(redistributeSortTimer); } } } }