![]() |
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 /** \file p3m.h code for calculating the MDLC (magnetic dipolar layer correction). 00022 * Purpose: get the corrections for dipolar 3D algorithms 00023 * when applied to a slab geometry and dipolar 00024 * particles. DLC & co 00025 * Article: A. Brodka, Chemical Physics Letters 400, 62-67 (2004). 00026 * 00027 * We also include a tuning function that returns the 00028 * cut-off necessary to attend a certain accuracy. 00029 * 00030 * Restrictions: the slab must be such that the z is the short 00031 * direction. Othewise we get trash. 00032 * 00033 */ 00034 00035 #include "utils.h" 00036 #include "global.h" 00037 #include "grid.h" 00038 #include "domain_decomposition.h" 00039 #include "particle_data.h" 00040 #include "communication.h" 00041 #include "p3m-dipolar.h" 00042 #include "cells.h" 00043 #include "mdlc_correction.h" 00044 00045 #ifdef DIPOLES 00046 00047 DLC_struct dlc_params = { 1e100, 0, 0, 0, 0}; 00048 00049 static int n_local_particles=0; 00050 static double mu_max; 00051 00052 void calc_mu_max() { 00053 Cell *cell; 00054 Particle *part; 00055 int i,c,np; 00056 00057 mu_max = -1; 00058 00059 for (c = 0; c < local_cells.n; c++) { 00060 cell = local_cells.cell[c]; 00061 part = cell->part; 00062 np = cell->n; 00063 for(i=0;i<np;i++) { 00064 if(mu_max < part[i].p.dipm ) { mu_max=part[i].p.dipm;} 00065 } 00066 } 00067 MPI_Allreduce(MPI_IN_PLACE, &mu_max, 1, MPI_DOUBLE, MPI_MAX, comm_cart); 00068 } 00069 00070 /* ******************************************************************* */ 00071 00072 MDINLINE double g1_DLC_dip(double g,double x) { 00073 double a,c,cc2,x3; 00074 c=g/x; 00075 cc2=c*c; 00076 x3=x*x*x; 00077 a=g*g*g/x+1.5*cc2+1.5*g/x3+0.75/(x3*x); 00078 return a; 00079 } 00080 /* ******************************************************************* */ 00081 00082 00083 MDINLINE double g2_DLC_dip(double g,double x) { 00084 double a,x2; 00085 x2=x*x; 00086 a=g*g/x+2.0*g/x2+2.0/(x2*x); 00087 return a; 00088 } 00089 /* ******************************************************************* */ 00090 00091 /* Subroutine designed to compute Mx, My, Mz and Mtotal */ 00092 00093 double slab_dip_count_mu(double *mt, double *mx, double *my) 00094 { 00095 Cell *cell; 00096 Particle *part; 00097 int i,c,np; 00098 double node_sums[3], tot_sums[3],Mz,M,My,Mx; 00099 00100 00101 node_sums[0]=0.0; tot_sums[0]=0.0; 00102 node_sums[1]=0.0; tot_sums[1]=0.0; 00103 node_sums[2]=0.0; tot_sums[2]=0.0; 00104 00105 for (c = 0; c < local_cells.n; c++) { 00106 cell = local_cells.cell[c]; 00107 part = cell->part; 00108 np = cell->n; 00109 for(i=0;i<np;i++) { 00110 if( part[i].p.dipm != 0.0 ) { 00111 node_sums[0] +=part[i].r.dip[0]; 00112 node_sums[1] +=part[i].r.dip[1]; 00113 node_sums[2] +=part[i].r.dip[2]; 00114 } 00115 } 00116 } 00117 00118 MPI_Allreduce(node_sums, tot_sums, 3, MPI_DOUBLE, MPI_SUM, comm_cart); 00119 00120 M= sqrt(tot_sums[0]*tot_sums[0]+tot_sums[1]*tot_sums[1]+tot_sums[2]*tot_sums[2]); 00121 Mz=tot_sums[2]; 00122 Mx=tot_sums[0]; 00123 My=tot_sums[1]; 00124 00125 //fprintf(stderr,"Mz=%20.15le \n",Mz); 00126 //fprintf(stderr,"M=%20.15le \n",M); 00127 00128 *mt=M; 00129 *mx=Mx; 00130 *my=My; 00131 00132 return Mz; 00133 } 00134 /* ******************************************************************* */ 00135 00136 00137 /* **************************************************************************************************** 00138 Compute the dipolar DLC corrections for forces and torques. 00139 Algorithm implemented accordingly to the paper of A. Brodka, Chem. Phys. Lett. 400, 62-67, (2004). 00140 **************************************************************************************************** 00141 */ 00142 00143 double get_DLC_dipolar(int kcut,double *fx, double *fy, double *fz, double *tx, double *ty, double *tz){ 00144 00145 int ix,iy,ip; 00146 double gx,gy,gr; 00147 00148 double S[4] = {0.0,0.0,0.0,0.0}; // S of Brodka methode, oder is S[4] = {Re(S+), Im(S+), Re(S-), Im(S-)} 00149 double *ReSjp=NULL,*ReSjm=NULL; 00150 double *ImSjp=NULL,*ImSjm=NULL; 00151 double *ReGrad_Mup=NULL,*ImGrad_Mup=NULL; 00152 double *ReGrad_Mum=NULL,*ImGrad_Mum=NULL; 00153 double a,b,c,d,er,ez,f,fa1; 00154 double s1,s2,s3,s4; 00155 double s1z,s2z,s3z,s4z; 00156 double ss; 00157 double energy,piarea,facux,facuy; 00158 int cc,j,np; 00159 Cell *cell = NULL; 00160 Particle *p1; 00161 00162 facux=2.0*M_PI/box_l[0]; 00163 facuy=2.0*M_PI/box_l[1]; 00164 00165 energy=0.0; 00166 00167 ReSjp= (double *) malloc(sizeof(double)*n_local_particles); 00168 ReSjm= (double *) malloc(sizeof(double)*n_local_particles); 00169 ImSjp= (double *) malloc(sizeof(double)*n_local_particles); 00170 ImSjm= (double *) malloc(sizeof(double)*n_local_particles); 00171 ReGrad_Mup = (double *) malloc(sizeof(double)*n_local_particles); 00172 ImGrad_Mup = (double *) malloc(sizeof(double)*n_local_particles); 00173 ReGrad_Mum = (double *) malloc(sizeof(double)*n_local_particles); 00174 ImGrad_Mum = (double *) malloc(sizeof(double)*n_local_particles); 00175 00176 for(ix=-kcut;ix<=+kcut;ix++){ 00177 for(iy=-kcut;iy<=+kcut;iy++){ 00178 if(!(ix==0 && iy==0)){ 00179 gx=(double)ix*facux; 00180 gy=(double)iy*facuy; 00181 00182 gr=sqrt(gx*gx+gy*gy); 00183 00184 fa1=1./(gr*(exp(gr*box_l[2])-1.0)); //We assume short slab direction is z direction 00185 00186 // ... Compute S+,(S+)*,S-,(S-)*, and Spj,Smj for the current g 00187 00188 S[0] = S[1] = S[2] = S[3] = 0.0; 00189 00190 ip=0; 00191 for(cc=0; cc<local_cells.n;cc++){ 00192 cell = local_cells.cell[cc]; 00193 p1 = cell->part; 00194 np = cell->n; 00195 00196 for(j = 0; j < np; j++) { 00197 if(p1[j].p.dipm>0){ 00198 00199 a=gx*p1[j].r.dip[0]+gy*p1[j].r.dip[1]; 00200 b=gr*p1[j].r.dip[2]; 00201 er=gx*p1[j].r.p[0] +gy*p1[j].r.p[1] ; 00202 ez=gr*p1[j].r.p[2]; 00203 c=cos(er); 00204 d=sin(er); 00205 f=exp(ez); 00206 00207 ReSjp[ip]=(b*c-a*d)*f; 00208 ImSjp[ip]=(c*a+b*d)*f; 00209 ReSjm[ip]=(-b*c-a*d)/f; 00210 ImSjm[ip]=(c*a-b*d)/f; 00211 ReGrad_Mup[ip]=c*f; 00212 ReGrad_Mum[ip]=c/f; 00213 ImGrad_Mup[ip]=d*f; 00214 ImGrad_Mum[ip]=d/f; 00215 00216 S[0]+=ReSjp[ip]; 00217 S[1]+=ImSjp[ip]; 00218 S[2]+=ReSjm[ip]; 00219 S[3]+=ImSjm[ip]; 00220 } 00221 ip++; 00222 } 00223 } 00224 00225 MPI_Allreduce(MPI_IN_PLACE, S, 4, MPI_DOUBLE, MPI_SUM, comm_cart); 00226 00227 //We compute the contribution to the energy ............ 00228 00229 //s2=(ReSm*ReSp+ImSm*ImSp); s2=s1!!! 00230 00231 energy+=fa1*((S[0]*S[2]+S[1]*S[3])*2.0); 00232 00233 // ... Now we can compute the contributions to E,Fj,Ej for the current g-value 00234 ip=0; 00235 for(cc=0; cc<local_cells.n;cc++){ 00236 cell = local_cells.cell[cc]; 00237 p1 = cell->part; 00238 np = cell->n; 00239 00240 for(j = 0; j < np; j++) { 00241 if(p1[j].p.dipm>0){ 00242 //We compute the contributions to the forces ............ 00243 00244 s1=-(-ReSjp[ip]*S[3]+ImSjp[ip]*S[2]); 00245 s2=+( ReSjm[ip]*S[1]-ImSjm[ip]*S[0]); 00246 s3=-(-ReSjm[ip]*S[1]+ImSjm[ip]*S[0]); 00247 s4=+( ReSjp[ip]*S[3]-ImSjp[ip]*S[2]); 00248 00249 s1z=+(ReSjp[ip]*S[2]+ImSjp[ip]*S[3]); 00250 s2z=-(ReSjm[ip]*S[0]+ImSjm[ip]*S[1]); 00251 s3z=-(ReSjm[ip]*S[0]+ImSjm[ip]*S[1]); 00252 s4z=+(ReSjp[ip]*S[2]+ImSjp[ip]*S[3]); 00253 00254 ss=s1+s2+s3+s4; 00255 fx[ip]+=fa1*gx*ss; 00256 fy[ip]+=fa1*gy*ss; 00257 00258 fz[ip]+=fa1*gr*(s1z+s2z+s3z+s4z); 00259 00260 //We compute the contributions to the electrical field ............ 00261 00262 s1=-(-ReGrad_Mup[ip]*S[3]+ImGrad_Mup[ip]*S[2]); 00263 s2=+( ReGrad_Mum[ip]*S[1]-ImGrad_Mum[ip]*S[0]); 00264 s3=-(-ReGrad_Mum[ip]*S[1]+ImGrad_Mum[ip]*S[0]); 00265 s4=+( ReGrad_Mup[ip]*S[3]-ImGrad_Mup[ip]*S[2]); 00266 00267 s1z=+(ReGrad_Mup[ip]*S[2]+ImGrad_Mup[ip]*S[3]); 00268 s2z=-(ReGrad_Mum[ip]*S[0]+ImGrad_Mum[ip]*S[1]); 00269 s3z=-(ReGrad_Mum[ip]*S[0]+ImGrad_Mum[ip]*S[1]); 00270 s4z=+(ReGrad_Mup[ip]*S[2]+ImGrad_Mup[ip]*S[3]); 00271 00272 ss=s1+s2+s3+s4; 00273 tx[ip]+=fa1*gx*ss; 00274 ty[ip]+=fa1*gy*ss; 00275 00276 tz[ip]+=fa1*gr*(s1z+s2z+s3z+s4z); 00277 }//if dipm>0 .... 00278 ip++; 00279 }//loop j 00280 } //loop cc 00281 00282 }//end of if(ii> ... 00283 00284 }} //end of loops for gx,gy 00285 00286 00287 //Convert from the corrections to the Electrical field to the corrections for the torques .... 00288 00289 00290 //printf("Electical field: Ex %le, Ey %le, Ez %le",-tx[0]*M_PI/(box_l[0]*box_l[1]),-ty[0]*M_PI/(box_l[0]*box_l[1]), 00291 //-tz[0]*M_PI/(box_l[0]*box_l[1]) ); 00292 00293 ip=0; 00294 for(cc=0; cc<local_cells.n;cc++){ 00295 cell = local_cells.cell[cc]; 00296 p1 = cell->part; 00297 np = cell->n; 00298 00299 for(j = 0; j < np; j++) { 00300 if(p1[j].p.dipm>0){ 00301 a=p1[j].r.dip[1]*tz[ip]-p1[j].r.dip[2]*ty[ip]; 00302 b=p1[j].r.dip[2]*tx[ip]-p1[j].r.dip[0]*tz[ip]; 00303 c=p1[j].r.dip[0]*ty[ip]-p1[j].r.dip[1]*tx[ip]; 00304 tx[ip]=a; 00305 ty[ip]=b; 00306 tz[ip]=c; 00307 00308 } 00309 ip++; 00310 } 00311 } 00312 00313 // Multiply by the factors we have left during the loops 00314 00315 //printf("box_l: %le %le %le \n",box_l[0],box_l[1],box_l[2]); 00316 00317 piarea=M_PI/(box_l[0]*box_l[1]); 00318 00319 for(j = 0; j < n_local_particles; j++) { 00320 fx[j]*=piarea; 00321 fy[j]*=piarea; 00322 fz[j]*=piarea; 00323 tx[j]*=piarea; 00324 ty[j]*=piarea; 00325 tz[j]*=piarea; 00326 } 00327 00328 energy*=(-piarea); 00329 00330 //fclose(FilePtr); 00331 00332 free(ReSjp); 00333 free(ReSjm); 00334 free(ImSjp); 00335 free(ImSjm); 00336 free(ReGrad_Mup); 00337 free(ImGrad_Mup); 00338 free(ReGrad_Mum); 00339 free(ImGrad_Mum); 00340 00341 00342 //printf("Energy0= %20.15le \n",energy); 00343 00344 00345 return energy; 00346 } 00347 /* ******************************************************************* */ 00348 00349 00350 /* **************************************************************************************************** 00351 Compute the dipolar DLC corrections 00352 Algorithm implemented accordingly to the paper of A. Brodka, Chem. Phys. Lett. 400, 62-67, (2004). 00353 **************************************************************************************************** 00354 */ 00355 00356 double get_DLC_energy_dipolar(int kcut){ 00357 00358 int ix,iy,ip; 00359 double gx,gy,gr; 00360 00361 double S[4], global_S[4]; 00362 double a,b,c,d,er,ez,f,fa1; 00363 double s1; 00364 double energy,piarea,facux,facuy; 00365 int cc,j,np; 00366 Cell *cell = NULL; 00367 Particle *p1; 00368 00369 //FILE *FilePtr; 00370 // char File_Name[40]; 00371 00372 n_local_particles = 0; 00373 for(cc=0; cc<local_cells.n;cc++) { 00374 cell = local_cells.cell[cc]; 00375 n_local_particles += cell->n; 00376 } 00377 00378 00379 facux=2.0*M_PI/box_l[0]; 00380 facuy=2.0*M_PI/box_l[1]; 00381 00382 energy=0.0; 00383 00384 for(ix=-kcut;ix<=+kcut;ix++){ 00385 for(iy=-kcut;iy<=+kcut;iy++){ 00386 00387 00388 if(!(ix==0 && iy==0)){ 00389 gx=(double)ix*facux; 00390 gy=(double)iy*facuy; 00391 00392 gr=sqrt(gx*gx+gy*gy); 00393 00394 fa1=1./(gr*(exp(gr*box_l[2])-1.0)); //We assume short slab direction is z direction 00395 00396 // ... Compute S+,(S+)*,S-,(S-)*, and Spj,Smj for the current g 00397 00398 S[0] = S[1] = S[2] = S[3] = 0.0; 00399 00400 ip=0; 00401 for(cc=0; cc<local_cells.n;cc++){ 00402 cell = local_cells.cell[cc]; 00403 p1 = cell->part; 00404 np = cell->n; 00405 00406 for(j = 0; j < np; j++) { 00407 if(p1[j].p.dipm>0){ 00408 00409 a=gx*p1[j].r.dip[0]+gy*p1[j].r.dip[1];{ 00410 b=gr*p1[j].r.dip[2]; 00411 er=gx*p1[j].r.p[0] +gy*p1[j].r.p[1] ; 00412 ez=gr*p1[j].r.p[2]; 00413 c=cos(er); 00414 d=sin(er); 00415 f=exp(ez); 00416 00417 S[0]+=(b*c-a*d)*f; 00418 S[1]+=(c*a+b*d)*f; 00419 S[2]+=(-b*c-a*d)/f; 00420 S[3]+=(c*a-b*d)/f; 00421 } 00422 00423 } 00424 ip++; 00425 } 00426 } 00427 MPI_Reduce(S, global_S, 4, MPI_DOUBLE, MPI_SUM, 0, comm_cart); 00428 00429 //We compute the contribution to the energy ............ 00430 s1=(global_S[0]*global_S[2]+global_S[1]*global_S[3]); 00431 //s2=(ReSm*ReSp+ImSm*ImSp); s2=s1!!! 00432 00433 energy+=fa1*(s1*2.0); 00434 00435 }//end of if(... 00436 }} //end of loops for gx,gy 00437 00438 00439 // Multiply by the factors we have left during the loops 00440 00441 piarea=M_PI/(box_l[0]*box_l[1]); 00442 energy*=(-piarea); 00443 return (this_node == 0) ? energy : 0.0; 00444 } 00445 /* ***************************************************************** */ 00446 00447 00448 00449 00450 /* ************************************************************************** 00451 ********** Compute and add the terms needed to correct the 3D dipolar***** 00452 ********** methods when we have an slab geometry ************************* 00453 ************************************************************************** */ 00454 00455 void add_mdlc_force_corrections(){ 00456 Cell *cell; 00457 Particle *p; 00458 int i,c,np,ip; 00459 int cc; 00460 int dip_DLC_kcut; 00461 double *dip_DLC_f_x=NULL,*dip_DLC_f_y=NULL,*dip_DLC_f_z=NULL; 00462 double *dip_DLC_t_x=NULL,*dip_DLC_t_y=NULL,*dip_DLC_t_z=NULL; 00463 double dip_DLC_energy=0.0; 00464 double mz=0.0,mx=0.0,my=0.0,volume,mtot=0.0; 00465 #if defined(ROTATION) && defined(DP3M) 00466 double dx,dy,dz,correps; 00467 #endif 00468 00469 dip_DLC_kcut=dlc_params.far_cut ; 00470 00471 n_local_particles = 0; 00472 for(cc=0; cc<local_cells.n;cc++) { 00473 cell = local_cells.cell[cc]; 00474 n_local_particles += cell->n; 00475 } 00476 00477 volume=box_l[0]*box_l[1]*box_l[2]; 00478 00479 // --- Create arrays that should contain the corrections to 00480 // the forces and torques, and set them to zero. 00481 00482 dip_DLC_f_x = (double *) malloc(sizeof(double)*n_total_particles); 00483 dip_DLC_f_y = (double *) malloc(sizeof(double)*n_total_particles); 00484 dip_DLC_f_z = (double *) malloc(sizeof(double)*n_total_particles); 00485 00486 dip_DLC_t_x = (double *) malloc(sizeof(double)*n_total_particles); 00487 dip_DLC_t_y = (double *) malloc(sizeof(double)*n_total_particles); 00488 dip_DLC_t_z = (double *) malloc(sizeof(double)*n_total_particles); 00489 00490 00491 for(i=0;i<n_local_particles;i++){ 00492 dip_DLC_f_x[i] = 0.0; 00493 dip_DLC_f_y[i] = 0.0; 00494 dip_DLC_f_z[i] = 0.0; 00495 00496 dip_DLC_t_x[i] = 0.0; 00497 dip_DLC_t_y[i] = 0.0; 00498 dip_DLC_t_z[i] = 0.0; 00499 } 00500 00501 //---- Compute the corrections ---------------------------------- 00502 00503 //First the DLC correction 00504 dip_DLC_energy+=coulomb.Dprefactor*get_DLC_dipolar(dip_DLC_kcut,dip_DLC_f_x,dip_DLC_f_y,dip_DLC_f_z,dip_DLC_t_x,dip_DLC_t_y,dip_DLC_t_z); 00505 00506 // printf("Energy DLC = %20.15le \n",dip_DLC_energy); 00507 00508 //Now we compute the the correction like Yeh and Klapp to take into account the fact that you are using a 00509 //3D PBC method which uses spherical summation instead of slab-wise sumation. Slab-wise summation is the one 00510 //required to apply DLC correction. This correction is often called SDC = Shape Dependent Correction. 00511 //See Brodka, Chem. Phys. Lett. 400, 62, (2004). 00512 00513 mz=slab_dip_count_mu(&mtot, &mx, &my); 00514 #ifdef DP3M 00515 if(coulomb.Dmethod == DIPOLAR_MDLC_P3M) { 00516 if(dp3m.params.epsilon == P3M_EPSILON_METALLIC) { 00517 dip_DLC_energy+=coulomb.Dprefactor*2.*M_PI/volume*(mz*mz); 00518 } 00519 else{ 00520 dip_DLC_energy+=coulomb.Dprefactor*2.*M_PI/volume*(mz*mz-mtot*mtot/(2.0*dp3m.params.epsilon+1.0)); 00521 } 00522 } 00523 else 00524 #endif 00525 { 00526 dip_DLC_energy+=coulomb.Dprefactor*2.*M_PI/volume*(mz*mz); 00527 fprintf(stderr,"You are not using the P3M method, therefore p3m.epsilon is unknown, I assume metallic borders \n"); 00528 } 00529 00530 // --- Transfer the computed corrections to the Forces, Energy and torques 00531 // of the particles 00532 00533 ip = 0; 00534 for (c = 0; c < local_cells.n; c++) { 00535 cell = local_cells.cell[c]; 00536 p = cell->part; 00537 np = cell->n; 00538 for(i=0; i<np; i++) { 00539 if( (p[i].p.dipm) != 0.0 ) { 00540 00541 p[i].f.f[0] += coulomb.Dprefactor*dip_DLC_f_x[ip]; 00542 p[i].f.f[1] += coulomb.Dprefactor*dip_DLC_f_y[ip]; 00543 p[i].f.f[2] += coulomb.Dprefactor*dip_DLC_f_z[ip]; //SDC correction term is zero for the forces 00544 00545 #if defined(ROTATION) && defined(DP3M) 00546 double correc= 4.*M_PI/volume; 00547 //in the Next lines: the second term (correc*...)is the SDC correction for the torques 00548 if(dp3m.params.epsilon == P3M_EPSILON_METALLIC) { 00549 00550 dx=0.0; 00551 dy=0.0; 00552 dz=correc*(-1.0)*mz; 00553 00554 p[i].f.torque[0] +=coulomb.Dprefactor*(dip_DLC_t_x[ip]+p[i].r.dip[1]*dz - p[i].r.dip[2]*dy ) ; 00555 p[i].f.torque[1] +=coulomb.Dprefactor*(dip_DLC_t_y[ip]+p[i].r.dip[2]*dx - p[i].r.dip[0]*dz ) ; 00556 p[i].f.torque[2] +=coulomb.Dprefactor*(dip_DLC_t_z[ip]+p[i].r.dip[0]*dy - p[i].r.dip[1]*dx ); 00557 00558 00559 }else{ 00560 00561 correps= correc/(2.0*dp3m.params.epsilon+1.0); 00562 dx=correps*mx; 00563 dy=correps*my; 00564 dz=correc*(-1.0+1./(2.0*dp3m.params.epsilon+1.0))*mz; 00565 00566 p[i].f.torque[0] +=coulomb.Dprefactor*(dip_DLC_t_x[ip]+p[i].r.dip[1]*dz - p[i].r.dip[2]*dy ) ; 00567 p[i].f.torque[1] +=coulomb.Dprefactor*(dip_DLC_t_y[ip]+p[i].r.dip[2]*dx - p[i].r.dip[0]*dz ) ; 00568 p[i].f.torque[2] +=coulomb.Dprefactor*(dip_DLC_t_z[ip]+p[i].r.dip[0]*dy - p[i].r.dip[1]*dx ); 00569 00570 00571 } 00572 #endif 00573 } 00574 ip++; 00575 } 00576 } 00577 00578 //--- Free the memory used for computing the corrections ---------------- 00579 00580 free(dip_DLC_f_x); 00581 free(dip_DLC_f_y); 00582 free(dip_DLC_f_z); 00583 free(dip_DLC_t_x); 00584 free(dip_DLC_t_y); 00585 free(dip_DLC_t_z); 00586 00587 00588 00589 } 00590 /* ***************************************************************** */ 00591 00592 00593 00594 /* ************************************************************************** 00595 ********** Compute and add the terms needed to correct the energy of ***** 00596 ********** 3D dipolar methods when we have an slab geometry ***** 00597 ************************************************************************** */ 00598 00599 double add_mdlc_energy_corrections(){ 00600 double dip_DLC_energy=0.0; 00601 double mz=0.0,mx=0.0,my=0.0,volume,mtot=0.0; 00602 int dip_DLC_kcut; 00603 00604 volume=box_l[0]*box_l[1]*box_l[2]; 00605 00606 dip_DLC_kcut=dlc_params.far_cut ; 00607 00608 //---- Compute the corrections ---------------------------------- 00609 00610 //First the DLC correction 00611 dip_DLC_energy+=coulomb.Dprefactor*get_DLC_energy_dipolar(dip_DLC_kcut); 00612 00613 // printf("Energy DLC = %20.15le \n",dip_DLC_energy); 00614 00615 //Now we compute the the correction like Yeh and Klapp to take into account the fact that you are using a 00616 //3D PBC method which uses spherical summation instead of slab-wise sumation. Slab-wise summation is the one 00617 //required to apply DLC correction. This correction is often called SDC = Shape Dependent Correction. 00618 //See Brodka, Chem. Phys. Lett. 400, 62, (2004). 00619 00620 mz=slab_dip_count_mu(&mtot, &mx, &my); 00621 00622 if(this_node == 0) { 00623 #ifdef DP3M 00624 if(coulomb.Dmethod == DIPOLAR_MDLC_P3M) { 00625 if(dp3m.params.epsilon == P3M_EPSILON_METALLIC) { 00626 dip_DLC_energy+=coulomb.Dprefactor*2.*M_PI/volume*(mz*mz); 00627 } 00628 else{ 00629 dip_DLC_energy+=coulomb.Dprefactor*2.*M_PI/volume*(mz*mz-mtot*mtot/(2.0*dp3m.params.epsilon+1.0)); 00630 } 00631 } 00632 else 00633 #endif 00634 { 00635 dip_DLC_energy+=coulomb.Dprefactor*2.*M_PI/volume*(mz*mz); 00636 fprintf(stderr,"You are not using the P3M method, therefore dp3m.params.epsilon unknown, I assume metallic borders \n"); 00637 } 00638 00639 return dip_DLC_energy; 00640 } else { 00641 return 0.0; 00642 } 00643 00644 } 00645 /* ***************************************************************** */ 00646 00647 /* ------------------------------------------------------------------------------- 00648 Subroutine to compute the cut-off (NCUT) necessary in the DLC dipolar part 00649 to get a certain accuracy (acc). We assume particles to have all them a same 00650 value of the dipolar momentum modulus (mu_max). mu_max is taken as the largest value of 00651 mu inside the sytem. If we assum the gap has a width gap_size (within which there is no particles) 00652 00653 Lz=h+gap_size 00654 00655 BE CAREFUL: (1) We assum the short distance for the slab to be in the Z direction 00656 (2) You must also tune the other 3D method to the same accuracy, otherwise 00657 it has no sense to have a good accurated result for DLC-dipolar. 00658 00659 ---------------------------------------------------------------------------------- */ 00660 00661 int mdlc_tune(double error) 00662 { 00663 double de,n,gc,lz,lx,a,fa1,fa2,fa0,h; 00664 int kc,limitkc=200,flag; 00665 00666 MDLC_TRACE(fprintf(stderr, "%d: mdlc_tune().\n", this_node)); 00667 00668 n=(double) n_total_particles; 00669 lz=box_l[2]; 00670 00671 a=box_l[0]*box_l[1]; 00672 mpi_bcast_max_mu(); /* we take the maximum dipole in the system, to be sure that the errors in the other case 00673 will be equal or less than for this one */ 00674 00675 h=dlc_params.h; 00676 if (h < 0) return ES_ERROR; 00677 00678 if(h > lz) { 00679 fprintf(stderr,"tune DLC dipolar: Slab is larger than the box size !!! \n"); 00680 exit(1); 00681 } 00682 00683 if(fabs(box_l[0]-box_l[1])>0.001) { 00684 fprintf(stderr,"tune DLC dipolar: box size in x direction is different from y direction !!! \n"); 00685 fprintf(stderr,"The tuning formula requires both to be equal. \n"); 00686 exit(1); 00687 } 00688 00689 lx=box_l[0]; 00690 00691 flag=0; 00692 for(kc=1;kc<limitkc;kc++){ 00693 gc=kc*2.0*PI/lx; 00694 fa0=sqrt(9.0*exp(+2.*gc*h)*g1_DLC_dip(gc,lz-h)+22.0*g1_DLC_dip(gc,lz)+9.0*exp(-2.0*gc*h)*g1_DLC_dip(gc,lz+h) ); 00695 fa1=0.5*sqrt(PI/(2.0*a))*fa0; 00696 fa2=g2_DLC_dip(gc,lz); 00697 de=n*(mu_max*mu_max)/(4.0*(exp(gc*lz)-1.0)) *(fa1+fa2); 00698 if(de<error) {flag=1;break;} 00699 } 00700 00701 if(flag==0) { 00702 fprintf(stderr,"tune DLC dipolar: Sorry, unable to find a proper cut-off for such system and accuracy.\n"); 00703 fprintf(stderr,"Try modifiying the variable limitkc in the c-code: dlc_correction.c ... \n"); 00704 return ES_ERROR; 00705 } 00706 00707 dlc_params.far_cut=kc; 00708 00709 MDLC_TRACE(fprintf(stderr, "%d: done mdlc_tune().\n", this_node)); 00710 00711 return ES_OK; 00712 00713 } 00714 00715 00716 //====================================================================================================================== 00717 //====================================================================================================================== 00718 00719 00720 int mdlc_sanity_checks() 00721 { 00722 #ifdef PARTIAL_PERIODIC 00723 char *errtxt; 00724 if (!PERIODIC(0) || !PERIODIC(1) || !PERIODIC(2)) { 00725 errtxt = runtime_error(128); 00726 ERROR_SPRINTF(errtxt, "{006 mdlc requires periodicity 1 1 1} "); 00727 return 1; 00728 } 00729 #endif 00730 00731 // It will be desirable to have a checking function that check that the slab geometry is such that 00732 // the short direction is along the z component. 00733 00734 return 0; 00735 } 00736 /* ***************************************************************** */ 00737 00738 int mdlc_set_params(double maxPWerror, double gap_size, double far_cut) 00739 { 00740 MDLC_TRACE(fprintf(stderr, "%d: mdlc_set_params().\n", this_node)); 00741 00742 dlc_params.maxPWerror = maxPWerror; 00743 dlc_params.gap_size = gap_size; 00744 dlc_params.h = box_l[2] - gap_size; 00745 00746 00747 switch (coulomb.Dmethod) { 00748 #ifdef DP3M 00749 case DIPOLAR_MDLC_P3M: 00750 case DIPOLAR_P3M: 00751 coulomb.Dmethod =DIPOLAR_MDLC_P3M; 00752 break; 00753 #endif 00754 case DIPOLAR_MDLC_DS: 00755 case DIPOLAR_DS: 00756 coulomb.Dmethod =DIPOLAR_MDLC_DS; 00757 break; 00758 default: 00759 return ES_ERROR; 00760 } 00761 00762 dlc_params.far_cut = far_cut; 00763 if (far_cut != -1) { 00764 dlc_params.far_calculated = 0; 00765 } 00766 else { 00767 dlc_params.far_calculated = 1; 00768 if (mdlc_tune(dlc_params.maxPWerror) == ES_ERROR) { 00769 char *errtxt = runtime_error(128); 00770 ERROR_SPRINTF(errtxt, "{009 mdlc tuning failed, gap size too small} "); 00771 } 00772 } 00773 mpi_bcast_coulomb_params(); 00774 00775 return ES_OK; 00776 } 00777 /* ***************************************************************** */ 00778 00779 #endif 00780 00781 00782 00783 00784 00785 00786 00787 00788
1.7.5.1