ESPResSo 3.2.0-159-gf5c8922-git
Extensible Simulation Package for Soft Matter Research
domain_decomposition.c
Go to the documentation of this file.
00001 /*
00002   Copyright (C) 2010,2011,2012,2013 The ESPResSo project
00003   Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 
00004     Max-Planck-Institute for Polymer Research, Theory Group
00005   
00006   This file is part of ESPResSo.
00007   
00008   ESPResSo is free software: you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation, either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   ESPResSo is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
00020 */
00021 /** \file domain_decomposition.c
00022  *
00023  *  This file contains everything related to the cell system: domain decomposition.
00024  *  See also \ref domain_decomposition.h
00025  */
00026 
00027 #include "domain_decomposition.h"
00028 #include "errorhandling.h"
00029 #include "forces.h"
00030 #include "pressure.h"
00031 #include "energy.h"
00032 #include "constraint.h"
00033 #include "initialize.h"
00034 
00035 /************************************************/
00036 /** \name Defines */
00037 /************************************************/
00038 /*@{*/
00039 
00040 /** half the number of cell neighbors in 3 Dimensions. */
00041 #define CELLS_MAX_NEIGHBORS 14
00042 
00043 /*@}*/
00044 
00045 /************************************************/
00046 /** \name Variables */
00047 /************************************************/
00048 /*@{*/
00049 
00050 DomainDecomposition dd = { 1, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, NULL };
00051 
00052 int max_num_cells = CELLS_MAX_NUM_CELLS;
00053 int min_num_cells = 1;
00054 double max_skin   = 0.0;
00055 
00056 /*@}*/
00057 
00058 /************************************************************/
00059 /** \name Privat Functions */
00060 /************************************************************/
00061 /*@{*/
00062 
00063 /** Convenient replace for loops over all cells. */
00064 #define DD_CELLS_LOOP(m,n,o) \
00065   for(o=0; o<dd.ghost_cell_grid[2]; o++) \
00066     for(n=0; n<dd.ghost_cell_grid[1]; n++) \
00067       for(m=0; m<dd.ghost_cell_grid[0]; m++)
00068 
00069 /** Convenient replace for loops over Local cells. */
00070 #define DD_LOCAL_CELLS_LOOP(m,n,o) \
00071   for(o=1; o<dd.cell_grid[2]+1; o++) \
00072     for(n=1; n<dd.cell_grid[1]+1; n++) \
00073       for(m=1; m<dd.cell_grid[0]+1; m++)
00074 
00075 /** Convenient replace for inner cell check. usage: if(DD_IS_LOCAL_CELL(m,n,o)) {...} */
00076 #define DD_IS_LOCAL_CELL(m,n,o) \
00077   ( m > 0 && m < dd.ghost_cell_grid[0] - 1 && \
00078     n > 0 && n < dd.ghost_cell_grid[1] - 1 && \
00079     o > 0 && o < dd.ghost_cell_grid[2] - 1 ) 
00080 
00081 /** Convenient replace for ghost cell check. usage: if(DD_IS_GHOST_CELL(m,n,o)) {...} */
00082 #define DD_IS_GHOST_CELL(m,n,o) \
00083   ( m == 0 || m == dd.ghost_cell_grid[0] - 1 || \
00084     n == 0 || n == dd.ghost_cell_grid[1] - 1 || \
00085     o == 0 || o == dd.ghost_cell_grid[2] - 1 ) 
00086 
00087 /** Calculate cell grid dimensions, cell sizes and number of cells.
00088  *  Calculates the cell grid, based on \ref local_box_l and \ref
00089  *  max_range. If the number of cells is larger than \ref
00090  *  max_num_cells, it increases max_range until the number of cells is
00091  *  smaller or equal \ref max_num_cells. It sets: \ref
00092  *  DomainDecomposition::cell_grid, \ref
00093  *  DomainDecomposition::ghost_cell_grid, \ref
00094  *  DomainDecomposition::cell_size, \ref
00095  *  DomainDecomposition::inv_cell_size, and \ref n_cells.
00096  */
00097 void dd_create_cell_grid()
00098 {
00099   int i,n_local_cells,new_cells,min_ind;
00100   double cell_range[3], min_size, scale, volume;
00101   CELL_TRACE(fprintf(stderr, "%d: dd_create_cell_grid: max_range %f\n",this_node,max_range));
00102   CELL_TRACE(fprintf(stderr, "%d: dd_create_cell_grid: local_box %f-%f, %f-%f, %f-%f,\n",this_node,my_left[0],my_right[0],my_left[1],my_right[1],my_left[2],my_right[2]));
00103   
00104   /* initialize */
00105   cell_range[0]=cell_range[1]=cell_range[2] = max_range;
00106 
00107   if (max_range < ROUND_ERROR_PREC*box_l[0]) {
00108     /* this is the initialization case */
00109     n_local_cells = dd.cell_grid[0] = dd.cell_grid[1] = dd.cell_grid[2]=1;
00110   }
00111   else {
00112     /* Calculate initial cell grid */
00113     volume = local_box_l[0];
00114     for(i=1;i<3;i++) volume *= local_box_l[i];
00115     scale = pow(max_num_cells/volume, 1./3.);
00116     for(i=0;i<3;i++) {
00117       /* this is at least 1 */
00118       dd.cell_grid[i] = (int)ceil(local_box_l[i]*scale);
00119       cell_range[i] = local_box_l[i]/dd.cell_grid[i];
00120 
00121       if ( cell_range[i] < max_range ) {
00122         /* ok, too many cells for this direction, set to minimum */
00123         dd.cell_grid[i] = (int)floor(local_box_l[i]/max_range);
00124         if ( dd.cell_grid[i] < 1 ) {
00125           char *error_msg = runtime_error(ES_INTEGER_SPACE + 2*ES_DOUBLE_SPACE + 128);
00126           ERROR_SPRINTF(error_msg, "{002 interaction range %g in direction %d is larger than the local box size %g} ",
00127                         max_range, i, local_box_l[i]);
00128           dd.cell_grid[i] = 1;
00129         }
00130         cell_range[i] = local_box_l[i]/dd.cell_grid[i];
00131       }
00132     }
00133 
00134     /* It may be necessary to asymmetrically assign the scaling to the coordinates, which the above approach will not do.
00135        For a symmetric box, it gives a symmetric result. Here we correct that. */
00136     for (;;) {
00137       n_local_cells = dd.cell_grid[0];
00138       for (i = 1; i < 3; i++)
00139         n_local_cells *= dd.cell_grid[i];
00140 
00141       /* done */
00142       if (n_local_cells <= max_num_cells)
00143         break;
00144 
00145       /* find coordinate with the smallest cell range */
00146       min_ind = 0;
00147       min_size = cell_range[0];
00148       for (i = 1; i < 3; i++)
00149         if (dd.cell_grid[i] > 1 && cell_range[i] < min_size) {
00150           min_ind = i;
00151           min_size = cell_range[i];
00152         }
00153       CELL_TRACE(fprintf(stderr, "%d: minimal coordinate %d, size %f, grid %d\n", this_node,min_ind, min_size, dd.cell_grid[min_ind]));
00154 
00155       dd.cell_grid[min_ind]--;
00156       cell_range[min_ind] = local_box_l[min_ind]/dd.cell_grid[min_ind];
00157     }
00158     CELL_TRACE(fprintf(stderr, "%d: final %d %d %d\n", this_node, dd.cell_grid[0], dd.cell_grid[1], dd.cell_grid[2]));
00159 
00160     /* sanity check */
00161     if (n_local_cells < min_num_cells) {
00162       char *error_msg = runtime_error(ES_INTEGER_SPACE + 2*ES_DOUBLE_SPACE + 128);
00163       ERROR_SPRINTF(error_msg, "{001 number of cells %d is smaller than minimum %d (interaction range too large or min_num_cells too large)} ",
00164                     n_local_cells, min_num_cells);
00165     }
00166   }
00167 
00168   /* quit program if unsuccesful */
00169   if(n_local_cells > max_num_cells) {
00170     char *error_msg = runtime_error(128);
00171     ERROR_SPRINTF(error_msg, "{003 no suitable cell grid found} ");
00172   }
00173 
00174   /* now set all dependent variables */
00175   new_cells=1;
00176   for(i=0;i<3;i++) {
00177     dd.ghost_cell_grid[i] = dd.cell_grid[i]+2;  
00178     new_cells              *= dd.ghost_cell_grid[i];
00179     dd.cell_size[i]       = local_box_l[i]/(double)dd.cell_grid[i];
00180     dd.inv_cell_size[i]   = 1.0 / dd.cell_size[i];
00181   }
00182   max_skin = dmin(dmin(dd.cell_size[0],dd.cell_size[1]),dd.cell_size[2]) - max_cut;
00183 
00184   /* allocate cell array and cell pointer arrays */
00185   realloc_cells(new_cells);
00186   realloc_cellplist(&local_cells, local_cells.n = n_local_cells);
00187   realloc_cellplist(&ghost_cells, ghost_cells.n = new_cells-n_local_cells);
00188 
00189   CELL_TRACE(fprintf(stderr, "%d: dd_create_cell_grid, n_cells=%d, local_cells.n=%d, ghost_cells.n=%d, dd.ghost_cell_grid=(%d,%d,%d)\n", this_node, n_cells,local_cells.n,ghost_cells.n,dd.ghost_cell_grid[0],dd.ghost_cell_grid[1],dd.ghost_cell_grid[2]));
00190 }
00191 
00192 /** Fill local_cells list and ghost_cells list for use with domain
00193     decomposition.  \ref cells::cells is assumed to be a 3d grid with size
00194     \ref DomainDecomposition::ghost_cell_grid . */
00195 void dd_mark_cells()
00196 {
00197   int m,n,o,cnt_c=0,cnt_l=0,cnt_g=0;
00198   DD_CELLS_LOOP(m,n,o) {
00199     if(DD_IS_LOCAL_CELL(m,n,o)) local_cells.cell[cnt_l++] = &cells[cnt_c++]; 
00200     else                        ghost_cells.cell[cnt_g++] = &cells[cnt_c++];
00201   } 
00202 }
00203 
00204 /** Fill a communication cell pointer list. Fill the cell pointers of
00205     all cells which are inside a rectangular subgrid of the 3D cell
00206     grid (\ref DomainDecomposition::ghost_cell_grid) starting from the
00207     lower left corner lc up to the high top corner hc. The cell
00208     pointer list part_lists must already be large enough.
00209     \param part_lists  List of cell pointers to store the result.
00210     \param lc          lower left corner of the subgrid.
00211     \param hc          high up corner of the subgrid.
00212  */
00213 int dd_fill_comm_cell_lists(Cell **part_lists, int lc[3], int hc[3])
00214 {
00215   int i,m,n,o,c=0;
00216   /* sanity check */
00217   for(i=0; i<3; i++) {
00218     if(lc[i]<0 || lc[i] >= dd.ghost_cell_grid[i]) return 0;
00219     if(hc[i]<0 || hc[i] >= dd.ghost_cell_grid[i]) return 0;
00220     if(lc[i] > hc[i]) return 0;
00221   }
00222 
00223   for(o=lc[0]; o<=hc[0]; o++) 
00224     for(n=lc[1]; n<=hc[1]; n++) 
00225       for(m=lc[2]; m<=hc[2]; m++) {
00226         i = get_linear_index(o,n,m,dd.ghost_cell_grid);
00227         CELL_TRACE(fprintf(stderr,"%d: dd_fill_comm_cell_list: add cell %d\n",this_node,i));
00228         part_lists[c] = &cells[i];
00229         c++;
00230       }
00231   return c;
00232 }
00233 
00234 /** Create communicators for cell structure domain decomposition. (see \ref GhostCommunicator) */
00235 void  dd_prepare_comm(GhostCommunicator *comm, int data_parts)
00236 {
00237   int dir,lr,i,cnt, num, n_comm_cells[3];
00238   int lc[3],hc[3],done[3]={0,0,0};
00239 
00240   /* calculate number of communications */
00241   num = 0;
00242   for(dir=0; dir<3; dir++) { 
00243     for(lr=0; lr<2; lr++) {
00244 #ifdef PARTIAL_PERIODIC
00245       /* No communication for border of non periodic direction */
00246       if( PERIODIC(dir) || (boundary[2*dir+lr] == 0) ) 
00247 #endif
00248         {
00249           if(node_grid[dir] == 1 ) num++;
00250           else num += 2;
00251         }
00252     }
00253   }
00254 
00255   /* prepare communicator */
00256   CELL_TRACE(fprintf(stderr,"%d Create Communicator: prep_comm data_parts %d num %d\n",this_node,data_parts,num));
00257   prepare_comm(comm, data_parts, num);
00258 
00259   /* number of cells to communicate in a direction */
00260   n_comm_cells[0] = dd.cell_grid[1]       * dd.cell_grid[2];
00261   n_comm_cells[1] = dd.cell_grid[2]       * dd.ghost_cell_grid[0];
00262   n_comm_cells[2] = dd.ghost_cell_grid[0] * dd.ghost_cell_grid[1];
00263 
00264   cnt=0;
00265   /* direction loop: x, y, z */
00266   for(dir=0; dir<3; dir++) {
00267     lc[(dir+1)%3] = 1-done[(dir+1)%3]; 
00268     lc[(dir+2)%3] = 1-done[(dir+2)%3];
00269     hc[(dir+1)%3] = dd.cell_grid[(dir+1)%3]+done[(dir+1)%3];
00270     hc[(dir+2)%3] = dd.cell_grid[(dir+2)%3]+done[(dir+2)%3];
00271     /* lr loop: left right */
00272     /* here we could in principle build in a one sided ghost
00273        communication, simply by taking the lr loop only over one
00274        value */
00275     for(lr=0; lr<2; lr++) {
00276       if(node_grid[dir] == 1) {
00277         /* just copy cells on a single node */
00278 #ifdef PARTIAL_PERIODIC
00279         if( PERIODIC(dir ) || (boundary[2*dir+lr] == 0) ) 
00280 #endif
00281           {
00282             comm->comm[cnt].type          = GHOST_LOCL;
00283             comm->comm[cnt].node          = this_node;
00284             /* Buffer has to contain Send and Recv cells -> factor 2 */
00285             comm->comm[cnt].part_lists    = malloc(2*n_comm_cells[dir]*sizeof(ParticleList *));
00286             comm->comm[cnt].n_part_lists  = 2*n_comm_cells[dir];
00287             /* prepare folding of ghost positions */
00288             if((data_parts & GHOSTTRANS_POSSHFTD) && boundary[2*dir+lr] != 0) 
00289               comm->comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir];
00290             /* fill send comm cells */
00291             lc[(dir+0)%3] = hc[(dir+0)%3] = 1+lr*(dd.cell_grid[(dir+0)%3]-1);  
00292             dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc);
00293             CELL_TRACE(fprintf(stderr,"%d: prep_comm %d copy to          grid (%d,%d,%d)-(%d,%d,%d)\n",this_node,cnt,
00294                                lc[0],lc[1],lc[2],hc[0],hc[1],hc[2]));
00295             /* fill recv comm cells */
00296             lc[(dir+0)%3] = hc[(dir+0)%3] = 0+(1-lr)*(dd.cell_grid[(dir+0)%3]+1);
00297             /* place recieve cells after send cells */
00298             dd_fill_comm_cell_lists(&comm->comm[cnt].part_lists[n_comm_cells[dir]],lc,hc);
00299             CELL_TRACE(fprintf(stderr,"%d: prep_comm %d copy from        grid (%d,%d,%d)-(%d,%d,%d)\n",this_node,cnt,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2]));
00300             cnt++;
00301           }
00302       }
00303       else {
00304         /* i: send/recv loop */
00305         for(i=0; i<2; i++) {  
00306 #ifdef PARTIAL_PERIODIC
00307           if( PERIODIC(dir) || (boundary[2*dir+lr] == 0) ) 
00308 #endif
00309             if((node_pos[dir]+i)%2==0) {
00310               comm->comm[cnt].type          = GHOST_SEND;
00311               comm->comm[cnt].node          = node_neighbors[2*dir+lr];
00312               comm->comm[cnt].part_lists    = malloc(n_comm_cells[dir]*sizeof(ParticleList *));
00313               comm->comm[cnt].n_part_lists  = n_comm_cells[dir];
00314               /* prepare folding of ghost positions */
00315               if((data_parts & GHOSTTRANS_POSSHFTD) && boundary[2*dir+lr] != 0) 
00316                 comm->comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir];
00317               
00318               lc[(dir+0)%3] = hc[(dir+0)%3] = 1+lr*(dd.cell_grid[(dir+0)%3]-1);  
00319               dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc);
00320               
00321               CELL_TRACE(fprintf(stderr,"%d: prep_comm %d send to   node %d grid (%d,%d,%d)-(%d,%d,%d)\n",this_node,cnt,
00322                                  comm->comm[cnt].node,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2]));
00323               cnt++;
00324             }
00325 #ifdef PARTIAL_PERIODIC
00326           if( PERIODIC(dir) || (boundary[2*dir+(1-lr)] == 0) ) 
00327 #endif
00328             if((node_pos[dir]+(1-i))%2==0) {
00329               comm->comm[cnt].type          = GHOST_RECV;
00330               comm->comm[cnt].node          = node_neighbors[2*dir+(1-lr)];
00331               comm->comm[cnt].part_lists    = malloc(n_comm_cells[dir]*sizeof(ParticleList *));
00332               comm->comm[cnt].n_part_lists  = n_comm_cells[dir];
00333               
00334               lc[(dir+0)%3] = hc[(dir+0)%3] = 0+(1-lr)*(dd.cell_grid[(dir+0)%3]+1);
00335               dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc);
00336               
00337               CELL_TRACE(fprintf(stderr,"%d: prep_comm %d recv from node %d grid (%d,%d,%d)-(%d,%d,%d)\n",this_node,cnt,
00338                                  comm->comm[cnt].node,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2]));
00339               cnt++;
00340             }
00341         }
00342       }
00343       done[dir]=1;
00344     }
00345   }
00346 }
00347 
00348 /** Revert the order of a communicator: After calling this the
00349     communicator is working in reverted order with exchanged
00350     communication types GHOST_SEND <-> GHOST_RECV. */
00351 void dd_revert_comm_order(GhostCommunicator *comm)
00352 {
00353   int i,j,nlist2;
00354   GhostCommunication tmp;
00355   ParticleList *tmplist;
00356 
00357   CELL_TRACE(fprintf(stderr,"%d: dd_revert_comm_order: anz comm: %d\n",this_node,comm->num));
00358 
00359   /* revert order */
00360   for(i=0; i<(comm->num/2); i++) {
00361     tmp = comm->comm[i];
00362     comm->comm[i] = comm->comm[comm->num-i-1];
00363     comm->comm[comm->num-i-1] = tmp;
00364   }
00365   /* exchange SEND/RECV */
00366   for(i=0; i<comm->num; i++) {
00367     if(comm->comm[i].type == GHOST_SEND) comm->comm[i].type = GHOST_RECV;
00368     else if(comm->comm[i].type == GHOST_RECV) comm->comm[i].type = GHOST_SEND;
00369     else if(comm->comm[i].type == GHOST_LOCL) {
00370       nlist2=comm->comm[i].n_part_lists/2;
00371       for(j=0;j<nlist2;j++) {
00372         tmplist = comm->comm[i].part_lists[j];
00373         comm->comm[i].part_lists[j] = comm->comm[i].part_lists[j+nlist2];
00374         comm->comm[i].part_lists[j+nlist2] = tmplist;
00375       }
00376     }
00377   }
00378 }
00379 
00380 /** Of every two communication rounds, set the first receivers to prefetch and poststore */
00381 void dd_assign_prefetches(GhostCommunicator *comm)
00382 {
00383   int cnt;
00384 
00385   for(cnt=0; cnt<comm->num; cnt += 2) {
00386     if (comm->comm[cnt].type == GHOST_RECV && comm->comm[cnt + 1].type == GHOST_SEND) {
00387       comm->comm[cnt].type |= GHOST_PREFETCH | GHOST_PSTSTORE;
00388       comm->comm[cnt + 1].type |= GHOST_PREFETCH | GHOST_PSTSTORE;
00389     }
00390   }
00391 }
00392 
00393 /** update the 'shift' member of those GhostCommunicators, which use
00394     that value to speed up the folding process of its ghost members
00395     (see \ref dd_prepare_comm for the original), i.e. all which have
00396     GHOSTTRANS_POSSHFTD or'd into 'data_parts' upon execution of \ref
00397     dd_prepare_comm. */
00398 void dd_update_communicators_w_boxl()
00399 {
00400   int cnt=0;
00401   /* direction loop: x, y, z */
00402   for(int dir=0; dir<3; dir++) {
00403     /* lr loop: left right */
00404     for(int lr=0; lr<2; lr++) {
00405       if(node_grid[dir] == 1) {
00406 #ifdef PARTIAL_PERIODIC
00407         if( PERIODIC(dir ) || (boundary[2*dir+lr] == 0) ) 
00408 #endif
00409           {
00410             /* prepare folding of ghost positions */
00411             if(boundary[2*dir+lr] != 0) {
00412               cell_structure.exchange_ghosts_comm.comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir]; 
00413               cell_structure.update_ghost_pos_comm.comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir]; 
00414             }
00415             cnt++;
00416           }
00417       }
00418       else {
00419         /* i: send/recv loop */
00420         for(int i=0; i<2; i++) {  
00421 #ifdef PARTIAL_PERIODIC
00422           if( PERIODIC(dir) || (boundary[2*dir+lr] == 0) ) 
00423 #endif
00424             if((node_pos[dir]+i)%2==0) {
00425               /* prepare folding of ghost positions */
00426               if(boundary[2*dir+lr] != 0) {
00427                 cell_structure.exchange_ghosts_comm.comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir];
00428                 cell_structure.update_ghost_pos_comm.comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir];
00429               }
00430               cnt++;
00431             }
00432 #ifdef PARTIAL_PERIODIC
00433           if( PERIODIC(dir) || (boundary[2*dir+(1-lr)] == 0) ) 
00434 #endif
00435             if((node_pos[dir]+(1-i))%2==0) {
00436               cnt++;
00437             }
00438         }
00439       }
00440     }
00441   }
00442 }
00443 
00444 /** Init cell interactions for cell system domain decomposition.
00445  * initializes the interacting neighbor cell list of a cell The
00446  * created list of interacting neighbor cells is used by the verlet
00447  * algorithm (see verlet.c) to build the verlet lists.
00448  */
00449 void dd_init_cell_interactions()
00450 {
00451   int m,n,o,p,q,r,ind1,ind2,c_cnt=0,n_cnt;
00452  
00453   /* initialize cell neighbor structures */
00454   dd.cell_inter = (IA_Neighbor_List *) realloc(dd.cell_inter,local_cells.n*sizeof(IA_Neighbor_List));
00455   for(m=0; m<local_cells.n; m++) { 
00456     dd.cell_inter[m].nList = NULL; 
00457     dd.cell_inter[m].n_neighbors=0; 
00458   }
00459 
00460   /* loop all local cells */
00461   DD_LOCAL_CELLS_LOOP(m,n,o) {
00462     dd.cell_inter[c_cnt].nList = (IA_Neighbor *) realloc(dd.cell_inter[c_cnt].nList, CELLS_MAX_NEIGHBORS*sizeof(IA_Neighbor));
00463     dd.cell_inter[c_cnt].n_neighbors = CELLS_MAX_NEIGHBORS;
00464  
00465     n_cnt=0;
00466     ind1 = get_linear_index(m,n,o,dd.ghost_cell_grid);
00467     /* loop all neighbor cells */
00468     for(p=o-1; p<=o+1; p++)     
00469       for(q=n-1; q<=n+1; q++)
00470         for(r=m-1; r<=m+1; r++) {   
00471           ind2 = get_linear_index(r,q,p,dd.ghost_cell_grid);
00472           if(ind2 >= ind1) {
00473             dd.cell_inter[c_cnt].nList[n_cnt].cell_ind = ind2;
00474             dd.cell_inter[c_cnt].nList[n_cnt].pList    = &cells[ind2];
00475             init_pairList(&dd.cell_inter[c_cnt].nList[n_cnt].vList);
00476             n_cnt++;
00477           }
00478         }
00479     c_cnt++;
00480   }
00481 }
00482 
00483 /*************************************************/
00484 
00485 /** Returns pointer to the cell which corresponds to the position if
00486     the position is in the nodes spatial domain otherwise a NULL
00487     pointer. */
00488 Cell *dd_save_position_to_cell(double pos[3]) 
00489 {
00490   int i,cpos[3];
00491   double lpos;
00492 
00493   for(i=0;i<3;i++) {
00494     lpos = pos[i] - my_left[i];
00495 
00496     cpos[i] = (int)(lpos*dd.inv_cell_size[i])+1;
00497     
00498     /* particles outside our box. Still take them if
00499        VERY close or nonperiodic boundary */
00500     if (cpos[i] < 1) {
00501       if (lpos > -ROUND_ERROR_PREC*box_l[i]
00502 #ifdef PARTIAL_PERIODIC
00503           || (!PERIODIC(i) && boundary[2*i])
00504 #endif
00505           )
00506         cpos[i] = 1;
00507       else
00508         return NULL;
00509     }
00510     else if (cpos[i] > dd.cell_grid[i]) {
00511       if (lpos < local_box_l[i] + ROUND_ERROR_PREC*box_l[i]
00512 #ifdef PARTIAL_PERIODIC
00513           || (!PERIODIC(i) && boundary[2*i+1])
00514 #endif
00515           )
00516         cpos[i] = dd.cell_grid[i];
00517       else
00518         return NULL;
00519     }
00520   }
00521   i = get_linear_index(cpos[0],cpos[1],cpos[2], dd.ghost_cell_grid); 
00522   return &(cells[i]);  
00523 }
00524 
00525 Cell *dd_position_to_cell(double pos[3])
00526 {
00527   int i,cpos[3];
00528   double lpos;
00529 
00530   for(i=0;i<3;i++) {
00531     lpos = pos[i] - my_left[i];
00532 
00533     cpos[i] = (int)(lpos*dd.inv_cell_size[i])+1;
00534 
00535     if (cpos[i] < 1) {
00536       cpos[i] = 1;
00537 #ifdef ADDITIONAL_CHECKS
00538       if (PERIODIC(i) && lpos < -ROUND_ERROR_PREC*box_l[i]) {
00539         char *errtext = runtime_error(128 + 3*ES_DOUBLE_SPACE);
00540         ERROR_SPRINTF(errtext, "{005 particle @ (%g, %g, %g) is outside of the allowed cell grid} ", pos[0], pos[1], pos[2]);
00541       }
00542 #endif
00543     }
00544     else if (cpos[i] > dd.cell_grid[i]) {
00545       cpos[i] = dd.cell_grid[i];
00546 #ifdef ADDITIONAL_CHECKS
00547       if (PERIODIC(i) && lpos > local_box_l[i] + ROUND_ERROR_PREC*box_l[i]) {
00548         char *errtext = runtime_error(128 + 3*ES_DOUBLE_SPACE);
00549         ERROR_SPRINTF(errtext, "{005 particle @ (%g, %g, %g) is outside of the allowed cell grid} ", pos[0], pos[1], pos[2]);
00550       }
00551 #endif
00552     }
00553   }
00554   i = get_linear_index(cpos[0],cpos[1],cpos[2], dd.ghost_cell_grid);  
00555   return &cells[i];
00556 }
00557 
00558 /*************************************************/
00559 
00560 /** Append the particles in pl to \ref local_cells and update \ref local_particles.  
00561     @return 0 if all particles in pl reside in the nodes domain otherwise 1.*/
00562 int dd_append_particles(ParticleList *pl, int fold_dir)
00563 {
00564   int p, dir, c, cpos[3], flag=0, fold_coord=fold_dir/2;
00565 
00566   CELL_TRACE(fprintf(stderr, "%d: dd_append_particles %d\n", this_node, pl->n));
00567 
00568   for(p=0; p<pl->n; p++) {
00569     if(boundary[fold_dir] != 0)
00570       fold_coordinate(pl->part[p].r.p, pl->part[p].l.i, fold_coord);
00571     
00572     for(dir=0;dir<3;dir++) {
00573       cpos[dir] = (int)((pl->part[p].r.p[dir]-my_left[dir])*dd.inv_cell_size[dir])+1;
00574 
00575       if (cpos[dir] < 1) { 
00576         cpos[dir] = 1;
00577 #ifdef PARTIAL_PERIODIC 
00578         if( PERIODIC(dir) ) 
00579 #endif
00580           {
00581             flag=1;
00582             CELL_TRACE(if(fold_coord==2){fprintf(stderr, "%d: dd_append_particles: particle %d (%f,%f,%f) not inside node domain.\n", this_node,pl->part[p].p.identity,pl->part[p].r.p[0],pl->part[p].r.p[1],pl->part[p].r.p[2]);});
00583           }
00584       }
00585       else if (cpos[dir] > dd.cell_grid[dir]) {
00586         cpos[dir] = dd.cell_grid[dir];
00587 #ifdef PARTIAL_PERIODIC 
00588         if( PERIODIC(dir) ) 
00589 #endif
00590           {
00591             flag=1;
00592             CELL_TRACE(if(fold_coord==2){fprintf(stderr, "%d: dd_append_particles: particle %d (%f,%f,%f) not inside node domain.\n", this_node,pl->part[p].p.identity,pl->part[p].r.p[0],pl->part[p].r.p[1],pl->part[p].r.p[2]);});
00593           }
00594       }
00595     }
00596     c = get_linear_index(cpos[0],cpos[1],cpos[2], dd.ghost_cell_grid);
00597     CELL_TRACE(fprintf(stderr,"%d: dd_append_particles: Appen Part id=%d to cell %d\n",this_node,pl->part[p].p.identity,c));
00598     append_indexed_particle(&cells[c],&pl->part[p]);
00599   }
00600   return flag;
00601 }
00602  
00603 /*@}*/
00604 
00605 /************************************************************/
00606 /* Public Functions */
00607 /************************************************************/
00608 
00609 void dd_on_geometry_change(int flags) {
00610   /* check that the CPU domains are still sufficiently large. */
00611   for (int i = 0; i < 3; i++)
00612     if (local_box_l[i] < max_range) {
00613       char *errtext = runtime_error(128 + ES_INTEGER_SPACE);
00614       ERROR_SPRINTF(errtext,"{013 box_l in direction %d is too small} ", i);
00615     }
00616 
00617   /* A full resorting is necessary if the grid has changed. We simply
00618      don't have anything fast for this case. Probably also not
00619      necessary. */
00620   if (flags & CELL_FLAG_GRIDCHANGED) {
00621     CELL_TRACE(fprintf(stderr,"%d: dd_on_geometry_change full redo\n",
00622                        this_node));
00623     cells_re_init(CELL_STRUCTURE_CURRENT);
00624     return;
00625   }
00626 
00627   /* otherwise, re-set our geometrical dimensions which have changed
00628      (in addition to the general ones that \ref grid_changed_box_l
00629      takes care of) */
00630   for(int i=0; i<3; i++) {
00631     dd.cell_size[i]       = local_box_l[i]/(double)dd.cell_grid[i];
00632     dd.inv_cell_size[i]   = 1.0 / dd.cell_size[i];
00633   }
00634   double min_cell_size = dmin(dmin(dd.cell_size[0],dd.cell_size[1]),dd.cell_size[2]);
00635   max_skin = min_cell_size - max_cut;
00636 
00637   CELL_TRACE(fprintf(stderr, "%d: dd_on_geometry_change: max_range = %f, min_cell_size = %f, max_skin = %f\n", this_node, max_range, min_cell_size, max_skin));
00638   
00639   if (max_range > min_cell_size) {
00640     /* if new box length leads to too small cells, redo cell structure
00641        using smaller number of cells. */
00642     cells_re_init(CELL_STRUCTURE_DOMDEC);
00643     return;
00644   }
00645 
00646   /* If we are not in a hurry, check if we can maybe optimize the cell
00647      system by using smaller cells. */
00648   if (!(flags & CELL_FLAG_FAST)) {
00649     int i;
00650     for(i=0; i<3; i++) {
00651       int poss_size = (int)floor(local_box_l[i]/max_range);
00652       if (poss_size > dd.cell_grid[i])
00653         break;
00654     }
00655     if (i < 3) {
00656       /* new range/box length allow smaller cells, redo cell structure,
00657          possibly using smaller number of cells. */
00658       cells_re_init(CELL_STRUCTURE_DOMDEC);
00659       return;
00660     }
00661   }
00662 
00663   dd_update_communicators_w_boxl();
00664 
00665   /* tell other algorithms that the box length might have changed. */
00666   on_boxl_change();
00667 }
00668 
00669 /************************************************************/
00670 void dd_topology_init(CellPList *old)
00671 {
00672   int c,p,np;
00673   int exchange_data, update_data;
00674   Particle *part;
00675 
00676   CELL_TRACE(fprintf(stderr, "%d: dd_topology_init: Number of recieved cells=%d\n", this_node, old->n));
00677 
00678   /** broadcast the flag for using verlet list */
00679   MPI_Bcast(&dd.use_vList, 1, MPI_INT, 0, comm_cart);
00680  
00681   cell_structure.type             = CELL_STRUCTURE_DOMDEC;
00682   cell_structure.position_to_node = map_position_node_array;
00683   cell_structure.position_to_cell = dd_position_to_cell;
00684 
00685   /* set up new domain decomposition cell structure */
00686   dd_create_cell_grid();
00687   /* mark cells */
00688   dd_mark_cells();
00689   /* create communicators */
00690   dd_prepare_comm(&cell_structure.ghost_cells_comm,         GHOSTTRANS_PARTNUM);
00691 
00692   exchange_data = (GHOSTTRANS_PROPRTS | GHOSTTRANS_POSITION | GHOSTTRANS_POSSHFTD);
00693   update_data   = (GHOSTTRANS_POSITION | GHOSTTRANS_POSSHFTD);
00694   dd_prepare_comm(&cell_structure.exchange_ghosts_comm,  exchange_data);
00695   dd_prepare_comm(&cell_structure.update_ghost_pos_comm, update_data);
00696 
00697   dd_prepare_comm(&cell_structure.collect_ghost_force_comm, GHOSTTRANS_FORCE);
00698   /* collect forces has to be done in reverted order! */
00699   dd_revert_comm_order(&cell_structure.collect_ghost_force_comm);
00700 
00701   dd_assign_prefetches(&cell_structure.ghost_cells_comm);
00702   dd_assign_prefetches(&cell_structure.exchange_ghosts_comm);
00703   dd_assign_prefetches(&cell_structure.update_ghost_pos_comm);
00704   dd_assign_prefetches(&cell_structure.collect_ghost_force_comm);
00705 
00706 #ifdef LB
00707   dd_prepare_comm(&cell_structure.ghost_lbcoupling_comm, GHOSTTRANS_COUPLING) ;
00708   dd_assign_prefetches(&cell_structure.ghost_lbcoupling_comm) ;
00709 #endif
00710 
00711   /* initialize cell neighbor structures */
00712   dd_init_cell_interactions();
00713 
00714   /* copy particles */
00715   for (c = 0; c < old->n; c++) {
00716     part = old->cell[c]->part;
00717     np   = old->cell[c]->n;
00718     for (p = 0; p < np; p++) {
00719       Cell *nc = dd_save_position_to_cell(part[p].r.p);
00720       /* particle does not belong to this node. Just stow away
00721          somewhere for the moment */
00722       if (nc == NULL)
00723         nc = local_cells.cell[0];
00724       append_unindexed_particle(nc, &part[p]);
00725     }
00726   }
00727   for(c=0; c<local_cells.n; c++) {
00728     update_local_particles(local_cells.cell[c]);
00729   }
00730   CELL_TRACE(fprintf(stderr,"%d: dd_topology_init: done\n",this_node));
00731 }
00732 
00733 /************************************************************/
00734 void dd_topology_release()
00735 {
00736   int i,j;
00737   CELL_TRACE(fprintf(stderr,"%d: dd_topology_release:\n",this_node));
00738   /* release cell interactions */
00739   for(i=0; i<local_cells.n; i++) {
00740     for(j=0; j<dd.cell_inter[i].n_neighbors; j++) 
00741       free_pairList(&dd.cell_inter[i].nList[j].vList);
00742     dd.cell_inter[i].nList = (IA_Neighbor *) realloc(dd.cell_inter[i].nList,0);
00743   }
00744   dd.cell_inter = (IA_Neighbor_List *) realloc(dd.cell_inter,0);
00745   /* free ghost cell pointer list */
00746   realloc_cellplist(&ghost_cells, ghost_cells.n = 0);
00747   /* free ghost communicators */
00748   free_comm(&cell_structure.ghost_cells_comm);
00749   free_comm(&cell_structure.exchange_ghosts_comm);
00750   free_comm(&cell_structure.update_ghost_pos_comm);
00751   free_comm(&cell_structure.collect_ghost_force_comm);
00752 #ifdef LB
00753   free_comm(&cell_structure.ghost_lbcoupling_comm);
00754 #endif
00755 }
00756 
00757 /************************************************************/
00758 void  dd_exchange_and_sort_particles(int global_flag)
00759 {
00760   int dir, c, p, i, finished=0;
00761   ParticleList *cell,*sort_cell, send_buf_l, send_buf_r, recv_buf_l, recv_buf_r;
00762   Particle *part;
00763   CELL_TRACE(fprintf(stderr,"%d: dd_exchange_and_sort_particles(%d):\n",this_node,global_flag));
00764 
00765   init_particlelist(&send_buf_l);
00766   init_particlelist(&send_buf_r);
00767   init_particlelist(&recv_buf_l);
00768   init_particlelist(&recv_buf_r);
00769   while(finished == 0 ) {
00770     finished=1;
00771     /* direction loop: x, y, z */  
00772     for(dir=0; dir<3; dir++) { 
00773       if(node_grid[dir] > 1) {
00774         /* Communicate particles that have left the node domain */
00775         /* particle loop */
00776         for(c=0; c<local_cells.n; c++) {
00777           cell = local_cells.cell[c];
00778           for (p = 0; p < cell->n; p++) {
00779             part = &cell->part[p];
00780             /* Move particles to the left side */
00781             if(part->r.p[dir] - my_left[dir] < -ROUND_ERROR_PREC*box_l[dir]) {
00782 #ifdef PARTIAL_PERIODIC 
00783               if( PERIODIC(dir) || (boundary[2*dir]==0) ) 
00784 #endif
00785                 {
00786                   CELL_TRACE(fprintf(stderr,"%d: dd_ex_and_sort_p: send part left %d\n",this_node,part->p.identity));
00787                   local_particles[part->p.identity] = NULL;
00788                   move_indexed_particle(&send_buf_l, cell, p);
00789                   if(p < cell->n) p--;
00790                 }
00791             }
00792             /* Move particles to the right side */
00793             else if(part->r.p[dir] - my_right[dir] >= ROUND_ERROR_PREC*box_l[dir]) {
00794 #ifdef PARTIAL_PERIODIC 
00795               if( PERIODIC(dir) || (boundary[2*dir+1]==0) ) 
00796 #endif
00797                 {
00798                   CELL_TRACE(fprintf(stderr,"%d: dd_ex_and_sort_p: send part right %d\n",this_node,part->p.identity));
00799                   local_particles[part->p.identity] = NULL;
00800                   move_indexed_particle(&send_buf_r, cell, p);
00801                   if(p < cell->n) p--;
00802                 }
00803             }
00804             /* Sort particles in cells of this node during last direction */
00805             else if(dir==2) {
00806               sort_cell = dd_save_position_to_cell(part->r.p);
00807               if(sort_cell != cell) {
00808                 if(sort_cell==NULL) {
00809                   CELL_TRACE(fprintf(stderr,"%d: dd_exchange_and_sort_particles: Take another loop",this_node));
00810                   CELL_TRACE(fprintf(stderr, "%d: dd_exchange_and_sort_particles: CP1 Particle %d (%f,%f,%f) not inside node domain.\n",
00811                                      this_node,part->p.identity,part->r.p[0],part->r.p[1],part->r.p[2]));                
00812                   finished=0;
00813                   sort_cell = local_cells.cell[0];
00814                   if(sort_cell != cell) {
00815                     move_indexed_particle(sort_cell, cell, p);
00816                     if(p < cell->n) p--;
00817                   }
00818                 }
00819                 else {
00820                   move_indexed_particle(sort_cell, cell, p);
00821                   if(p < cell->n) p--;
00822                 }
00823               }
00824             }
00825           }
00826         }
00827 
00828         /* Exchange particles */
00829         if(node_pos[dir]%2==0) {
00830           send_particles(&send_buf_l, node_neighbors[2*dir]);
00831           recv_particles(&recv_buf_r, node_neighbors[2*dir+1]);
00832           send_particles(&send_buf_r, node_neighbors[2*dir+1]);
00833           recv_particles(&recv_buf_l, node_neighbors[2*dir]);
00834         }
00835         else {
00836           recv_particles(&recv_buf_r, node_neighbors[2*dir+1]);
00837           send_particles(&send_buf_l, node_neighbors[2*dir]);
00838           recv_particles(&recv_buf_l, node_neighbors[2*dir]);
00839           send_particles(&send_buf_r, node_neighbors[2*dir+1]);
00840         }
00841         /* sort received particles to cells */
00842         if(dd_append_particles(&recv_buf_l, 2*dir  ) && dir == 2) finished = 0;
00843         if(dd_append_particles(&recv_buf_r, 2*dir+1) && dir == 2) finished = 0; 
00844         /* reset send/recv buffers */
00845         send_buf_l.n = 0;
00846         send_buf_r.n = 0;
00847         recv_buf_l.n = 0;
00848         recv_buf_r.n = 0;
00849       }
00850       else {
00851         /* Single node direction case (no communication) */
00852         /* Fold particles that have left the box */
00853         /* particle loop */
00854         for(c=0; c<local_cells.n; c++) {
00855           cell = local_cells.cell[c];
00856           for (p = 0; p < cell->n; p++) {
00857             part = &cell->part[p];
00858 #ifdef PARTIAL_PERIODIC 
00859             if( PERIODIC(dir) ) 
00860 #endif
00861               {
00862                 fold_coordinate(part->r.p, part->l.i, dir);
00863               }
00864             if (dir==2) {
00865               sort_cell = dd_save_position_to_cell(part->r.p);
00866               if(sort_cell != cell) {
00867                 if(sort_cell==NULL) {
00868                   CELL_TRACE(fprintf(stderr, "%d: dd_exchange_and_sort_particles: CP2 Particle %d (%f,%f,%f) not inside node domain.\n",
00869                                      this_node,part->p.identity,part->r.p[0],part->r.p[1],part->r.p[2]));
00870                   finished=0;
00871                   sort_cell = local_cells.cell[0];
00872                   if(sort_cell != cell) {
00873                     move_indexed_particle(sort_cell, cell, p);
00874                     if(p < cell->n) p--;
00875                   }      
00876                 }
00877                 else {
00878                   CELL_TRACE(fprintf(stderr, "%d: dd_exchange_and_sort_particles: move particle id %d\n", this_node,part->p.identity));
00879                   move_indexed_particle(sort_cell, cell, p);
00880                   if(p < cell->n) p--;
00881                 }
00882               }
00883             }
00884           }
00885         }
00886       }
00887     }
00888 
00889     /* Communicate wether particle exchange is finished */
00890     if(global_flag == CELL_GLOBAL_EXCHANGE) {
00891       if(this_node==0) {
00892         int sum;
00893         MPI_Reduce(&finished, &sum, 1, MPI_INT, MPI_SUM, 0, comm_cart);
00894         if( sum < n_nodes ) finished=0; else finished=sum; 
00895       } else {
00896         MPI_Reduce(&finished, NULL, 1, MPI_INT, MPI_SUM, 0, comm_cart);
00897       }
00898       MPI_Bcast(&finished, 1, MPI_INT, 0, comm_cart);
00899     } else {
00900       if(finished == 0) {
00901         char *errtext = runtime_error(128);
00902         ERROR_SPRINTF(errtext,"{004 some particles moved more than min_local_box_l, reduce the time step} ");
00903         /* the bad guys are all in cell 0, but probably their interactions are of no importance anyways.
00904            However, their positions have to be made valid again. */
00905         finished = 1;
00906         /* all out of range coordinates in the left overs cell are moved to (0,0,0) */
00907         cell = local_cells.cell[0];
00908         for (p = 0; p < cell->n; p++) {
00909           part = &cell->part[p];
00910           if(dir < 3 && (part->r.p[dir] < my_left[dir] || part->r.p[dir] > my_right[dir]))
00911             for (i = 0; i < 3; i++)
00912               part->r.p[i] = 0;
00913         }
00914       }
00915     }
00916     CELL_TRACE(fprintf(stderr,"%d: dd_exchange_and_sort_particles: finished value: %d\n",this_node,finished));
00917   }
00918 
00919   realloc_particlelist(&send_buf_l, 0);
00920   realloc_particlelist(&send_buf_r, 0);
00921   realloc_particlelist(&recv_buf_l, 0);
00922   realloc_particlelist(&recv_buf_r, 0);
00923 
00924 #ifdef ADDITIONAL_CHECKS
00925   check_particle_consistency();
00926 #endif
00927 
00928   CELL_TRACE(fprintf(stderr,"%d: dd_exchange_and_sort_particles finished\n",this_node));
00929 }
00930 
00931 /*************************************************/
00932 
00933 int calc_processor_min_num_cells()
00934 {
00935   int i, min = 1;
00936   /* the minimal number of cells can be lower if there are at least two nodes serving a direction,
00937      since this also ensures that the cell size is at most half the box length. However, if there is
00938      only one processor for a direction, there have to be at least two cells for this direction. */
00939   for (i = 0; i < 3; i++) 
00940     if (node_grid[i] == 1) 
00941       min *= 2;
00942   return min;
00943 }
00944 
00945 void calc_link_cell()
00946 {
00947   int c, np1, n, np2, i ,j, j_start;
00948   Cell *cell;
00949   IA_Neighbor *neighbor;
00950   Particle *p1, *p2;
00951   double dist2, vec21[3];
00952 
00953   /* Loop local cells */
00954   for (c = 0; c < local_cells.n; c++) {
00955 
00956     cell = local_cells.cell[c];
00957     p1   = cell->part;
00958     np1  = cell->n;
00959 
00960     /* Loop cell neighbors */
00961     for (n = 0; n < dd.cell_inter[c].n_neighbors; n++) {
00962       neighbor = &dd.cell_inter[c].nList[n];
00963       p2  = neighbor->pList->part;
00964       np2 = neighbor->pList->n;
00965       /* Loop cell particles */
00966       for(i=0; i < np1; i++) {
00967         j_start = 0;
00968         /* Tasks within cell: bonded forces */
00969         if(n == 0) {
00970           add_bonded_force(&p1[i]);
00971 #ifdef CONSTRAINTS
00972           add_constraints_forces(&p1[i]);
00973 #endif
00974           if (rebuild_verletlist)
00975             memcpy(p1[i].l.p_old, p1[i].r.p, 3*sizeof(double));
00976 
00977           j_start = i+1;
00978         }
00979         /* Loop neighbor cell particles */
00980         for(j = j_start; j < np2; j++) {
00981 #ifdef EXCLUSIONS
00982           if(do_nonbonded(&p1[i], &p2[j]))
00983 #endif
00984             {
00985               dist2 = distance2vec(p1[i].r.p, p2[j].r.p, vec21);
00986               add_non_bonded_pair_force(&(p1[i]), &(p2[j]), vec21, sqrt(dist2), dist2);
00987             }
00988         }
00989       }
00990     }
00991   }
00992   rebuild_verletlist = 0;
00993 }
00994 
00995 /************************************************************/
00996 
00997 void calculate_link_cell_energies()
00998 {
00999   int c, np1, np2, n, i, j, j_start;
01000   Cell *cell;
01001   IA_Neighbor *neighbor;
01002   Particle *p1, *p2;
01003   double dist2, vec21[3];
01004 
01005   CELL_TRACE(fprintf(stderr,"%d: calculate link-cell energies\n",this_node));
01006 
01007   /* Loop local cells */
01008   for (c = 0; c < local_cells.n; c++) {
01009     cell = local_cells.cell[c];
01010     p1   = cell->part;
01011     np1  = cell->n;
01012     /* calculate bonded interactions (loop local particles) */
01013     for(i = 0; i < np1; i++)  {
01014       add_kinetic_energy(&p1[i]);
01015       add_bonded_energy(&p1[i]);
01016 #ifdef CONSTRAINTS
01017       add_constraints_energy(&p1[i]);
01018 #endif
01019 
01020       if (rebuild_verletlist)
01021         memcpy(p1[i].l.p_old, p1[i].r.p, 3*sizeof(double));
01022     }
01023 
01024     CELL_TRACE(fprintf(stderr,"%d: cell %d with %d neighbors\n",this_node,c, dd.cell_inter[c].n_neighbors));
01025     /* Loop cell neighbors */
01026     for (n = 0; n < dd.cell_inter[c].n_neighbors; n++) {
01027       neighbor = &dd.cell_inter[c].nList[n];
01028       p2  = neighbor->pList->part;
01029       np2 = neighbor->pList->n;
01030       /* Loop cell particles */
01031       for(i=0; i < np1; i++) {
01032         j_start = 0;
01033         if(n == 0) j_start = i+1;
01034         /* Loop neighbor cell particles */
01035         for(j = j_start; j < np2; j++) {        
01036 #ifdef EXCLUSIONS
01037           if(do_nonbonded(&p1[i], &p2[j]))
01038 #endif
01039             {
01040               dist2 = distance2vec(p1[i].r.p, p2[j].r.p, vec21);
01041               add_non_bonded_pair_energy(&(p1[i]), &(p2[j]), vec21, sqrt(dist2), dist2);
01042             }
01043         }
01044       }
01045     }
01046   }
01047   rebuild_verletlist = 0;
01048 }
01049 
01050 /************************************************************/
01051 
01052 void calculate_link_cell_virials(int v_comp)
01053 {
01054   int c, np1, np2, n, i, j, j_start;
01055   Cell *cell;
01056   IA_Neighbor *neighbor;
01057   Particle *p1, *p2;
01058   double dist2, vec21[3];
01059 
01060   CELL_TRACE(fprintf(stderr,"%d: calculate link-cell energies\n",this_node));
01061 
01062   /* Loop local cells */
01063   for (c = 0; c < local_cells.n; c++) {
01064     cell = local_cells.cell[c];
01065     p1   = cell->part;
01066     np1  = cell->n;
01067     /* calculate bonded interactions (loop local particles) */
01068     for(i = 0; i < np1; i++)  {
01069       add_kinetic_virials(&p1[i], v_comp);
01070       add_bonded_virials(&p1[i]);
01071 #ifdef BOND_ANGLE_OLD
01072       add_three_body_bonded_stress(&p1[i]);
01073 #endif
01074 #ifdef BOND_ANGLE
01075       add_three_body_bonded_stress(&p1[i]);
01076 #endif
01077       if (rebuild_verletlist)
01078         memcpy(p1[i].l.p_old, p1[i].r.p, 3*sizeof(double));
01079     }
01080 
01081     CELL_TRACE(fprintf(stderr,"%d: cell %d with %d neighbors\n",this_node,c, dd.cell_inter[c].n_neighbors));
01082     /* Loop cell neighbors */
01083     for (n = 0; n < dd.cell_inter[c].n_neighbors; n++) {
01084       neighbor = &dd.cell_inter[c].nList[n];
01085       p2  = neighbor->pList->part;
01086       np2 = neighbor->pList->n;
01087       /* Loop cell particles */
01088       for(i=0; i < np1; i++) {
01089         j_start = 0;
01090         if(n == 0) j_start = i+1;
01091         /* Loop neighbor cell particles */
01092         for(j = j_start; j < np2; j++) {        
01093 #ifdef EXCLUSIONS
01094           if(do_nonbonded(&p1[i], &p2[j]))
01095 #endif
01096             {
01097               dist2 = distance2vec(p1[i].r.p, p2[j].r.p, vec21);
01098               add_non_bonded_pair_virials(&(p1[i]), &(p2[j]), vec21, sqrt(dist2), dist2);
01099             }
01100         }
01101       }
01102     }
01103   }
01104   rebuild_verletlist = 0;
01105 }
01106 
01107 /************************************************************/