ESPResSo 3.2.0-11-g9950804-git
Extensible Simulation Package for Soft Matter Research
layered.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 layered.c
00022     Implementation of \ref layered.h "layered.h".
00023  */
00024 #include <mpi.h>
00025 #include <string.h>
00026 #include "utils.h"
00027 #include "cells.h"
00028 #include "integrate.h"
00029 #include "layered.h"
00030 #include "global.h"
00031 #include "communication.h"
00032 #include "ghosts.h"
00033 #include "forces.h"
00034 #include "pressure.h"
00035 #include "energy.h"
00036 #include "constraint.h"
00037 #include "domain_decomposition.h"
00038 
00039 /* Organization: Layers only in one direction.
00040    ghost_bottom
00041    c1
00042    c2
00043    c3
00044    .
00045    .
00046    .
00047    cn
00048    ghost_top
00049 
00050    First, all nodes send downwards, then upwards. Within these actions,
00051    first the odd nodes send. For even n_nodes, this algorithm is straight
00052    forward: first the odd nodes send, the even receive, then vice versa.
00053    For odd n_nodes, we have
00054    1) 1->2 3->4 5->1
00055    2) 2->3 4->5
00056    So in the first round node 5 has to wait for node 1 to
00057    complete the send and get ready to receive. In other words,
00058    what physically happens is:
00059    1) 1->2 3->4 5->*
00060    2) *->1 2->3 4->*
00061    3) *->5
00062    This means that one pending receive has to be done in addition
00063    provided that all other transmissions can happen in parallel.
00064 
00065 */
00066 
00067 /** wether we are the lowest node */
00068 #define LAYERED_BOTTOM 1
00069 /** wether we are the highest node */
00070 #define LAYERED_TOP    2
00071 /** same as PERIODIC(2) */
00072 #define LAYERED_PERIODIC 4
00073 #define LAYERED_BTM_MASK (LAYERED_BOTTOM|LAYERED_PERIODIC)
00074 #define LAYERED_TOP_MASK (LAYERED_TOP|LAYERED_PERIODIC)
00075 /** node has a neighbor above (modulo n_nodes) */
00076 #define LAYERED_TOP_NEIGHBOR ((layered_flags & LAYERED_TOP_MASK) != LAYERED_TOP)
00077 /** node has a neighbor below (modulo n_nodes) */
00078 #define LAYERED_BTM_NEIGHBOR ((layered_flags & LAYERED_BTM_MASK) != LAYERED_BOTTOM)
00079 
00080 int layered_flags = 0;
00081 int n_layers = -1, determine_n_layers = 1;
00082 double layer_h = 0, layer_h_i = 0;
00083 
00084 static int btm, top;
00085 
00086 void layered_get_mi_vector(double res[3], double a[3], double b[3])
00087 {
00088   int i;
00089 
00090   for(i=0;i<2;i++) {
00091     res[i] = a[i] - b[i];
00092 #ifdef PARTIAL_PERIODIC
00093     if (PERIODIC(i))
00094 #endif
00095       res[i] -= dround(res[i]*box_l_i[i])*box_l[i];
00096   }
00097   res[2] = a[2] - b[2];
00098 }
00099 
00100 Cell *layered_position_to_cell(double pos[3])
00101 {
00102   int cpos = (int)((pos[2] - my_left[2])*layer_h_i) + 1;
00103   if (cpos < 1) {
00104     if (!LAYERED_BTM_NEIGHBOR)
00105       cpos = 1;
00106     else
00107       return NULL;
00108   }
00109   else if (cpos > n_layers) {
00110     /* not periodic, but at top */
00111     if (!LAYERED_TOP_NEIGHBOR)
00112       cpos = n_layers;
00113     else
00114       return NULL;
00115   }
00116   return &(cells[cpos]);
00117 }
00118 
00119 void layered_topology_release()
00120 {
00121   CELL_TRACE(fprintf(stderr,"%d: layered_topology_release:\n", this_node));
00122   free_comm(&cell_structure.ghost_cells_comm);
00123   free_comm(&cell_structure.exchange_ghosts_comm);
00124   free_comm(&cell_structure.update_ghost_pos_comm);
00125   free_comm(&cell_structure.collect_ghost_force_comm);
00126 }
00127 
00128 static void layered_prepare_comm(GhostCommunicator *comm, int data_parts)
00129 {
00130   int even_odd;
00131   int c, n;
00132 
00133   if (n_nodes > 1) {
00134     /* more than one node => no local transfers */
00135 
00136     /* how many communications to do: up even/odd, down even/odd */
00137     n = 4;
00138     /* one communication missing if not periodic but on border */
00139     if (!LAYERED_TOP_NEIGHBOR)
00140       n -= 2;
00141     if (!LAYERED_BTM_NEIGHBOR)
00142       n -= 2;
00143 
00144     prepare_comm(comm, data_parts, n);
00145 
00146     /* always sending/receiving 1 cell per time step */
00147     for(c = 0; c < n; c++) {
00148       comm->comm[c].part_lists = malloc(sizeof(ParticleList *));
00149       comm->comm[c].n_part_lists = 1;
00150       comm->comm[c].mpi_comm = comm_cart;
00151     }
00152 
00153     c = 0;
00154 
00155     CELL_TRACE(fprintf(stderr, "%d: ghostrec new comm of size %d\n", this_node, n));
00156     /* downwards */
00157     for (even_odd = 0; even_odd < 2; even_odd++) {
00158       /* send */
00159       if (this_node % 2 == even_odd && LAYERED_BTM_NEIGHBOR) {
00160         comm->comm[c].type = GHOST_SEND;
00161         /* round 1 uses prefetched data and stores delayed data */
00162         if (c == 1)
00163           comm->comm[c].type |= GHOST_PREFETCH | GHOST_PSTSTORE;
00164         comm->comm[c].node = btm;
00165         if (data_parts == GHOSTTRANS_FORCE) {
00166           comm->comm[c].part_lists[0] = &cells[0];
00167           CELL_TRACE(fprintf(stderr, "%d: ghostrec send force to %d btmg\n", this_node, btm));
00168         }
00169         else {
00170           comm->comm[c].part_lists[0] = &cells[1];
00171 
00172           /* if periodic and bottom or top, send shifted */
00173           comm->comm[c].shift[0] = comm->comm[c].shift[1] = 0;
00174           if (((layered_flags & LAYERED_BTM_MASK) == LAYERED_BTM_MASK) &&
00175               (data_parts & GHOSTTRANS_POSITION)) {
00176             comm->data_parts |= GHOSTTRANS_POSSHFTD;
00177             comm->comm[c].shift[2] = box_l[2];
00178           }
00179           else
00180             comm->comm[c].shift[2] = 0;
00181           CELL_TRACE(fprintf(stderr, "%d: ghostrec send to %d shift %f btml\n", this_node, btm, comm->comm[c].shift[2]));
00182         }
00183         c++;
00184       }
00185       /* recv. Note we test r_node as we always have to test the sender
00186          as for odd n_nodes maybe we send AND receive. */
00187       if (top % 2 == even_odd && LAYERED_TOP_NEIGHBOR) {
00188         comm->comm[c].type = GHOST_RECV;
00189         /* round 0 prefetch send for round 1 and delay recvd data processing */
00190         if (c == 0)
00191           comm->comm[c].type |= GHOST_PREFETCH | GHOST_PSTSTORE;
00192         comm->comm[c].node = top;
00193         if (data_parts == GHOSTTRANS_FORCE) {
00194           comm->comm[c].part_lists[0] = &cells[n_layers];
00195           CELL_TRACE(fprintf(stderr, "%d: ghostrec get force from %d topl\n", this_node, top));
00196         }
00197         else {
00198           comm->comm[c].part_lists[0] = &cells[n_layers + 1];
00199           CELL_TRACE(fprintf(stderr, "%d: ghostrec recv from %d topg\n", this_node, top));
00200         }
00201         c++;
00202       }
00203     }
00204 
00205     CELL_TRACE(fprintf(stderr, "%d: ghostrec upwards\n", this_node));
00206     /* upwards */
00207     for (even_odd = 0; even_odd < 2; even_odd++) {
00208       /* send */
00209       if (this_node % 2 == even_odd && LAYERED_TOP_NEIGHBOR) {
00210         comm->comm[c].type = GHOST_SEND;
00211         /* round 1 use prefetched data from round 0.
00212            But this time there may already have been two transfers downwards */
00213         if (c % 2 == 1)
00214           comm->comm[c].type |= GHOST_PREFETCH | GHOST_PSTSTORE;
00215         comm->comm[c].node = top;
00216         if (data_parts == GHOSTTRANS_FORCE) {
00217           comm->comm[c].part_lists[0] = &cells[n_layers + 1];
00218           CELL_TRACE(fprintf(stderr, "%d: ghostrec send force to %d topg\n", this_node, top));
00219         }
00220         else {
00221           comm->comm[c].part_lists[0] = &cells[n_layers];
00222 
00223           /* if periodic and bottom or top, send shifted */
00224           comm->comm[c].shift[0] = comm->comm[c].shift[1] = 0;
00225           if (((layered_flags & LAYERED_TOP_MASK) == LAYERED_TOP_MASK) &&
00226               (data_parts & GHOSTTRANS_POSITION)) {
00227             comm->data_parts |= GHOSTTRANS_POSSHFTD;
00228             comm->comm[c].shift[2] = -box_l[2];
00229           }
00230           else
00231             comm->comm[c].shift[2] = 0;
00232           CELL_TRACE(fprintf(stderr, "%d: ghostrec send to %d shift %f topl\n", this_node, top, comm->comm[c].shift[2]));
00233         }
00234         c++;
00235       }
00236       /* recv. Note we test r_node as we always have to test the sender
00237          as for odd n_nodes maybe we send AND receive. */
00238       if (btm % 2 == even_odd && LAYERED_BTM_NEIGHBOR) {
00239         comm->comm[c].type = GHOST_RECV;
00240         /* round 0 prefetch. But this time there may already have been two transfers downwards */
00241         if (c % 2 == 0)
00242           comm->comm[c].type |= GHOST_PREFETCH | GHOST_PSTSTORE;
00243         comm->comm[c].node = btm;
00244         if (data_parts == GHOSTTRANS_FORCE) {
00245           comm->comm[c].part_lists[0] = &cells[1];
00246           CELL_TRACE(fprintf(stderr, "%d: ghostrec get force from %d btml\n", this_node, btm));
00247         }
00248         else {
00249           comm->comm[c].part_lists[0] = &cells[0];
00250           CELL_TRACE(fprintf(stderr, "%d: ghostrec recv from %d btmg\n", this_node, btm));
00251         }
00252         c++;
00253       }
00254     }
00255   }
00256   else {
00257     /* one node => local transfers, either 2 (up and down, periodic) or zero*/
00258 
00259     n = (layered_flags & LAYERED_PERIODIC) ? 2 : 0;
00260 
00261     prepare_comm(comm, data_parts, n);
00262 
00263     if (n != 0) {
00264       /* two cells: from and to */
00265       for(c = 0; c < n; c++) {
00266         comm->comm[c].part_lists = malloc(2*sizeof(ParticleList *));
00267         comm->comm[c].n_part_lists = 2;
00268         comm->comm[c].mpi_comm = comm_cart;
00269         comm->comm[c].node = this_node;
00270       }
00271 
00272       c = 0;
00273 
00274       /* downwards */
00275       comm->comm[c].type = GHOST_LOCL;
00276       if (data_parts == GHOSTTRANS_FORCE) {
00277         comm->comm[c].part_lists[0] = &cells[0];
00278         comm->comm[c].part_lists[1] = &cells[n_layers];
00279       }
00280       else {
00281         comm->comm[c].part_lists[0] = &cells[1];
00282         comm->comm[c].part_lists[1] = &cells[n_layers + 1];
00283         /* here it is periodic */
00284         if (data_parts & GHOSTTRANS_POSITION)
00285           comm->data_parts |= GHOSTTRANS_POSSHFTD;
00286         comm->comm[c].shift[0] = comm->comm[c].shift[1] = 0;
00287         comm->comm[c].shift[2] = box_l[2];
00288       }
00289       c++;
00290 
00291       /* upwards */
00292       comm->comm[c].type = GHOST_LOCL;
00293       if (data_parts == GHOSTTRANS_FORCE) {
00294         comm->comm[c].part_lists[0] = &cells[n_layers + 1];
00295         comm->comm[c].part_lists[1] = &cells[1];
00296       }
00297       else {
00298         comm->comm[c].part_lists[0] = &cells[n_layers];
00299         comm->comm[c].part_lists[1] = &cells[0];
00300         /* here it is periodic */
00301         if (data_parts & GHOSTTRANS_POSITION)
00302           comm->data_parts |= GHOSTTRANS_POSSHFTD;
00303         comm->comm[c].shift[0] = comm->comm[c].shift[1] = 0;
00304         comm->comm[c].shift[2] = -box_l[2];
00305       }
00306     }
00307   }
00308 }
00309 
00310 void layered_topology_init(CellPList *old)
00311 {
00312   Particle *part;
00313   int c, p, np;
00314 
00315   CELL_TRACE(fprintf(stderr, "%d: layered_topology_init, %d old particle lists\n", this_node, old->n));
00316 
00317   cell_structure.type = CELL_STRUCTURE_LAYERED;
00318   cell_structure.position_to_node = map_position_node_array;
00319   cell_structure.position_to_cell = layered_position_to_cell;
00320 
00321   /* check node grid. All we can do is 1x1xn. */
00322   if (node_grid[0] != 1 || node_grid[1] != 1) {
00323     char *errtxt = runtime_error(128 + ES_INTEGER_SPACE);
00324     ERROR_SPRINTF(errtxt, "{016 selected node grid is not suitable for layered cell structure (needs 1x1x%d grid)} ", n_nodes);
00325     node_grid[0] = node_grid[1] = 1;
00326     node_grid[2] = n_nodes;
00327   }
00328 
00329   if (this_node == 0 && determine_n_layers) {
00330     if (max_range > 0) {
00331       n_layers = (int)floor(local_box_l[2]/max_range);
00332       if (n_layers < 1) {
00333         char *errtxt = runtime_error(128 + 2*ES_DOUBLE_SPACE);
00334         ERROR_SPRINTF(errtxt, "{017 layered: maximal interaction range %g larger than local box length %g} ", max_range, local_box_l[2]);
00335         n_layers = 1;
00336       }
00337       if (n_layers > max_num_cells - 2)
00338         n_layers = imax(max_num_cells - 2, 0);
00339     }
00340     else
00341       n_layers = 1;
00342   }
00343   MPI_Bcast(&n_layers, 1, MPI_INT, 0, comm_cart);
00344 
00345   top = this_node + 1;
00346   if (top == n_nodes && (layered_flags & LAYERED_PERIODIC))
00347     top = 0;
00348   btm = this_node - 1;
00349   if (btm == -1 && (layered_flags & LAYERED_PERIODIC))
00350     btm = n_nodes - 1;
00351 
00352   layer_h = local_box_l[2]/(double)(n_layers);
00353   layer_h_i = 1/layer_h;
00354 
00355   if (layer_h < max_range) {
00356     char *errtxt = runtime_error(128 + 2*ES_DOUBLE_SPACE);
00357     ERROR_SPRINTF(errtxt, "{018 layered: maximal interaction range %g larger than layer height %g} ", max_range, layer_h);
00358   }
00359 
00360   /* check wether node is top and/or bottom */
00361   layered_flags = 0;
00362   if (this_node == 0)
00363     layered_flags |= LAYERED_BOTTOM;
00364   if (this_node == n_nodes - 1)
00365     layered_flags |= LAYERED_TOP;
00366 
00367   if (PERIODIC(2))
00368     layered_flags |= LAYERED_PERIODIC;
00369 
00370   CELL_TRACE(fprintf(stderr, "%d: layered_flags tn %d bn %d \n", this_node, LAYERED_TOP_NEIGHBOR, LAYERED_BTM_NEIGHBOR));
00371 
00372   /* allocate cells and mark them */
00373   realloc_cells(n_layers + 2);
00374   realloc_cellplist(&local_cells, local_cells.n = n_layers);
00375   for (c = 0; c < n_layers; c++)
00376     local_cells.cell[c] = &cells[c + 1];
00377   realloc_cellplist(&ghost_cells, ghost_cells.n = 2);
00378   ghost_cells.cell[0] = &cells[0];
00379   ghost_cells.cell[1] = &cells[n_layers + 1];
00380 
00381   /* create communicators */
00382   layered_prepare_comm(&cell_structure.ghost_cells_comm,         GHOSTTRANS_PARTNUM);
00383   layered_prepare_comm(&cell_structure.exchange_ghosts_comm,     GHOSTTRANS_PROPRTS | GHOSTTRANS_POSITION);
00384   layered_prepare_comm(&cell_structure.update_ghost_pos_comm,    GHOSTTRANS_POSITION);
00385   layered_prepare_comm(&cell_structure.collect_ghost_force_comm, GHOSTTRANS_FORCE);
00386 
00387   /* copy particles */
00388   for (c = 0; c < old->n; c++) {
00389     part = old->cell[c]->part;
00390     np   = old->cell[c]->n;
00391     for (p = 0; p < np; p++) {
00392       Cell *nc = layered_position_to_cell(part[p].r.p);
00393       /* particle does not belong to this node. Just stow away
00394          somewhere for the moment */
00395       if (nc == NULL)
00396         nc = local_cells.cell[0];
00397       append_unindexed_particle(nc, &part[p]);
00398     }
00399   }
00400   for (c = 1; c <= n_layers; c++)
00401     update_local_particles(&cells[c]);
00402 
00403   CELL_TRACE(fprintf(stderr, "%d: layered_topology_init done\n", this_node));
00404 }
00405  
00406 static void layered_append_particles(ParticleList *pl, ParticleList *up, ParticleList *dn)
00407 {
00408   int p;
00409 
00410   CELL_TRACE(fprintf(stderr, "%d: sorting in %d\n", this_node, pl->n));
00411   for(p = 0; p < pl->n; p++) {
00412     fold_position(pl->part[p].r.p, pl->part[p].l.i);
00413     if (LAYERED_BTM_NEIGHBOR && pl->part[p].r.p[2] < my_left[2]) {
00414       CELL_TRACE(fprintf(stderr, "%d: leaving part %d for node below\n", this_node, pl->part[p].p.identity));
00415       move_indexed_particle(dn, pl, p);
00416     }
00417     else if (LAYERED_TOP_NEIGHBOR && pl->part[p].r.p[2] >= my_right[2]) {
00418       CELL_TRACE(fprintf(stderr, "%d: leaving part %d for node above\n", this_node, pl->part[p].p.identity));
00419       move_indexed_particle(up, pl, p);
00420     }
00421     else
00422       move_indexed_particle(layered_position_to_cell(pl->part[p].r.p), pl, p);
00423     /* same particle again, as this is now a new one */
00424     if (p < pl->n) p--;
00425   }
00426   CELL_TRACE(fprintf(stderr, "%d: left over %d\n", this_node, pl->n));
00427 }
00428 
00429 void layered_exchange_and_sort_particles(int global_flag)
00430 {
00431   Particle *part;
00432   Cell *nc, *oc;
00433   int c, p, flag, redo;
00434   ParticleList send_buf_dn, send_buf_up;
00435   ParticleList recv_buf;
00436 
00437   CELL_TRACE(fprintf(stderr, "%d:layered exchange and sort %d\n", this_node, global_flag));
00438 
00439   init_particlelist(&send_buf_dn);
00440   init_particlelist(&send_buf_up);
00441 
00442   init_particlelist(&recv_buf);
00443 
00444   /* sort local particles */
00445   for (c = 1; c <= n_layers; c++) {
00446     oc = &cells[c];
00447 
00448     for (p = 0; p < oc->n; p++) {
00449       part = &oc->part[p];
00450 
00451       if (n_nodes != 1 && LAYERED_BTM_NEIGHBOR && part->r.p[2] < my_left[2]) {
00452         CELL_TRACE(fprintf(stderr, "%d: send part %d down\n", this_node, part->p.identity));
00453         move_indexed_particle(&send_buf_dn, oc, p);
00454         if (p < oc->n) p--;
00455       }
00456       else if (n_nodes != 1 && LAYERED_TOP_NEIGHBOR && part->r.p[2] >= my_right[2]) {
00457         CELL_TRACE(fprintf(stderr, "%d: send part %d up\n", this_node, part->p.identity));
00458         move_indexed_particle(&send_buf_up, oc, p);
00459         if (p < oc->n) p--;
00460       }
00461       else {
00462         /* particle stays here. Fold anyways to get x,y correct */
00463         fold_position(part->r.p, part->l.i);
00464         nc = layered_position_to_cell(part->r.p);
00465         if (nc != oc) {
00466           move_indexed_particle(nc, oc, p);
00467           if (p < oc->n) p--;
00468         }
00469       }
00470     }
00471   }
00472 
00473   for (;;) {
00474     /* transfer */
00475     if (n_nodes > 1) {
00476       if (this_node % 2 == 0) {
00477         /* send down */
00478         if (LAYERED_BTM_NEIGHBOR) {
00479           CELL_TRACE(fprintf(stderr,"%d: send dn\n",this_node));
00480           send_particles(&send_buf_dn, btm);
00481         }
00482         if (LAYERED_TOP_NEIGHBOR) {
00483           CELL_TRACE(fprintf(stderr,"%d: recv up\n",this_node));
00484           recv_particles(&recv_buf, top);
00485         }
00486         /* send up */
00487         if (LAYERED_TOP_NEIGHBOR) {
00488           CELL_TRACE(fprintf(stderr,"%d: send up\n",this_node));
00489           send_particles(&send_buf_up, top);
00490         }
00491         if (LAYERED_BTM_NEIGHBOR) {
00492           CELL_TRACE(fprintf(stderr,"%d: recv dn\n",this_node));
00493           recv_particles(&recv_buf, btm);
00494         }
00495       }
00496       else {
00497         if (LAYERED_TOP_NEIGHBOR) {
00498           CELL_TRACE(fprintf(stderr,"%d: recv up\n",this_node));
00499           recv_particles(&recv_buf, top);
00500         }
00501         if (LAYERED_BTM_NEIGHBOR) {
00502           CELL_TRACE(fprintf(stderr,"%d: send dn\n",this_node));
00503           send_particles(&send_buf_dn, btm);
00504         }
00505         if (LAYERED_BTM_NEIGHBOR) {
00506           CELL_TRACE(fprintf(stderr,"%d: recv dn\n",this_node));
00507           recv_particles(&recv_buf, btm);
00508         }
00509         if (LAYERED_TOP_NEIGHBOR) {
00510           CELL_TRACE(fprintf(stderr,"%d: send up\n",this_node));
00511           send_particles(&send_buf_up, top);
00512         }
00513       }
00514     }
00515 #ifdef ADDITIONAL_CHECKS
00516     else {
00517       if (recv_buf.n != 0 || send_buf_dn.n != 0 || send_buf_up.n != 0) {
00518         fprintf(stderr, "1 node but transfer buffers are not empty. send up %d, down %d, recv %d\n",
00519                 send_buf_up.n, send_buf_dn.n, recv_buf.n);
00520         errexit();
00521       }
00522     }
00523 #endif
00524     layered_append_particles(&recv_buf, &send_buf_up, &send_buf_dn);
00525 
00526     /* handshake redo */
00527     flag = (send_buf_up.n != 0 || send_buf_dn.n != 0);
00528     
00529     CELL_TRACE(if (flag) fprintf(stderr, "%d: requesting another exchange round\n", this_node));
00530 
00531     if (global_flag == CELL_GLOBAL_EXCHANGE) {
00532       MPI_Allreduce(&flag, &redo, 1, MPI_INT, MPI_MAX, comm_cart);
00533       if (!redo)
00534         break;
00535       CELL_TRACE(fprintf(stderr, "%d: another exchange round\n", this_node));
00536     }
00537     else {
00538       if (flag) {
00539         char *errtxt = runtime_error(128 + ES_DOUBLE_SPACE);
00540         ERROR_SPRINTF(errtxt,"{019 layered_exchange_and_sort_particles: particle moved more than one cell} ");
00541 
00542         /* sort left over particles into border cells */
00543         CELL_TRACE(fprintf(stderr, "%d: emergency sort\n", this_node));
00544         while (send_buf_up.n > 0)
00545           move_indexed_particle(&cells[1], &send_buf_up, 0);
00546         while (send_buf_dn.n > 0)
00547           move_indexed_particle(&cells[n_layers], &send_buf_dn, 0);
00548       }
00549       break;
00550     }
00551   }
00552 
00553   realloc_particlelist(&recv_buf, 0);
00554 }
00555 
00556 /** nonbonded and bonded force calculation using the verlet list */
00557 void layered_calculate_ia()
00558 {
00559   int c, i, j;
00560   Cell  *celll, *cellb;
00561   int      npl,    npb;
00562   Particle *pl,    *pb, *p1;
00563   double dist2, d[3];
00564  
00565   CELL_TRACE(fprintf(stderr, "%d: rebuild_v=%d\n", this_node, rebuild_verletlist));
00566 
00567   for (c = 1; c <= n_layers; c++) {
00568     celll = &cells[c];
00569     pl    = celll->part;
00570     npl   = celll->n;
00571 
00572     cellb = &cells[c-1];
00573     pb    = cellb->part;
00574     npb   = cellb->n;
00575 
00576     for(i = 0; i < npl; i++) {
00577       p1 = &pl[i];
00578 
00579       if (rebuild_verletlist)
00580         memcpy(p1->l.p_old, p1->r.p, 3*sizeof(double));
00581 
00582       add_bonded_force(p1);
00583 #ifdef CONSTRAINTS
00584       add_constraints_forces(p1);
00585 #endif
00586 
00587       /* cell itself and bonded / constraints */
00588       for(j = i+1; j < npl; j++) {
00589         layered_get_mi_vector(d, p1->r.p, pl[j].r.p);
00590         dist2 = sqrlen(d);
00591 #ifdef EXCLUSIONS
00592         if (do_nonbonded(p1, &pl[j]))
00593 #endif
00594           add_non_bonded_pair_force(p1, &pl[j], d, sqrt(dist2), dist2);
00595       }
00596 
00597       /* bottom neighbor */
00598       for(j = 0; j < npb; j++) {
00599         layered_get_mi_vector(d, p1->r.p, pb[j].r.p);
00600         dist2 = sqrlen(d);
00601 #ifdef EXCLUSIONS
00602         if (do_nonbonded(p1, &pb[j]))
00603 #endif
00604           add_non_bonded_pair_force(p1, &pb[j], d, sqrt(dist2), dist2);
00605       }
00606     }
00607   }
00608   rebuild_verletlist = 0;
00609 }
00610 
00611 void layered_calculate_energies()
00612 {
00613   int c, i, j;
00614   Cell  *celll, *cellb;
00615   int      npl,    npb;
00616   Particle *pl,    *pb, *p1;
00617   double dist2, d[3];
00618  
00619   CELL_TRACE(fprintf(stderr, "%d: rebuild_v=%d\n", this_node, rebuild_verletlist));
00620 
00621   for (c = 1; c <= n_layers; c++) {
00622     celll = &cells[c];
00623     pl    = celll->part;
00624     npl   = celll->n;
00625 
00626     cellb = &cells[c-1];
00627     pb    = cellb->part;
00628     npb   = cellb->n;
00629 
00630     for(i = 0; i < npl; i++) {
00631       p1 = &pl[i];
00632 
00633       if (rebuild_verletlist)
00634         memcpy(p1->l.p_old, p1->r.p, 3*sizeof(double));
00635 
00636       add_kinetic_energy(p1);
00637 
00638       add_bonded_energy(p1);
00639 #ifdef CONSTRAINTS
00640       add_constraints_energy(p1);
00641 #endif
00642 
00643       /* cell itself and bonded / constraints */
00644       for(j = i+1; j < npl; j++) {
00645         layered_get_mi_vector(d, p1->r.p, pl[j].r.p);
00646         dist2 = sqrlen(d);
00647 #ifdef EXCLUSIONS
00648         if (do_nonbonded(p1, &pl[j]))
00649 #endif
00650           add_non_bonded_pair_energy(p1, &pl[j], d, sqrt(dist2), dist2);
00651       }
00652 
00653       /* bottom neighbor */
00654       for(j = 0; j < npb; j++) {
00655         layered_get_mi_vector(d, p1->r.p, pb[j].r.p);
00656         dist2 = sqrlen(d);
00657 #ifdef EXCLUSIONS
00658         if (do_nonbonded(p1, &pb[j]))
00659 #endif
00660           add_non_bonded_pair_energy(p1, &pb[j], d, sqrt(dist2), dist2);
00661       }
00662     }
00663   }
00664   rebuild_verletlist = 0;
00665 }
00666 
00667 void layered_calculate_virials(int v_comp)
00668 {
00669   int c, i, j;
00670   Cell  *celll, *cellb;
00671   int      npl,    npb;
00672   Particle *pl,    *pb, *p1;
00673   double dist2, d[3];
00674  
00675   for (c = 1; c <= n_layers; c++) {
00676     celll = &cells[c];
00677     pl    = celll->part;
00678     npl   = celll->n;
00679 
00680     cellb = &cells[c-1];
00681     pb    = cellb->part;
00682     npb   = cellb->n;
00683 
00684     for(i = 0; i < npl; i++) {
00685       p1 = &pl[i];
00686 
00687       if (rebuild_verletlist)
00688         memcpy(p1->l.p_old, p1->r.p, 3*sizeof(double));
00689 
00690       add_kinetic_virials(p1,v_comp);
00691 
00692       add_bonded_virials(p1);
00693 #ifdef BOND_ANGLE_OLD
00694       add_three_body_bonded_stress(p1);
00695 #endif
00696 #ifdef BOND_ANGLE
00697       add_three_body_bonded_stress(p1);
00698 #endif
00699 
00700       /* cell itself and bonded / constraints */
00701       for(j = i+1; j < npl; j++) {
00702         layered_get_mi_vector(d, p1->r.p, pl[j].r.p);
00703         dist2 = sqrlen(d);
00704 #ifdef EXCLUSIONS
00705         if (do_nonbonded(p1, &pl[j]))
00706 #endif
00707           add_non_bonded_pair_virials(p1, &pl[j], d, sqrt(dist2), dist2);
00708       }
00709 
00710       /* bottom neighbor */
00711       for(j = 0; j < npb; j++) {
00712         layered_get_mi_vector(d, p1->r.p, pb[j].r.p);
00713         dist2 = sqrlen(d);
00714 #ifdef EXCLUSIONS
00715         if (do_nonbonded(p1, &pb[j]))
00716 #endif
00717           add_non_bonded_pair_virials(p1, &pb[j], d, sqrt(dist2), dist2);
00718       }
00719     }
00720   }
00721   rebuild_verletlist = 0;
00722 }