ESPResSo 3.2.0-159-gf5c8922-git
Extensible Simulation Package for Soft Matter Research
cells.c
Go to the documentation of this file.
00001 /*
00002   Copyright (C) 2010,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 cells.c
00022  *
00023  *  This file contains functions for the cell system.
00024  *
00025  *  For more information on cells, see cells.h
00026  *   */
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include "utils.h"
00031 #include "cells.h"
00032 #include "grid.h"
00033 #include "particle_data.h"
00034 #include "interaction_data.h"
00035 #include "integrate.h"
00036 #include "initialize.h"
00037 #include "communication.h"
00038 #include "verlet.h"
00039 #include "ghosts.h"
00040 #include "domain_decomposition.h"
00041 #include "nsquare.h"
00042 #include "layered.h"
00043 
00044 /* Variables */
00045 
00046 /** list of all cells. */
00047 Cell *cells = NULL;
00048 /** size of \ref cells */
00049 int n_cells = 0;
00050 /** list of pointers to all cells containing particles physically on the local node. */
00051 CellPList local_cells = { NULL, 0, 0 };
00052 /** list of pointers to all cells containing ghosts. */
00053 CellPList ghost_cells = { NULL, 0, 0 };
00054 
00055 /** Type of cell structure in use */
00056 CellStructure cell_structure = { CELL_STRUCTURE_NONEYET };
00057 
00058 double max_range = 0.0;
00059 
00060 int rebuild_verletlist = 0;
00061 
00062 /************************************************************/
00063 /** \name Privat Functions */
00064 /************************************************************/
00065 /*@{*/
00066 
00067 #ifdef ADDITIONAL_CHECKS
00068 /** Extensive Debug function to check the consistency of the cells and
00069     the particles therein. Use with care! */
00070 static void check_cells_consistency()
00071 {
00072   int c, index;
00073   IntList used;
00074   alloc_intlist(&used, n_cells);
00075   memset(used.e, 0, n_cells*sizeof(int));
00076   
00077   for (c = 0; c < local_cells.n; c++) {
00078     index = (void *)local_cells.cell[c] - (void *)cells;
00079     if ((index % sizeof(Cell)) != 0) {
00080       fprintf(stderr, "%d: local cell pointer not even aligned, certainly wrong (local_cell[%d], index=%d).\n", this_node, c, index);
00081       errexit();
00082     }
00083     index /= sizeof(Cell);
00084     if (index < 0 || index >= n_cells) {
00085       fprintf(stderr, "%d: local cell pointer out of range, maybe old leftover (local_cell[%d]).\n", this_node, c);
00086       errexit();
00087     }
00088     if (used.e[index]) {
00089       fprintf(stderr, "%d: local cell is already pointed to (local_cell[%d]).\n", this_node, c);
00090       errexit();
00091     }
00092     used.e[index] = 1;
00093   }
00094 
00095   for (c = 0; c < ghost_cells.n; c++) {
00096     index = (void *)ghost_cells.cell[c] - (void *)cells;
00097     if ((index % sizeof(Cell)) != 0) {
00098       fprintf(stderr, "%d: ghost cell pointer not even aligned, certainly wrong (ghost_cell[%d], index=%d).\n", this_node, c, index);
00099       errexit();
00100     }
00101     index /= sizeof(Cell);
00102     if (index < 0 || index >= n_cells) {
00103       fprintf(stderr, "%d: ghost cell pointer out of range, maybe old leftover (ghost_cell[%d]).\n", this_node, c);
00104       errexit();
00105     }
00106     if (used.e[index]) {
00107       fprintf(stderr, "%d: ghost cell is already pointed to (ghost_cell[%d]).\n", this_node, c);
00108       errexit();
00109     }
00110     used.e[index] = 1;
00111   }
00112   for (c = 0; c < n_cells; c++)
00113     if (!used.e[c]) {
00114       fprintf(stderr, "%d: cell %d is not used anywhere.\n", this_node, c);
00115       errexit();
00116     }
00117   realloc_intlist(&used, 0);
00118 }
00119 #endif
00120 
00121 /** Switch for choosing the topology release function of a certain
00122     cell system. */
00123 static void topology_release(int cs) {
00124   switch (cs) {
00125   case CELL_STRUCTURE_NONEYET:
00126     break;
00127   case CELL_STRUCTURE_CURRENT:
00128     topology_release(cell_structure.type);
00129     break;
00130   case CELL_STRUCTURE_DOMDEC:
00131     dd_topology_release();
00132     break;
00133   case CELL_STRUCTURE_NSQUARE:
00134     nsq_topology_release();
00135     break;
00136   case CELL_STRUCTURE_LAYERED:
00137     layered_topology_release();
00138     break;
00139   default:
00140     fprintf(stderr, "INTERNAL ERROR: attempting to sort the particles in an unknown way (%d)\n", cs);
00141     errexit();
00142   }
00143 }
00144 
00145 /** Switch for choosing the topology init function of a certain
00146     cell system. */
00147 static void topology_init(int cs, CellPList *local) {
00148   switch (cs) {
00149   case CELL_STRUCTURE_NONEYET:
00150     break;
00151   case CELL_STRUCTURE_CURRENT:
00152     topology_init(cell_structure.type, local);
00153     break;
00154   case CELL_STRUCTURE_DOMDEC:
00155     dd_topology_init(local);
00156     break;
00157   case CELL_STRUCTURE_NSQUARE:
00158     nsq_topology_init(local);
00159     break;
00160   case CELL_STRUCTURE_LAYERED:
00161     layered_topology_init(local);
00162     break;
00163   default:
00164     fprintf(stderr, "INTERNAL ERROR: attempting to sort the particles in an unknown way (%d)\n", cs);
00165     errexit();
00166   }
00167 }
00168 
00169 /*@}*/
00170 
00171 /************************************************************
00172  *            Exported Functions                            *
00173  ************************************************************/
00174 
00175 /************************************************************/
00176 
00177 void cells_re_init(int new_cs)
00178 {
00179   CellPList tmp_local;
00180   Cell *tmp_cells;
00181   int tmp_n_cells,i;
00182 
00183   CELL_TRACE(fprintf(stderr, "%d: cells_re_init: convert type (%d->%d)\n", this_node, cell_structure.type, new_cs));
00184 
00185   invalidate_ghosts();
00186 
00187   /* 
00188      CELL_TRACE({
00189      int p;
00190      for (p = 0; p < n_total_particles; p++)
00191      if (local_particles[p])
00192      fprintf(stderr, "%d: cells_re_init: got particle %d\n", this_node, p);
00193      }
00194      );
00195   */
00196 
00197   topology_release(cell_structure.type);
00198   /* MOVE old local_cell list to temporary buffer */
00199   memcpy(&tmp_local,&local_cells,sizeof(CellPList));
00200   init_cellplist(&local_cells);
00201 
00202   /* MOVE old cells to temporary buffer */
00203   tmp_cells   = cells;
00204   tmp_n_cells = n_cells;
00205   cells   = NULL;
00206   n_cells = 0;
00207 
00208   topology_init(new_cs, &tmp_local);
00209 
00210   particle_invalidate_part_node();
00211 
00212   /* finally deallocate the old cells */
00213   realloc_cellplist(&tmp_local,0);
00214   for(i=0;i<tmp_n_cells;i++)
00215     realloc_particlelist(&tmp_cells[i],0);
00216 
00217   free(tmp_cells);
00218   CELL_TRACE(fprintf(stderr, "%d: old cells deallocated\n",this_node));
00219 
00220   /*
00221     CELL_TRACE({
00222     int p;
00223     for (p = 0; p < n_total_particles; p++)
00224     if (local_particles[p])
00225     fprintf(stderr, "%d: cells_re_init: now got particle %d\n", this_node, p);
00226     }
00227     );
00228   */
00229 
00230   /* to enforce initialization of the ghost cells */
00231   resort_particles = 1;
00232 
00233 #ifdef ADDITIONAL_CHECKS
00234   check_cells_consistency();
00235 #endif
00236 
00237   on_cell_structure_change();
00238 }
00239 
00240 /************************************************************/
00241 
00242 void realloc_cells(int size)
00243 {
00244   int i;
00245   CELL_TRACE(fprintf(stderr, "%d: realloc_cells %d\n", this_node, size));
00246   /* free all memory associated with cells to be deleted. */
00247   for(i=size; i<n_cells; i++) {
00248     realloc_particlelist(&cells[i],0);
00249   }
00250   /* resize the cell list */
00251   if(size != n_cells) {
00252     cells = (Cell *) realloc(cells, sizeof(Cell)*size);
00253   }
00254   /* initialize new cells */
00255   for(i=n_cells; i<size; i++) {
00256     init_particlelist(&cells[i]);
00257   }
00258   n_cells = size;
00259 }  
00260 
00261 /*************************************************/
00262 
00263 void announce_resort_particles()
00264 {
00265   int sum;
00266   
00267   MPI_Allreduce(&resort_particles, &sum, 1, MPI_INT, MPI_SUM, comm_cart);
00268   resort_particles = (sum > 0) ? 1 : 0;
00269   
00270   INTEG_TRACE(fprintf(stderr,"%d: announce_resort_particles: resort_particles=%d\n",
00271                       this_node, resort_particles));
00272 }
00273 
00274 /*************************************************/
00275 
00276 int cells_get_n_particles()
00277 {
00278   int c, cnt = 0;
00279   for (c = 0; c < local_cells.n; c++)
00280     cnt += local_cells.cell[c]->n;
00281   return cnt;
00282 }
00283 
00284 /*************************************************/
00285 
00286 void print_local_particle_positions()
00287 {
00288   Cell *cell;
00289   int c,i,np,cnt=0;
00290   Particle *part;
00291 
00292   for (c = 0; c < local_cells.n; c++) {
00293     cell = local_cells.cell[c];
00294     part = cell->part;
00295     np   = cell->n;
00296     for(i=0 ; i < np; i++) {
00297       fprintf(stderr,"%d: local cell %d contains part id=%d pos=(%f,%f,%f)\n",
00298               this_node, c, part[i].p.identity,
00299               part[i].r.p[0], part[i].r.p[1], part[i].r.p[2]);
00300       cnt++;
00301     }
00302   }
00303   fprintf(stderr,"%d: found %d particles\n",this_node,cnt);
00304 }
00305 
00306 /*************************************************/
00307 
00308 void cells_resort_particles(int global_flag)
00309 {
00310   CELL_TRACE(fprintf(stderr, "%d: entering cells_resort_particles %d\n", this_node, global_flag));
00311 
00312   invalidate_ghosts();
00313 
00314   particle_invalidate_part_node();
00315   n_verlet_updates++;
00316 
00317   switch (cell_structure.type) {
00318   case CELL_STRUCTURE_LAYERED:
00319     layered_exchange_and_sort_particles(global_flag);
00320     break;
00321   case CELL_STRUCTURE_NSQUARE:
00322     nsq_balance_particles(global_flag);
00323     break;
00324   case CELL_STRUCTURE_DOMDEC:
00325     dd_exchange_and_sort_particles(global_flag);
00326     break;
00327   }
00328 
00329 #ifdef ADDITIONAL_CHECKS
00330   /* at the end of the day, everything should be consistent again */
00331   check_particle_consistency();
00332 #endif
00333 
00334   ghost_communicator(&cell_structure.ghost_cells_comm);
00335   ghost_communicator(&cell_structure.exchange_ghosts_comm);
00336 
00337   resort_particles = 0;
00338   rebuild_verletlist = 1;
00339 
00340   on_resort_particles();
00341 
00342   CELL_TRACE(fprintf(stderr, "%d: leaving cells_resort_particles\n", this_node));
00343 }
00344 
00345 /*************************************************/
00346 
00347 void cells_on_geometry_change(int flags)
00348 {
00349   if (max_cut > 0.0) {
00350     if (skin >= 0.0)
00351       max_range = max_cut + skin;
00352     else
00353       /* if the skin is not yet set, assume zero. */
00354       max_range = max_cut;
00355   }
00356   else
00357     /* if no interactions yet, we also don't need a skin */
00358     max_range = 0.0;
00359 
00360   CELL_TRACE(fprintf(stderr,"%d: on_geometry_change with max range %f\n", this_node, max_range));
00361 
00362   switch (cell_structure.type) {
00363   case CELL_STRUCTURE_DOMDEC:
00364     dd_on_geometry_change(flags);
00365     break;
00366   case CELL_STRUCTURE_LAYERED:
00367     /* there is no fast version, always redo everything. */
00368     cells_re_init(CELL_STRUCTURE_LAYERED);
00369     break;
00370   case CELL_STRUCTURE_NSQUARE:
00371     /* this cell system doesn't need to react, just tell
00372        the others */
00373     on_boxl_change();
00374     break;
00375   }
00376 }
00377 
00378 /*************************************************/
00379 
00380 void check_resort_particles()
00381 {
00382   int i, c, np;
00383   Cell *cell;
00384   Particle *p;
00385   double skin2 = SQR(skin/2.0);
00386 
00387   for (c = 0; c < local_cells.n; c++) {
00388     cell = local_cells.cell[c];
00389     p  = cell->part;
00390     np = cell->n;
00391     for(i = 0; i < np; i++) {
00392       /* Verlet criterion check */
00393       if(distance2(p[i].r.p, p[i].l.p_old) > skin2) resort_particles = 1;
00394     }
00395   }
00396   announce_resort_particles();
00397 }
00398 
00399 /*************************************************/
00400 void cells_update_ghosts()
00401 {
00402   /* if dd.use_vList is set, it so far means we want EXACT sorting of the particles.*/
00403   if (dd.use_vList == 0)
00404     resort_particles = 1;
00405 
00406   if (resort_particles) {
00407     /* Communication step:  number of ghosts and ghost information */
00408     cells_resort_particles(CELL_NEIGHBOR_EXCHANGE);
00409   }
00410   else
00411     /* Communication step: ghost information */
00412     ghost_communicator(&cell_structure.update_ghost_pos_comm);
00413 }
00414 
00415 /*************************************************/
00416 
00417 void print_ghost_positions()
00418 {
00419   Cell *cell;
00420   int c,i,np,cnt=0;
00421   Particle *part;
00422 
00423   for (c = 0; c < ghost_cells.n; c++) {
00424     cell = ghost_cells.cell[c];
00425     part = cell->part;
00426     np   = cell->n;
00427     for(i=0 ; i < np; i++) {
00428       fprintf(stderr,"%d: local cell %d contains ghost id=%d pos=(%f,%f,%f)\n",
00429               this_node, c, part[i].p.identity,
00430               part[i].r.p[0], part[i].r.p[1], part[i].r.p[2]);
00431       cnt++;
00432     }
00433   }
00434   fprintf(stderr,"%d: found %d ghosts\n",this_node,cnt);
00435 }