![]() |
ESPResSo 3.2.0-159-gf5c8922-git
Extensible Simulation Package for Soft Matter Research
|
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 /************************************************************/
1.7.5.1