ESPResSo 3.2.0-11-g9950804-git
Extensible Simulation Package for Soft Matter Research
iccp3m.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 
00022 /** \file iccp3m.c
00023     Detailed Information about the method is included in the corresponding header file \ref iccp3m.h.
00024 
00025  */
00026 #include <stdlib.h>
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include <stddef.h>
00030 #include <math.h>
00031 #include <time.h>
00032 
00033 #include "iccp3m.h"
00034 #include "p3m.h"
00035 #include "elc.h"
00036 #include "mmm2d.h"
00037 #include "mmm1d.h"
00038 
00039 #include "communication.h"
00040 
00041 #include "utils.h"
00042 #include "verlet.h"
00043 #include "cells.h"
00044 #include "particle_data.h"
00045 #include "interaction_data.h"
00046 #include "domain_decomposition.h"
00047 #include "verlet.h"
00048 #include "forces.h"
00049 #include "config.h"
00050 #include "global.h"
00051 
00052 #ifdef ELECTROSTATICS
00053 
00054 iccp3m_struct iccp3m_cfg;
00055 
00056 int iccp3m_initialized = 0;
00057 /* functions that are used in icc* to compute the electric field acting on the induced charges,
00058  * excluding forces other than the electrostatic ones */
00059 void init_forces_iccp3m();
00060 void calc_long_range_forces_iccp3m();
00061 MDINLINE void add_pair_iccp3m(PairList *pl, Particle *p1, Particle *p2);
00062 void resize_verlet_list_iccp3m(PairList *pl);
00063 MDINLINE void init_local_particle_force_iccp3m(Particle *part);
00064 MDINLINE void init_ghost_force_iccp3m(Particle *part);
00065 extern void on_particle_change();
00066 
00067 Cell *local_icc;
00068 CellPList me_do_ghosts_icc;
00069 
00070 /* other icc*  functions */
00071 int imod(int x,int y);
00072 void iccp3m_revive_forces();
00073 void iccp3m_store_forces();
00074 
00075 /** Granularity of the verlet list */
00076 #define LIST_INCREMENT 20
00077 
00078 void iccp3m_init(void){
00079    iccp3m_cfg.set_flag=0;
00080    iccp3m_cfg.areas = NULL;
00081    iccp3m_cfg.ein = NULL;
00082    iccp3m_cfg.nvectorx = NULL;
00083    iccp3m_cfg.nvectory = NULL;
00084    iccp3m_cfg.nvectorz = NULL;
00085    iccp3m_cfg.extx = 0;
00086    iccp3m_cfg.exty = 0;
00087    iccp3m_cfg.extz = 0;
00088 }
00089 
00090 
00091 
00092 int bcast_iccp3m_cfg(void){
00093   int i;
00094 
00095 
00096   MPI_Bcast((int*)&iccp3m_cfg.n_ic, 1, MPI_INT, 0, comm_cart); 
00097 
00098   /* allocates Memory on slave nodes 
00099    * Master node allocates the memory when parsing tcl arguments
00100    * */
00101   if (this_node != 0) {
00102     iccp3m_cfg.areas      = (double*) realloc (iccp3m_cfg.areas     ,(iccp3m_cfg.n_ic) * sizeof(double));
00103     iccp3m_cfg.ein        = (double*) realloc (iccp3m_cfg.ein       ,(iccp3m_cfg.n_ic) * sizeof(double));
00104     iccp3m_cfg.nvectorx   = (double*) realloc (iccp3m_cfg.nvectorx  ,(iccp3m_cfg.n_ic) * sizeof(double));
00105     iccp3m_cfg.nvectory   = (double*) realloc (iccp3m_cfg.nvectory  ,(iccp3m_cfg.n_ic) * sizeof(double));
00106     iccp3m_cfg.nvectorz   = (double*) realloc (iccp3m_cfg.nvectorz  ,(iccp3m_cfg.n_ic) * sizeof(double));
00107   }
00108 
00109   MPI_Bcast((int*)&iccp3m_cfg.num_iteration, 1, MPI_INT, 0, comm_cart); 
00110   MPI_Bcast((double*)&iccp3m_cfg.convergence, 1, MPI_DOUBLE, 0, comm_cart);
00111   MPI_Bcast((double*)&iccp3m_cfg.eout, 1, MPI_DOUBLE, 0, comm_cart);
00112   MPI_Bcast((double*)&iccp3m_cfg.relax, 1, MPI_DOUBLE, 0, comm_cart);
00113   
00114   /* broadcast the vectors element by element. This is slow
00115    * but safe and only performed at the beginning of each simulation*/
00116   for ( i = 0; i < iccp3m_cfg.n_ic; i++) {
00117     MPI_Bcast((double*)&iccp3m_cfg.areas[i], 1, MPI_DOUBLE, 0, comm_cart);
00118     MPI_Bcast((double*)&iccp3m_cfg.ein[i], 1, MPI_DOUBLE, 0, comm_cart);
00119     MPI_Bcast((double*)&iccp3m_cfg.nvectorx[i], 1, MPI_DOUBLE, 0, comm_cart);
00120     MPI_Bcast((double*)&iccp3m_cfg.nvectory[i], 1, MPI_DOUBLE, 0, comm_cart);
00121     MPI_Bcast((double*)&iccp3m_cfg.nvectorz[i], 1, MPI_DOUBLE, 0, comm_cart);
00122   }
00123   MPI_Bcast((double*)&iccp3m_cfg.extx, 1, MPI_DOUBLE, 0, comm_cart);
00124   MPI_Bcast((double*)&iccp3m_cfg.exty, 1, MPI_DOUBLE, 0, comm_cart);
00125   MPI_Bcast((double*)&iccp3m_cfg.extz, 1, MPI_DOUBLE, 0, comm_cart);
00126 
00127   MPI_Bcast(&iccp3m_cfg.citeration, 1, MPI_DOUBLE, 0, comm_cart);
00128   MPI_Bcast(&iccp3m_cfg.set_flag, 1, MPI_DOUBLE, 0, comm_cart);
00129 
00130   return 0 ;
00131     
00132 }
00133 
00134 int iccp3m_iteration() {
00135    double fdot,hold,hnew,hmax,del_eps,diff=0.0,difftemp=0.0, ex, ey, ez, l_b;
00136    Cell *cell;
00137    int c,np;
00138    Particle *part;
00139    int i, j,id;
00140    char* errtxt;
00141    double globalmax;
00142    double f1, f2 = 0;
00143 
00144    iccp3m_sanity_check();
00145    
00146    l_b = coulomb.bjerrum;
00147    if((iccp3m_cfg.eout <= 0)) {
00148      errtxt = runtime_error(128);
00149      ERROR_SPRINTF(errtxt, "ICCP3M: nonpositive dielectric constant is not allowed. Put a decent tcl error here\n");
00150    }
00151    
00152    
00153    iccp3m_cfg.citeration=0;
00154    for(j=0;j<iccp3m_cfg.num_iteration;j++) {
00155      hmax=0.;
00156      force_calc_iccp3m(); /* Calculate electrostatic forces (SR+LR) excluding source source interaction*/
00157      diff=0;
00158      for(c = 0; c < local_cells.n; c++) {
00159        cell = local_cells.cell[c];
00160        part = cell->part;
00161        np   = cell->n;
00162        for(i=0 ; i < np; i++) {
00163          id = part[i].p.identity ;
00164          if( id < iccp3m_cfg.n_ic ) {
00165            /* the dielectric-related prefactor: */                     
00166            del_eps = (iccp3m_cfg.ein[id]-iccp3m_cfg.eout)/(iccp3m_cfg.ein[id] + iccp3m_cfg.eout)/6.283185307;
00167            /* calculate the electric field at the certain position */
00168            ex=part[i].f.f[0]/part[i].p.q;
00169            ey=part[i].f.f[1]/part[i].p.q;
00170            ez=part[i].f.f[2]/part[i].p.q;
00171            
00172            /* let's add the contribution coming from the external field */
00173            ex += iccp3m_cfg.extx; 
00174            ey += iccp3m_cfg.exty; 
00175            ez += iccp3m_cfg.extz;
00176            
00177            if (ex == 0 && ey == 0 && ez == 0) {
00178              errtxt = runtime_error(128);
00179              ERROR_SPRINTF(errtxt, "ICCP3M found zero electric field on a charge. This must never happen");
00180            }
00181            /* the dot product   */
00182            fdot = ex*iccp3m_cfg.nvectorx[id]+
00183              ey*iccp3m_cfg.nvectory[id]+
00184              ez*iccp3m_cfg.nvectorz[id];
00185            
00186            /* recalculate the old charge density */
00187            hold=part[i].p.q/iccp3m_cfg.areas[id];
00188            /* determine if it is higher than the previously highest charge density */            
00189            if(hold>fabs(hmax))hmax=fabs(hold); 
00190            f1 =  (+del_eps*fdot/l_b);
00191            //                      double f2 = (1- 0.5*(iccp3m_cfg.ein[id]-iccp3m_cfg.eout)/(iccp3m_cfg.eout + iccp3m_cfg.ein[id] ))*(iccp3m_cfg.sigma[id]);
00192            if (iccp3m_cfg.sigma!=0) {
00193              f2 = (2*iccp3m_cfg.eout)/(iccp3m_cfg.eout + iccp3m_cfg.ein[id] )*(iccp3m_cfg.sigma[id]);
00194            } 
00195            
00196            hnew=(1.-iccp3m_cfg.relax)*hold + (iccp3m_cfg.relax)*(f1 + f2);
00197            difftemp=fabs( 2.*(hnew - hold)/(hold+hnew) ); /* relative variation: never use 
00198                                                              an estimator which can be negative
00199                                                              here */
00200            if(difftemp > diff && part[i].p.q > 1e-5)
00201              {
00202                //                          if (fabs(difftemp - 1./(1./iccp3m_cfg.relax - 1.)) > 1e-10) 
00203                diff=difftemp;  /* Take the largest error to check for convergence */
00204              }
00205            part[i].p.q = hnew * iccp3m_cfg.areas[id];
00206            /* check if the charge now is more than 1e6, to determine if ICC still leads to reasonable results */
00207            /* this is kind a arbitrary measure but, does a good job spotting divergence !*/
00208            if(fabs(part[i].p.q) > 1e6) { 
00209              errtxt = runtime_error(128);
00210              ERROR_SPRINTF(errtxt, "{error occured 990 : too big charge assignment in iccp3m! q >1e6 , \
00211                                assigned charge= %f } \n",part[i].p.q);
00212              diff = 1e90; /* A very high value is used as error code */
00213              break;
00214            }
00215          }
00216        }  /* cell particles */
00217        // printf("cell %d w %d particles over (node %d)\n",c,np,this_node); fflush(stdout);
00218      } /* local cells */
00219      iccp3m_cfg.citeration++;
00220      MPI_Allreduce(&diff, &globalmax, 1,MPI_DOUBLE, MPI_MAX, comm_cart);
00221      
00222      if (globalmax < iccp3m_cfg.convergence) 
00223        break; 
00224      if ( diff > 1e89 ) /* Error happened */
00225        return iccp3m_cfg.citeration++;
00226      
00227    } /* iteration */
00228    //on_particle_change();
00229    
00230    return iccp3m_cfg.citeration++;
00231 }
00232 
00233 void force_calc_iccp3m() {
00234 /* The following ist mostly copied from forces.c */
00235 
00236 /*  I don“t see the point of this part until there are electrical dipoles in Espresso, BTW, it generates a warning .. JJCP
00237 #ifdef DIPOLES
00238    convert_quat_to_dip_all();
00239 #endif
00240 
00241 */
00242 
00243   init_forces_iccp3m(); 
00244   switch (cell_structure.type) {
00245   case CELL_STRUCTURE_LAYERED:
00246     layered_calculate_ia_iccp3m();
00247     break;
00248   case CELL_STRUCTURE_DOMDEC:
00249     if(dd.use_vList) {
00250       if (rebuild_verletlist) {
00251         build_verlet_lists_and_calc_verlet_ia_iccp3m();
00252        } else  {
00253         calculate_verlet_ia_iccp3m();
00254       }
00255     }
00256     else
00257       calc_link_cell_iccp3m();
00258     break;
00259   case CELL_STRUCTURE_NSQUARE:
00260     nsq_calculate_ia_iccp3m();
00261   }
00262   
00263   calc_long_range_forces_iccp3m();
00264 }
00265 
00266 /** nonbonded and bonded force calculation using the verlet list */
00267 void layered_calculate_ia_iccp3m()
00268 {
00269   int c, i, j;
00270   Cell  *celll, *cellb;
00271   int      npl,    npb;
00272   Particle *pl,    *pb, *p1;
00273   double dist2, d[3];
00274 
00275   CELL_TRACE(fprintf(stderr, "%d: rebuild_v=%d\n", this_node, rebuild_verletlist));
00276 
00277   for (c = 1; c <= n_layers; c++) {
00278     celll = &cells[c];
00279     pl    = celll->part;
00280     npl   = celll->n;
00281 
00282     cellb = &cells[c-1];
00283     pb    = cellb->part;
00284     npb   = cellb->n;
00285 
00286     for(i = 0; i < npl; i++) {
00287       p1 = &pl[i];
00288 
00289       if (rebuild_verletlist)
00290         memcpy(p1->l.p_old, p1->r.p, 3*sizeof(double));
00291 
00292       /* cell itself. No bonded / constraints considered in ICCP3M */
00293       for(j = i+1; j < npl; j++) {
00294         layered_get_mi_vector(d, p1->r.p, pl[j].r.p);
00295         dist2 = sqrlen(d);
00296 #ifdef EXCLUSIONS
00297         if (do_nonbonded(p1, &pl[j])) {
00298 #endif
00299           /* avoid source-source computation */
00300            add_non_bonded_pair_force_iccp3m(p1, &pl[j], d, sqrt(dist2), dist2);
00301 #ifdef EXCLUSIONS  
00302          }
00303 #endif
00304       }
00305 
00306       /* bottom neighbor */
00307       for(j = 0; j < npb; j++) {
00308         layered_get_mi_vector(d, p1->r.p, pb[j].r.p);
00309         dist2 = sqrlen(d);
00310 #ifdef EXCLUSIONS
00311         if (do_nonbonded(p1, &pl[j])) {
00312 #endif
00313              /* avoid source-source computation */
00314            add_non_bonded_pair_force_iccp3m(p1, &pb[j], d, sqrt(dist2), dist2);
00315 #ifdef EXCLUSIONS
00316          }
00317 #endif
00318       }
00319     }
00320   }
00321   rebuild_verletlist = 0;
00322 }
00323 
00324 void build_verlet_lists_and_calc_verlet_ia_iccp3m()
00325 {
00326   int c, np1, n, np2, i ,j, j_start=0;
00327   Cell *cell;
00328   IA_Neighbor *neighbor;
00329   Particle *p1, *p2;
00330   PairList *pl;
00331   double dist2, vec21[3];
00332 
00333 #ifdef VERLET_DEBUG 
00334   int estimate, sum=0;
00335   fprintf(stderr,"%d: build_verlet_list_and_calc_verlet_ia:\n",this_node);
00336   /* estimate number of interactions: (0.5*n_part*ia_volume*density)/n_nodes */
00337   estimate = 0.5*n_total_particles*(4.0/3.0*PI*pow(max_cut_nonbonded,3.0))*(n_total_particles/(box_l[0]*box_l[1]*box_l[2]))/n_nodes;
00338 
00339   if (!dd.use_vList) { fprintf(stderr, "%d: build_verlet_lists, but use_vList == 0\n", this_node); errexit(); }
00340 #endif
00341  
00342   /* Loop local cells */
00343   for (c = 0; c < local_cells.n; c++) {
00344     VERLET_TRACE(fprintf(stderr,"%d: cell %d with %d neighbors\n",this_node,c, dd.cell_inter[c].n_neighbors));
00345 
00346     cell = local_cells.cell[c];
00347     p1   = cell->part;
00348     np1  = cell->n;
00349     /* Loop cell neighbors */
00350     for (n = 0; n < dd.cell_inter[c].n_neighbors; n++) {
00351       neighbor = &dd.cell_inter[c].nList[n];
00352       p2  = neighbor->pList->part;
00353       np2 = neighbor->pList->n;
00354       VERLET_TRACE(fprintf(stderr,"%d: neighbor %d contains %d parts\n",this_node,n,np2));
00355       /* init pair list */
00356       pl  = &neighbor->vList;
00357       pl->n = 0;
00358       /* Loop cell particles */
00359       for(i=0; i < np1; i++) {
00360         j_start = 0;
00361         /* Tasks within cell: (no bonded forces) store old position, avoid double counting */
00362         if(n == 0) {
00363           memcpy(p1[i].l.p_old, p1[i].r.p, 3*sizeof(double));
00364           j_start = i+1;
00365         }
00366         /* Loop neighbor cell particles */
00367         for(j = j_start; j < np2; j++) {
00368 #ifdef EXCLUSIONS
00369           if(do_nonbonded(&p1[i], &p2[j]))
00370 #endif
00371           {
00372           dist2 = distance2vec(p1[i].r.p, p2[j].r.p, vec21);
00373 
00374           VERLET_TRACE(fprintf(stderr,"%d: pair %d %d has distance %f\n",this_node,p1[i].p.identity,p2[j].p.identity,sqrt(dist2)));
00375           if(dist2 <= SQR(get_ia_param(p1[i].p.type, p2[j].p.type)->max_cut + skin)) {
00376             ONEPART_TRACE(if(p1[i].p.identity==check_id) fprintf(stderr,"%d: OPT: Verlet Pair %d %d (Cells %d,%d %d,%d dist %f)\n",this_node,p1[i].p.identity,p2[j].p.identity,c,i,n,j,sqrt(dist2)));
00377             ONEPART_TRACE(if(p2[j].p.identity==check_id) fprintf(stderr,"%d: OPT: Verlet Pair %d %d (Cells %d %d dist %f)\n",this_node,p1[i].p.identity,p2[j].p.identity,c,n,sqrt(dist2)));
00378 
00379             add_pair_iccp3m(pl, &p1[i], &p2[j]);
00380             /* calc non bonded interactions */ 
00381                add_non_bonded_pair_force_iccp3m(&(p1[i]), &(p2[j]), vec21, sqrt(dist2), dist2);
00382           }
00383          }
00384         }
00385       }
00386       resize_verlet_list_iccp3m(pl);
00387       VERLET_TRACE(fprintf(stderr,"%d: neighbor %d has %d pairs\n",this_node,n,pl->n));
00388       VERLET_TRACE(sum += pl->n);
00389     }
00390   }
00391 
00392   VERLET_TRACE(fprintf(stderr,"%d: total number of interaction pairs: %d (should be around %d)\n",this_node,sum,estimate));
00393  
00394   rebuild_verletlist = 0;
00395 }
00396 
00397 void calculate_verlet_ia_iccp3m()
00398 {
00399   int c, np, n, i;
00400   Cell *cell;
00401   Particle *p1, *p2, **pairs;
00402   double dist2, vec21[3];
00403 
00404   /* Loop local cells */
00405   for (c = 0; c < local_cells.n; c++) {
00406     cell = local_cells.cell[c];
00407     p1   = cell->part;
00408     np  = cell->n;
00409     /* Loop cell neighbors */
00410     for (n = 0; n < dd.cell_inter[c].n_neighbors; n++) {
00411       pairs = dd.cell_inter[c].nList[n].vList.pair;
00412       np    = dd.cell_inter[c].nList[n].vList.n;
00413       /* verlet list loop */
00414       for(i=0; i<2*np; i+=2) {
00415               p1 = pairs[i];                    /* pointer to particle 1 */
00416               p2 = pairs[i+1];                  /* pointer to particle 2 */
00417               dist2 = distance2vec(p1->r.p, p2->r.p, vec21); 
00418               add_non_bonded_pair_force_iccp3m(p1, p2, vec21, sqrt(dist2), dist2);
00419       }
00420     }
00421   }
00422 }
00423 
00424 void calc_link_cell_iccp3m()
00425 {
00426   int c, np1, n, np2, i ,j, j_start=0;
00427   Cell *cell;
00428   IA_Neighbor *neighbor;
00429   Particle *p1, *p2;
00430   double dist2, vec21[3];
00431  
00432   /* Loop local cells */
00433   for (c = 0; c < local_cells.n; c++) {
00434 
00435     cell = local_cells.cell[c];
00436     p1   = cell->part;
00437     np1  = cell->n;
00438     /* Loop cell neighbors */
00439     for (n = 0; n < dd.cell_inter[c].n_neighbors; n++) {
00440       neighbor = &dd.cell_inter[c].nList[n];
00441       p2  = neighbor->pList->part;
00442       np2 = neighbor->pList->n;
00443       /* Loop cell particles */
00444       for(i=0; i < np1; i++) {
00445         j_start = 0;
00446         /* Tasks within cell: bonded forces */
00447         if(n == 0) {
00448           if (rebuild_verletlist)
00449             memcpy(p1[i].l.p_old, p1[i].r.p, 3*sizeof(double));
00450 
00451           j_start = i+1;
00452         }
00453         /* Loop neighbor cell particles */
00454         for(j = j_start; j < np2; j++) {
00455             {
00456               dist2 = distance2vec(p1[i].r.p, p2[j].r.p, vec21);
00457               if(dist2 <= SQR(get_ia_param(p1[i].p.type, p2[j].p.type)->max_cut + skin)) {
00458                 /* calc non bonded interactions */
00459                 add_non_bonded_pair_force_iccp3m(&(p1[i]), &(p2[j]), vec21, sqrt(dist2), dist2);
00460               }
00461             }
00462         }
00463       }
00464     }
00465   }
00466   rebuild_verletlist = 0;
00467 }
00468 
00469 void nsq_calculate_ia_iccp3m()
00470 {
00471   Particle *partl, *partg;
00472   Particle *pt1, *pt2;
00473   int p, p2, npl, npg, c;
00474   double d[3], dist2, dist;
00475 
00476   npl   = local_icc->n;
00477   partl = local_icc->part;
00478 
00479   /* calculate bonded interactions and non bonded node-node */
00480   for (p = 0; p < npl; p++) {
00481     pt1 = &partl[p];
00482 
00483     if (rebuild_verletlist)
00484       memcpy(pt1->l.p_old, pt1->r.p, 3*sizeof(double));
00485 
00486     /* other particles, same node */
00487     for (p2 = p + 1; p2 < npl; p2++) {
00488       pt2 = &partl[p2];
00489       get_mi_vector(d, pt1->r.p, pt2->r.p);
00490       dist2 = sqrlen(d);
00491       dist = sqrt(dist2);
00492             add_non_bonded_pair_force_iccp3m(pt1, pt2, d, dist, dist2);
00493     }
00494 
00495     /* calculate with my ghosts */
00496     for (c = 0; c < me_do_ghosts_icc.n; c++) {
00497       npg   = me_do_ghosts_icc.cell[c]->n;
00498       partg = me_do_ghosts_icc.cell[c]->part;
00499 
00500       for (p2 = 0; p2 < npg; p2++) {
00501               pt2 = &partg[p2];
00502               get_mi_vector(d, pt1->r.p, pt2->r.p);
00503               dist2 = sqrlen(d);
00504               dist = sqrt(dist2);
00505               add_non_bonded_pair_force_iccp3m(pt1, pt2, d, dist, dist2);
00506       }
00507     }
00508   }
00509   rebuild_verletlist = 0;
00510 }
00511 
00512 
00513 void init_forces_iccp3m()
00514 {
00515   /* copied from forces.c */
00516   Cell *cell;
00517   Particle *p;
00518   int np, c, i;
00519 
00520   /* The force initialization depends on the used thermostat and the
00521      thermodynamic ensemble */
00522 
00523 #ifdef NPT
00524   char* errtxt;
00525   /* reset virial part of instantaneous pressure */
00526   if(integ_switch == INTEG_METHOD_NPT_ISO){
00527       errtxt = runtime_error(128);
00528       ERROR_SPRINTF(errtxt, "{ICCP3M cannot be used with pressure coupling} ");
00529   }
00530 #endif
00531 
00532   /* initialize forces with langevin thermostat forces
00533      or zero depending on the thermostat
00534      set torque to zero for all and rescale quaternions
00535   */
00536   for (c = 0; c < local_cells.n; c++) {
00537     cell = local_cells.cell[c];
00538     p  = cell->part;
00539     np = cell->n;
00540     for (i = 0; i < np; i++)
00541       init_local_particle_force_iccp3m(&p[i]);
00542   }
00543 
00544   /* initialize ghost forces with zero
00545      set torque to zero for all and rescale quaternions
00546   */
00547   for (c = 0; c < ghost_cells.n; c++) {
00548     cell = ghost_cells.cell[c];
00549     p  = cell->part;
00550     np = cell->n;
00551     for (i = 0; i < np; i++)
00552       init_ghost_force_iccp3m(&p[i]);
00553   }
00554    
00555 }
00556 
00557 void calc_long_range_forces_iccp3m()
00558 {
00559 #ifdef ELECTROSTATICS
00560   char* errtxt;
00561   /* calculate k-space part of electrostatic interaction. */
00562   if (!(coulomb.method == COULOMB_ELC_P3M || 
00563         coulomb.method == COULOMB_P3M     || 
00564         coulomb.method == COULOMB_MMM2D   ||
00565         coulomb.method == COULOMB_MMM1D)  ) { 
00566                 errtxt = runtime_error(128);
00567                 ERROR_SPRINTF(errtxt, "{ICCP3M implemented only for MMM1D,MMM2D,ELC or P3M ");
00568      }
00569   switch (coulomb.method) {
00570 #ifdef P3M
00571     case COULOMB_ELC_P3M:
00572        if (elc_params.dielectric_contrast_on) {
00573                 errtxt = runtime_error(128);
00574                 ERROR_SPRINTF(errtxt, "{ICCP3M conflicts with ELC dielectric constrast");
00575        }
00576        p3m_charge_assign();
00577        p3m_calc_kspace_forces(1,0);
00578        ELC_add_force(); 
00579     break;
00580 
00581     case COULOMB_P3M:
00582        p3m_charge_assign();
00583        p3m_calc_kspace_forces(1,0);
00584     break;
00585 #endif
00586     case COULOMB_MMM2D:
00587        MMM2D_add_far_force();
00588        MMM2D_dielectric_layers_force_contribution();
00589   }
00590 
00591 #endif
00592 }
00593 /** \name Privat Functions */
00594 /************************************************************/
00595 /*@{*/
00596 
00597 /** Add a particle pair to a verlet pair list.
00598     Checks verlet pair list size and reallocates memory if necessary.
00599  *  \param p1 Pointer to paricle one.
00600  *  \param p2 Pointer to paricle two.
00601  *  \param pl Pointer to the verlet pair list.
00602  */
00603 MDINLINE void add_pair_iccp3m(PairList *pl, Particle *p1, Particle *p2)
00604 {
00605   /* check size of verlet List */
00606   if(pl->n+1 >= pl->max) {
00607     pl->max += LIST_INCREMENT;
00608     pl->pair = (Particle **)realloc(pl->pair, 2*pl->max*sizeof(Particle *));
00609   }
00610   /* add pair */
00611   pl->pair[(2*pl->n)  ] = p1;
00612   pl->pair[(2*pl->n)+1] = p2;
00613   /* increase number of pairs */
00614   pl->n++;
00615 }
00616 
00617 void resize_verlet_list_iccp3m(PairList *pl)
00618 {
00619   int diff;
00620   diff = pl->max - pl->n;
00621   if( diff > 2*LIST_INCREMENT ) {
00622     diff = (diff/LIST_INCREMENT)-1;
00623     pl->max -= diff*LIST_INCREMENT;
00624     pl->pair = (Particle **)realloc(pl->pair, 2*pl->max*sizeof(Particle *));
00625   }
00626 }
00627 
00628 /** initialize the forces for a real particle */
00629 MDINLINE void init_local_particle_force_iccp3m(Particle *part)
00630 {
00631     part->f.f[0] = 0.0; /* no need to friction_thermo_langevin function */
00632     part->f.f[1] = 0.0;
00633     part->f.f[2] = 0.0;
00634 
00635 #ifdef ROTATION
00636     /* set torque to zero */
00637     part->f.torque[0] = 0;
00638     part->f.torque[1] = 0;
00639     part->f.torque[2] = 0;
00640 #endif
00641 }
00642 
00643 /** initialize the forces for a ghost particle */
00644 MDINLINE void init_ghost_force_iccp3m(Particle *part)
00645 {
00646   part->f.f[0] = 0.0;
00647   part->f.f[1] = 0.0;
00648   part->f.f[2] = 0.0;
00649 
00650 #ifdef ROTATION
00651   /* set torque to zero */
00652   part->f.torque[0] = 0;
00653   part->f.torque[1] = 0;
00654   part->f.torque[2] = 0;
00655 #endif
00656 }
00657 
00658 /* integer mod*/
00659 int imod(int x,int y) {
00660   double p,q,m;
00661   int z;
00662    p=x; q=y;
00663    m=fmod(p,q);
00664    z=m;
00665   return z;
00666 }
00667 
00668 
00669 void reset_forces() {
00670      Cell *cell;    
00671      int c,i,np;
00672      Particle *part;
00673    for(c = 0; c < local_cells.n; c++) {
00674        cell = local_cells.cell[c];
00675        part = cell->part;
00676        np   = cell->n;
00677      for(i=0 ; i < np; i++) {
00678       part[i].f.f[0]=0.0;  part[i].f.f[1]=0.0;  part[i].f.f[2]=0.0;
00679      }
00680    }
00681 }
00682 void iccp3m_revive_forces() {
00683   /* restore forces that are computed before in Espresso integrate_vv function*/
00684    Cell *cell;
00685    int c,i,np;
00686    Particle *part;
00687    for(c = 0; c < local_cells.n; c++) {
00688      cell = local_cells.cell[c];
00689      part = cell->part;
00690      np   = cell->n;
00691     for(i=0 ; i < np; i++) {
00692         part[i].f.f[0]=iccp3m_cfg.fx[part[i].p.identity];
00693         part[i].f.f[1]=iccp3m_cfg.fy[part[i].p.identity];
00694         part[i].f.f[2]=iccp3m_cfg.fz[part[i].p.identity];
00695      }
00696    }
00697 }
00698 void iccp3m_store_forces() {
00699   /* store forces that are computed before in Espresso integrate_vv function */
00700   /* iccp3m will re-compute electrostatic-forces on boundary particles */
00701    Cell *cell;
00702    int c,i,np;
00703    Particle *part;
00704    for(c = 0; c < local_cells.n; c++) {
00705      cell = local_cells.cell[c];
00706      part = cell->part;
00707      np   = cell->n;
00708     for(i=0 ; i < np; i++) {
00709        iccp3m_cfg.fx[part[i].p.identity]=part[i].f.f[0];
00710        iccp3m_cfg.fy[part[i].p.identity]=part[i].f.f[1];
00711        iccp3m_cfg.fz[part[i].p.identity]=part[i].f.f[2];
00712      }
00713    }
00714 }
00715 
00716 int iccp3m_sanity_check()
00717 {
00718   switch (coulomb.method) {
00719 #ifdef P3M
00720     case COULOMB_ELC_P3M: {
00721       if (elc_params.dielectric_contrast_on) {
00722         char *errtxt = runtime_error(128);
00723         ERROR_SPRINTF(errtxt, "ICCP3M conflicts with ELC dielectric constrast");
00724         return 1;
00725       }
00726       break;
00727     }
00728 #endif
00729     case COULOMB_DH: {
00730       char *errtxt = runtime_error(128);
00731       ERROR_SPRINTF(errtxt, "ICCP3M does not work with Debye-Hueckel iccp3m.h");
00732       return 1;
00733     }
00734     case COULOMB_RF: {
00735       char *errtxt = runtime_error(128);
00736       ERROR_SPRINTF(errtxt, "ICCP3M does not work with COULOMB_RF iccp3m.h");
00737       return 1;
00738     }
00739   }
00740   
00741 #ifdef NPT
00742   if(integ_switch == INTEG_METHOD_NPT_ISO) {
00743     char *errtxt = runtime_error(128);
00744     ERROR_SPRINTF(errtxt, "ICCP3M does not work in the NPT ensemble");
00745     return 1;
00746   }
00747 #endif
00748 
00749   return 0;
00750 }
00751 
00752 #endif
00753