![]() |
ESPResSo 3.2.0-11-g9950804-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 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
1.7.5.1