void cells_re_init(int new_cs) { CellPList tmp_local; Cell *tmp_cells; int tmp_n_cells,i; CELL_TRACE(fprintf(stderr, "%d: cells_re_init: convert type (%d->%d)\n", this_node, cell_structure.type, new_cs)); invalidate_ghosts(); /* CELL_TRACE({ int p; for (p = 0; p < n_total_particles; p++) if (local_particles[p]) fprintf(stderr, "%d: cells_re_init: got particle %d\n", this_node, p); } ); */ topology_release(cell_structure.type); /* MOVE old local_cell list to temporary buffer */ memcpy(&tmp_local,&local_cells,sizeof(CellPList)); init_cellplist(&local_cells); /* MOVE old cells to temporary buffer */ tmp_cells = cells; tmp_n_cells = n_cells; cells = NULL; n_cells = 0; topology_init(new_cs, &tmp_local); particle_invalidate_part_node(); /* finally deallocate the old cells */ realloc_cellplist(&tmp_local,0); for(i=0;i<tmp_n_cells;i++) realloc_particlelist(&tmp_cells[i],0); free(tmp_cells); CELL_TRACE(fprintf(stderr, "%d: old cells deallocated\n",this_node)); /* CELL_TRACE({ int p; for (p = 0; p < n_total_particles; p++) if (local_particles[p]) fprintf(stderr, "%d: cells_re_init: now got particle %d\n", this_node, p); } ); */ /* to enforce initialization of the ghost cells */ resort_particles = 1; #ifdef ADDITIONAL_CHECKS check_cells_consistency(); #endif }
void nsq_topology_release() { CELL_TRACE(fprintf(stderr,"%d: nsq_topology_release:\n",this_node)); /* free ghost cell pointer list */ realloc_cellplist(&me_do_ghosts, 0); free_comm(&cell_structure.ghost_cells_comm); free_comm(&cell_structure.exchange_ghosts_comm); free_comm(&cell_structure.update_ghost_pos_comm); free_comm(&cell_structure.collect_ghost_force_comm); }
/** Calculate cell grid dimensions, cell sizes and number of cells. * Calculates the cell grid, based on \ref local_box_l and \ref * max_range. If the number of cells is larger than \ref * max_num_cells, it increases max_range until the number of cells is * smaller or equal \ref max_num_cells. It sets: \ref * DomainDecomposition::cell_grid, \ref * DomainDecomposition::ghost_cell_grid, \ref * DomainDecomposition::cell_size, \ref * DomainDecomposition::inv_cell_size, and \ref n_cells. */ void dd_create_cell_grid() { int i,n_local_cells,new_cells,min_ind; double cell_range[3], min_size, scale, volume; CELL_TRACE(fprintf(stderr, "%d: dd_create_cell_grid: max_range %f\n",this_node,max_range)); 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])); /* initialize */ cell_range[0]=cell_range[1]=cell_range[2] = max_range; if (max_range < ROUND_ERROR_PREC*box_l[0]) { /* this is the initialization case */ n_local_cells = dd.cell_grid[0] = dd.cell_grid[1] = dd.cell_grid[2]=1; } else { /* Calculate initial cell grid */ volume = local_box_l[0]; for(i=1;i<3;i++) volume *= local_box_l[i]; scale = pow(max_num_cells/volume, 1./3.); for(i=0;i<3;i++) { /* this is at least 1 */ dd.cell_grid[i] = (int)ceil(local_box_l[i]*scale); cell_range[i] = local_box_l[i]/dd.cell_grid[i]; if ( cell_range[i] < max_range ) { /* ok, too many cells for this direction, set to minimum */ dd.cell_grid[i] = (int)floor(local_box_l[i]/max_range); if ( dd.cell_grid[i] < 1 ) { char *error_msg = runtime_error(ES_INTEGER_SPACE + 2*ES_DOUBLE_SPACE + 128); ERROR_SPRINTF(error_msg, "{002 interaction range %g in direction %d is larger than the local box size %g} ", max_range, i, local_box_l[i]); dd.cell_grid[i] = 1; } cell_range[i] = local_box_l[i]/dd.cell_grid[i]; } } /* It may be necessary to asymmetrically assign the scaling to the coordinates, which the above approach will not do. For a symmetric box, it gives a symmetric result. Here we correct that. */ for (;;) { n_local_cells = dd.cell_grid[0]; for (i = 1; i < 3; i++) n_local_cells *= dd.cell_grid[i]; /* done */ if (n_local_cells <= max_num_cells) break; /* find coordinate with the smallest cell range */ min_ind = 0; min_size = cell_range[0]; for (i = 1; i < 3; i++) if (dd.cell_grid[i] > 1 && cell_range[i] < min_size) { min_ind = i; min_size = cell_range[i]; } CELL_TRACE(fprintf(stderr, "%d: minimal coordinate %d, size %f, grid %d\n", this_node,min_ind, min_size, dd.cell_grid[min_ind])); dd.cell_grid[min_ind]--; cell_range[min_ind] = local_box_l[min_ind]/dd.cell_grid[min_ind]; } CELL_TRACE(fprintf(stderr, "%d: final %d %d %d\n", this_node, dd.cell_grid[0], dd.cell_grid[1], dd.cell_grid[2])); /* sanity check */ if (n_local_cells < min_num_cells) { char *error_msg = runtime_error(ES_INTEGER_SPACE + 2*ES_DOUBLE_SPACE + 128); ERROR_SPRINTF(error_msg, "{001 number of cells %d is smaller than minimum %d (interaction range too large or min_num_cells too large)} ", n_local_cells, min_num_cells); } } /* quit program if unsuccesful */ if(n_local_cells > max_num_cells) { char *error_msg = runtime_error(128); ERROR_SPRINTF(error_msg, "{003 no suitable cell grid found} "); } /* now set all dependent variables */ new_cells=1; for(i=0;i<3;i++) { dd.ghost_cell_grid[i] = dd.cell_grid[i]+2; new_cells *= dd.ghost_cell_grid[i]; dd.cell_size[i] = local_box_l[i]/(double)dd.cell_grid[i]; dd.inv_cell_size[i] = 1.0 / dd.cell_size[i]; } max_skin = dmin(dmin(dd.cell_size[0],dd.cell_size[1]),dd.cell_size[2]) - max_cut; /* allocate cell array and cell pointer arrays */ realloc_cells(new_cells); realloc_cellplist(&local_cells, local_cells.n = n_local_cells); realloc_cellplist(&ghost_cells, ghost_cells.n = new_cells-n_local_cells); 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])); }
void nsq_topology_init(CellPList *old) { Particle *part; int n, c, p, np, ntodo, diff; CELL_TRACE(fprintf(stderr, "%d: nsq_topology_init, %d\n", this_node, old->n)); cell_structure.type = CELL_STRUCTURE_NSQUARE; cell_structure.position_to_node = map_position_node_array; cell_structure.position_to_cell = nsq_position_to_cell; realloc_cells(n_nodes); /* mark cells */ local = &cells[this_node]; realloc_cellplist(&local_cells, local_cells.n = 1); local_cells.cell[0] = local; realloc_cellplist(&ghost_cells, ghost_cells.n = n_nodes - 1); c = 0; for (n = 0; n < n_nodes; n++) if (n != this_node) ghost_cells.cell[c++] = &cells[n]; /* distribute force calculation work */ ntodo = (n_nodes + 3)/2; init_cellplist(&me_do_ghosts); realloc_cellplist(&me_do_ghosts, ntodo); for (n = 0; n < n_nodes; n++) { diff = n - this_node; /* simple load balancing formula. Basically diff % n, where n >= n_nodes, n odd. The node itself is also left out, as it is treated differently */ if (((diff > 0 && (diff % 2) == 0) || (diff < 0 && ((-diff) % 2) == 1))) { CELL_TRACE(fprintf(stderr, "%d: doing interactions with %d\n", this_node, n)); me_do_ghosts.cell[me_do_ghosts.n++] = &cells[n]; } } /* create communicators */ nsq_prepare_comm(&cell_structure.ghost_cells_comm, GHOSTTRANS_PARTNUM); nsq_prepare_comm(&cell_structure.exchange_ghosts_comm, GHOSTTRANS_PROPRTS | GHOSTTRANS_POSITION); nsq_prepare_comm(&cell_structure.update_ghost_pos_comm, GHOSTTRANS_POSITION); nsq_prepare_comm(&cell_structure.collect_ghost_force_comm, GHOSTTRANS_FORCE); /* here we just decide what to transfer where */ if (n_nodes > 1) { for (n = 0; n < n_nodes; n++) { /* use the prefetched send buffers. Node 0 transmits first and never prefetches. */ if (this_node == 0 || this_node != n) { cell_structure.ghost_cells_comm.comm[n].type = GHOST_BCST; cell_structure.exchange_ghosts_comm.comm[n].type = GHOST_BCST; cell_structure.update_ghost_pos_comm.comm[n].type = GHOST_BCST; } else { cell_structure.ghost_cells_comm.comm[n].type = GHOST_BCST | GHOST_PREFETCH; cell_structure.exchange_ghosts_comm.comm[n].type = GHOST_BCST | GHOST_PREFETCH; cell_structure.update_ghost_pos_comm.comm[n].type = GHOST_BCST | GHOST_PREFETCH; } cell_structure.collect_ghost_force_comm.comm[n].type = GHOST_RDCE; } /* first round: all nodes except the first one prefetch their send data */ if (this_node != 0) { cell_structure.ghost_cells_comm.comm[0].type |= GHOST_PREFETCH; cell_structure.exchange_ghosts_comm.comm[0].type |= GHOST_PREFETCH; cell_structure.update_ghost_pos_comm.comm[0].type |= GHOST_PREFETCH; } } /* copy particles */ for (c = 0; c < old->n; c++) { part = old->cell[c]->part; np = old->cell[c]->n; for (p = 0; p < np; p++) append_unindexed_particle(local, &part[p]); } update_local_particles(local); }
/** Calculate cell grid dimensions, cell sizes and number of cells. * Calculates the cell grid, based on \ref local_box_l and \ref * max_range. If the number of cells is larger than \ref * max_num_cells, it increases max_range until the number of cells is * smaller or equal \ref max_num_cells. It sets: \ref * DomainDecomposition::cell_grid, \ref * DomainDecomposition::ghost_cell_grid, \ref * DomainDecomposition::cell_size, \ref * DomainDecomposition::inv_cell_size, and \ref n_cells. */ void dd_create_cell_grid() { int i,n_local_cells,new_cells,min_ind; double cell_range[3], min_size, scale, volume; CELL_TRACE(fprintf(stderr, "%d: dd_create_cell_grid: max_range %f\n",this_node,max_range)); 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])); /* initialize */ cell_range[0]=cell_range[1]=cell_range[2] = max_range; if (max_range < ROUND_ERROR_PREC*box_l[0]) { /* this is the initialization case */ #ifdef LEES_EDWARDS dd.cell_grid[0] = 2; dd.cell_grid[1] = 1; dd.cell_grid[2] = 1; n_local_cells = 2; #else n_local_cells = dd.cell_grid[0] = dd.cell_grid[1] = dd.cell_grid[2]=1; #endif } else { /* Calculate initial cell grid */ volume = local_box_l[0]; for(i=1;i<3;i++) volume *= local_box_l[i]; scale = pow(max_num_cells/volume, 1./3.); for(i=0;i<3;i++) { /* this is at least 1 */ dd.cell_grid[i] = (int)ceil(local_box_l[i]*scale); cell_range[i] = local_box_l[i]/dd.cell_grid[i]; if ( cell_range[i] < max_range ) { /* ok, too many cells for this direction, set to minimum */ dd.cell_grid[i] = (int)floor(local_box_l[i]/max_range); if ( dd.cell_grid[i] < 1 ) { ostringstream msg; msg << "interaction range " << max_range << " in direction " << i << " is larger than the local box size " << local_box_l[i]; runtimeError(msg); dd.cell_grid[i] = 1; } #ifdef LEES_EDWARDS if ( (i == 0) && (dd.cell_grid[0] < 2) ) { ostringstream msg; msg << "interaction range " << max_range << " in direction " << i << " is larger than half the local box size " << local_box_l[i] << "/2"; runtimeError(msg); dd.cell_grid[0] = 2; } #endif cell_range[i] = local_box_l[i]/dd.cell_grid[i]; } } /* It may be necessary to asymmetrically assign the scaling to the coordinates, which the above approach will not do. For a symmetric box, it gives a symmetric result. Here we correct that. */ for (;;) { n_local_cells = dd.cell_grid[0] * dd.cell_grid[1] * dd.cell_grid[2]; /* done */ if (n_local_cells <= max_num_cells) break; /* find coordinate with the smallest cell range */ min_ind = 0; min_size = cell_range[0]; #ifdef LEES_EDWARDS for (i = 2; i >= 1; i--) {/*preferably have thin slices in z or y... this is more efficient for Lees Edwards*/ #else for (i = 1; i < 3; i++) { #endif if (dd.cell_grid[i] > 1 && cell_range[i] < min_size) { min_ind = i; min_size = cell_range[i]; } } CELL_TRACE(fprintf(stderr, "%d: minimal coordinate %d, size %f, grid %d\n", this_node,min_ind, min_size, dd.cell_grid[min_ind])); dd.cell_grid[min_ind]--; cell_range[min_ind] = local_box_l[min_ind]/dd.cell_grid[min_ind]; } CELL_TRACE(fprintf(stderr, "%d: final %d %d %d\n", this_node, dd.cell_grid[0], dd.cell_grid[1], dd.cell_grid[2])); /* sanity check */ if (n_local_cells < min_num_cells) { ostringstream msg; msg << "number of cells "<< n_local_cells << " is smaller than minimum " << min_num_cells << " (interaction range too large or min_num_cells too large)"; runtimeError(msg); } } /* quit program if unsuccesful */ if(n_local_cells > max_num_cells) { ostringstream msg; msg << "no suitable cell grid found "; runtimeError(msg); } /* now set all dependent variables */ new_cells=1; for(i=0;i<3;i++) { dd.ghost_cell_grid[i] = dd.cell_grid[i]+2; #ifdef LEES_EDWARDS //Hack alert: only the boundary y-layers actually need the extra-thick ghost cell grid, //so some memory (and copies) are wasted in the name of simpler code. if( i == 0 ){dd.ghost_cell_grid[i]++;} #endif new_cells *= dd.ghost_cell_grid[i]; dd.cell_size[i] = local_box_l[i]/(double)dd.cell_grid[i]; dd.inv_cell_size[i] = 1.0 / dd.cell_size[i]; } max_skin = dmin(dmin(dd.cell_size[0],dd.cell_size[1]),dd.cell_size[2]) - max_cut; /* allocate cell array and cell pointer arrays */ realloc_cells(new_cells); realloc_cellplist(&local_cells, local_cells.n = n_local_cells); realloc_cellplist(&ghost_cells, ghost_cells.n = new_cells-n_local_cells); 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])); } /** Fill local_cells list and ghost_cells list for use with domain decomposition. \ref cells::cells is assumed to be a 3d grid with size \ref DomainDecomposition::ghost_cell_grid . */ void dd_mark_cells() { int m,n,o,cnt_c=0,cnt_l=0,cnt_g=0; DD_CELLS_LOOP(m,n,o) { #ifdef LEES_EDWARDS /* convenient for LE if a cell knows where it is*/ cells[cnt_c].myIndex[0] = m; cells[cnt_c].myIndex[1] = n; cells[cnt_c].myIndex[2] = o; #endif if(DD_IS_LOCAL_CELL(m,n,o)) local_cells.cell[cnt_l++] = &cells[cnt_c++]; else ghost_cells.cell[cnt_g++] = &cells[cnt_c++]; }