![]() |
ESPResSo 3.2.0-159-gf5c8922-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 magnetic_non_p3m_methods.c All 3d non P3M methods to deal with the magnetic dipoles 00022 * 00023 * DAWAANR => DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA 00024 * Handling of a system of dipoles where no replicas 00025 * Assumes minimum image convention for those axis in which the 00026 * system is periodic as defined by setmd. 00027 * 00028 * MDDS => Calculates dipole-dipole interaction of a perioidic system 00029 * by explicitly summing the dipole-dipole interaction over several copies of the system 00030 * Uses spherical summation order 00031 * 00032 */ 00033 00034 #include "domain_decomposition.h" 00035 #include "magnetic_non_p3m_methods.h" 00036 00037 #ifdef DIPOLES 00038 00039 // Calculates dipolar energy and/or force between two particles 00040 double calc_dipole_dipole_ia(Particle* p1, Particle *p2, int force_flag) 00041 { 00042 double u,r,pe1,pe2,pe3,pe4,r3,r5,r2,r7,a,b,cc,d,ab; 00043 #ifdef ROTATION 00044 double bx,by,bz,ax,ay,az; 00045 #endif 00046 double ffx,ffy,ffz; 00047 double dr[3]; 00048 00049 00050 // Distance between particles 00051 get_mi_vector(dr,p1->r.p,p2->r.p); 00052 00053 // Powers of distance 00054 r2=dr[0]*dr[0]+dr[1]*dr[1]+dr[2]*dr[2]; 00055 r=sqrt(r2); 00056 r3=r2*r; 00057 r5=r3*r2; 00058 r7=r5*r2; 00059 00060 // Dot products 00061 pe1=p1->r.dip[0]*p2->r.dip[0]+p1->r.dip[1]*p2->r.dip[1]+p1->r.dip[2]*p2->r.dip[2]; 00062 pe2=p1->r.dip[0]*dr[0]+p1->r.dip[1]*dr[1]+p1->r.dip[2]*dr[2]; 00063 pe3=p2->r.dip[0]*dr[0]+p2->r.dip[1]*dr[1]+p2->r.dip[2]*dr[2]; 00064 pe4=3.0/r5; 00065 00066 // Energy, if requested 00067 u= coulomb.Dprefactor* ( pe1/r3 - pe4*pe2*pe3); 00068 00069 // Force, if requested 00070 if(force_flag) { 00071 a=pe4*pe1; 00072 b=-15.0*pe2*pe3/r7; 00073 ab =a+b; 00074 cc=pe4*pe3; 00075 d=pe4*pe2; 00076 00077 // Result 00078 ffx=ab*dr[0]+cc*p1->r.dip[0]+d*p2->r.dip[0]; 00079 ffy=ab*dr[1]+cc*p1->r.dip[1]+d*p2->r.dip[1]; 00080 ffz=ab*dr[2]+cc*p1->r.dip[2]+d*p2->r.dip[2]; 00081 // Add the force to the particles 00082 p1->f.f[0] +=coulomb.Dprefactor*ffx; 00083 p1->f.f[1] +=coulomb.Dprefactor*ffy; 00084 p1->f.f[2] +=coulomb.Dprefactor*ffz; 00085 p2->f.f[0] -=coulomb.Dprefactor*ffx; 00086 p2->f.f[1] -=coulomb.Dprefactor*ffy; 00087 p2->f.f[2] -=coulomb.Dprefactor*ffz; 00088 00089 // Torques 00090 #ifdef ROTATION 00091 ax=p1->r.dip[1]*p2->r.dip[2]-p2->r.dip[1]*p1->r.dip[2]; 00092 ay=p2->r.dip[0]*p1->r.dip[2]-p1->r.dip[0]*p2->r.dip[2]; 00093 az=p1->r.dip[0]*p2->r.dip[1]-p2->r.dip[0]*p1->r.dip[1]; 00094 00095 bx=p1->r.dip[1]*dr[2]-dr[1]*p1->r.dip[2]; 00096 by=dr[0]*p1->r.dip[2]-p1->r.dip[0]*dr[2]; 00097 bz=p1->r.dip[0]*dr[1]-dr[0]*p1->r.dip[1]; 00098 00099 p1->f.torque[0]+=coulomb.Dprefactor*(-ax/r3+bx*cc); 00100 p1->f.torque[1]+=coulomb.Dprefactor *(-ay/r3+by*cc); 00101 p1->f.torque[2]+=coulomb.Dprefactor*(-az/r3+bz*cc); 00102 00103 // 2nd particle 00104 bx=p2->r.dip[1]*dr[2]-dr[1]*p2->r.dip[2]; 00105 by=dr[0]*p2->r.dip[2]-p2->r.dip[0]*dr[2]; 00106 bz=p2->r.dip[0]*dr[1]-dr[0]*p2->r.dip[1]; 00107 00108 p2->f.torque[0]+=coulomb.Dprefactor* (ax/r3+bx*d); 00109 p2->f.torque[1]+=coulomb.Dprefactor*(ay/r3+by*d); 00110 p2->f.torque[2]+=coulomb.Dprefactor* (az/r3+bz*d); 00111 #endif 00112 } 00113 00114 // Return energy 00115 return u; 00116 } 00117 00118 /* ============================================================================= 00119 DAWAANR => DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA 00120 ============================================================================= 00121 */ 00122 00123 double dawaanr_calculations(int force_flag, int energy_flag) 00124 { 00125 double u; 00126 int i,j,c,cc; 00127 00128 if(n_nodes!=1) {fprintf(stderr,"error: DAWAANR is just for one cpu .... \n"); exit(1);} 00129 if(!(force_flag) && !(energy_flag) ) {fprintf(stderr," I don't know why you call dawaanr_caclulations with all flags zero \n"); return 0;} 00130 00131 // Variable to sum up the energy 00132 u=0; 00133 00134 // Iterate over all cells 00135 for (c = 0; c < local_cells.n; c++) { 00136 // Iterate over all particles in this cell 00137 for(i=0;i<local_cells.cell[c]->n;i++) { 00138 // If the particle has no dipole moment, ignore it 00139 if( local_cells.cell[c]->part[i].p.dipm < 1.e-11 ) 00140 continue; 00141 00142 // Consider interaction of this particle with the others in the same cell 00143 for (j=i+1;j<local_cells.cell[c]->n; j++) { 00144 // If the particle has no dipole moment, ignore it 00145 if( local_cells.cell[c]->part[j].p.dipm < 1.e-11 ) 00146 continue; 00147 // Calculate energy and/or force between the particles 00148 u+=calc_dipole_dipole_ia(&local_cells.cell[c]->part[i],&local_cells.cell[c]->part[j],force_flag); 00149 } 00150 00151 // Calculate the ia between this particles and the particles in the 00152 // other cells: 00153 // Iterate over all remaining cells 00154 for (cc = c+1; cc < local_cells.n; cc++) { 00155 // Iterate over the particles in this cell 00156 for (j=0;j<local_cells.cell[cc]->n;j++) { 00157 // If it doesn't have dipole moment, ignore 00158 if( local_cells.cell[cc]->part[j].p.dipm < 1.e-11 ) 00159 continue; 00160 00161 // Calculate energy and/or force between the particles 00162 u+=calc_dipole_dipole_ia(&local_cells.cell[c]->part[i],&local_cells.cell[cc]->part[j],force_flag); 00163 } 00164 } 00165 } 00166 } 00167 00168 // Return energy 00169 return u; 00170 } 00171 00172 00173 /************************************************************/ 00174 00175 /*=================== */ 00176 /*=================== */ 00177 /*=================== */ 00178 /*=================== */ 00179 /*=================== */ 00180 /*=================== */ 00181 00182 /* ============================================================================= 00183 DIRECT SUM FOR MAGNETIC SYSTEMS 00184 ============================================================================= 00185 */ 00186 00187 int Ncut_off_magnetic_dipolar_direct_sum=0; 00188 00189 /************************************************************/ 00190 00191 00192 int magnetic_dipolar_direct_sum_sanity_checks() 00193 { 00194 /* left for the future , at this moment nothing to do */ 00195 00196 return 0; 00197 } 00198 00199 /************************************************************/ 00200 00201 00202 double magnetic_dipolar_direct_sum_calculations(int force_flag, int energy_flag) { 00203 Cell *cell; 00204 Particle *part; 00205 int i,c,np; 00206 double *x=NULL, *y=NULL, *z=NULL; 00207 double *mx=NULL, *my=NULL, *mz=NULL; 00208 double *fx=NULL, *fy=NULL, *fz=NULL; 00209 #ifdef ROTATION 00210 double *tx=NULL, *ty=NULL, *tz=NULL; 00211 #endif 00212 int dip_particles,dip_particles2; 00213 double ppos[3]; 00214 int img[3]; 00215 double u; 00216 00217 00218 if(n_nodes!=1) {fprintf(stderr,"error: magnetic Direct Sum is just for one cpu .... \n"); exit(1);} 00219 if(!(force_flag) && !(energy_flag) ) {fprintf(stderr," I don't know why you call dawaanr_caclulations with all flags zero \n"); return 0;} 00220 00221 x = (double *) malloc(sizeof(double)*n_total_particles); 00222 y = (double *) malloc(sizeof(double)*n_total_particles); 00223 z = (double *) malloc(sizeof(double)*n_total_particles); 00224 00225 mx = (double *) malloc(sizeof(double)*n_total_particles); 00226 my = (double *) malloc(sizeof(double)*n_total_particles); 00227 mz = (double *) malloc(sizeof(double)*n_total_particles); 00228 00229 if(force_flag) { 00230 fx = (double *) malloc(sizeof(double)*n_total_particles); 00231 fy = (double *) malloc(sizeof(double)*n_total_particles); 00232 fz = (double *) malloc(sizeof(double)*n_total_particles); 00233 00234 #ifdef ROTATION 00235 tx = (double *) malloc(sizeof(double)*n_total_particles); 00236 ty = (double *) malloc(sizeof(double)*n_total_particles); 00237 tz = (double *) malloc(sizeof(double)*n_total_particles); 00238 #endif 00239 } 00240 00241 dip_particles=0; 00242 for (c = 0; c < local_cells.n; c++) { 00243 cell = local_cells.cell[c]; 00244 part = cell->part; 00245 np = cell->n; 00246 for(i=0;i<np;i++) { 00247 if( part[i].p.dipm > 1.e-11 ) { 00248 00249 mx[dip_particles]=part[i].r.dip[0]; 00250 my[dip_particles]=part[i].r.dip[1]; 00251 mz[dip_particles]=part[i].r.dip[2]; 00252 00253 /* here we wish the coordinates to be folded into the primary box */ 00254 00255 ppos[0]=part[i].r.p[0]; 00256 ppos[1]=part[i].r.p[1]; 00257 ppos[2]=part[i].r.p[2]; 00258 img[0]=part[i].l.i[0]; 00259 img[1]=part[i].l.i[1]; 00260 img[2]=part[i].l.i[2]; 00261 fold_position(ppos, img); 00262 00263 x[dip_particles]=ppos[0]; 00264 y[dip_particles]=ppos[1]; 00265 z[dip_particles]=ppos[2]; 00266 00267 00268 if(force_flag) { 00269 fx[dip_particles]=0; 00270 fy[dip_particles]=0; 00271 fz[dip_particles]=0; 00272 00273 #ifdef ROTATION 00274 tx[dip_particles]=0; 00275 ty[dip_particles]=0; 00276 tz[dip_particles]=0; 00277 #endif 00278 } 00279 00280 dip_particles++; 00281 00282 } 00283 } 00284 } 00285 00286 /*now we do the calculations */ 00287 00288 { /* beginning of the area of calculation */ 00289 int nx,ny,nz,i,j; 00290 double r,rnx,rny,rnz,pe1,pe2,pe3,r3,r5,r2,r7; 00291 double a,b,c,d; 00292 #ifdef ROTATION 00293 double ax,ay,az,bx,by,bz; 00294 #endif 00295 double rx,ry,rz; 00296 double rnx2,rny2; 00297 int NCUT[3],NCUT2; 00298 00299 for(i=0;i<3;i++){ 00300 NCUT[i]=Ncut_off_magnetic_dipolar_direct_sum; 00301 #ifdef PARTIAL_PERIODIC 00302 if(PERIODIC(i) == 0) {NCUT[i]=0;} 00303 #endif 00304 } 00305 NCUT2=Ncut_off_magnetic_dipolar_direct_sum*Ncut_off_magnetic_dipolar_direct_sum; 00306 00307 00308 u=0; 00309 00310 fprintf(stderr,"Magnetic Direct sum takes long time. Done of %d: \n",dip_particles); 00311 00312 for(i=0;i<dip_particles;i++){ 00313 fprintf(stderr,"%d\r",i); 00314 for(j=0;j<dip_particles;j++){ 00315 pe1=mx[i]*mx[j]+my[i]*my[j]+mz[i]*mz[j]; 00316 rx=x[i]-x[j]; 00317 ry=y[i]-y[j]; 00318 rz=z[i]-z[j]; 00319 00320 for(nx=-NCUT[0];nx<=NCUT[0];nx++){ 00321 rnx=rx+nx*box_l[0]; 00322 rnx2=rnx*rnx; 00323 for(ny=-NCUT[1];ny<=NCUT[1];ny++){ 00324 rny=ry+ny*box_l[1]; 00325 rny2=rny*rny; 00326 for(nz=-NCUT[2];nz<=NCUT[2];nz++){ 00327 if( !(i==j && nx==0 && ny==0 && nz==0) ) { 00328 if(nx*nx+ny*ny +nz*nz<= NCUT2){ 00329 rnz=rz+nz*box_l[2]; 00330 r2=rnx2+rny2+rnz*rnz; 00331 r=sqrt(r2); 00332 r3=r2*r; 00333 r5=r3*r2; 00334 r7=r5*r2; 00335 00336 00337 pe2=mx[i]*rnx+my[i]*rny+mz[i]*rnz; 00338 pe3=mx[j]*rnx+my[j]*rny+mz[j]*rnz; 00339 00340 /*fprintf(stderr,"--------------------------------\n"); 00341 fprintf(stderr,"ij: %d %d\n",i,j); 00342 fprintf(stderr,"xyz[i]: %lf %lf %lf\n",x[i],y[i],z[i]); 00343 fprintf(stderr,"xyz[j]: %lf %lf %lf\n",x[j],y[j],z[j]); 00344 fprintf(stderr,"mu xyz[i]: %lf %lf %lf\n",mx[i],my[i],mz[i]); 00345 fprintf(stderr,"mu xyz[j]: %lf %lf %lf\n",mx[j],my[j],mz[j]); 00346 fprintf(stderr,"rnxyz: %lf %lf %lf\n",rnx,rny,rnz); 00347 fprintf(stderr,"--------------------------------\n");*/ 00348 00349 00350 //Energy ............................ 00351 00352 u+= pe1/r3 - 3.0*pe2*pe3/r5; 00353 00354 if(force_flag) { 00355 //force ............................ 00356 a=mx[i]*mx[j]+my[i]*my[j]+mz[i]*mz[j]; 00357 a=3.0*a/r5; 00358 b=-15.0*pe2*pe3/r7; 00359 c=3.0*pe3/r5; 00360 d=3.0*pe2/r5; 00361 00362 fx[i]+=(a+b)*rnx+c*mx[i]+d*mx[j]; 00363 fy[i]+=(a+b)*rny+c*my[i]+d*my[j]; 00364 fz[i]+=(a+b)*rnz+c*mz[i]+d*mz[j]; 00365 00366 #ifdef ROTATION 00367 //torque ............................ 00368 c=3.0/r5*pe3; 00369 ax=my[i]*mz[j]-my[j]*mz[i]; 00370 ay=mx[j]*mz[i]-mx[i]*mz[j]; 00371 az=mx[i]*my[j]-mx[j]*my[i]; 00372 00373 bx=my[i]*rnz-rny*mz[i]; 00374 by=rnx*mz[i]-mx[i]*rnz; 00375 bz=mx[i]*rny-rnx*my[i]; 00376 00377 tx[i]+=-ax/r3+bx*c; 00378 ty[i]+=-ay/r3+by*c; 00379 tz[i]+=-az/r3+bz*c; 00380 #endif 00381 } /* of force_flag */ 00382 00383 } }/* of nx*nx+ny*ny +nz*nz< NCUT*NCUT and !(i==j && nx==0 && ny==0 && nz==0) */ 00384 }/* of for nz */ 00385 }/* of for ny */ 00386 }/* of for nx */ 00387 }} /* of j and i */ 00388 00389 00390 fprintf(stderr,"done \n"); 00391 }/* end of the area of calculation */ 00392 00393 00394 00395 /* set the forces, and torques of the particles within Espresso */ 00396 if(force_flag) { 00397 00398 dip_particles2=0; 00399 for (c = 0; c < local_cells.n; c++) { 00400 cell = local_cells.cell[c]; 00401 part = cell->part; 00402 np = cell->n; 00403 for(i=0;i<np;i++) { 00404 if( part[i].p.dipm > 1.e-11 ) { 00405 00406 part[i].f.f[0]+=coulomb.Dprefactor*fx[dip_particles2]; 00407 part[i].f.f[1]+=coulomb.Dprefactor*fy[dip_particles2]; 00408 part[i].f.f[2]+=coulomb.Dprefactor*fz[dip_particles2]; 00409 00410 #ifdef ROTATION 00411 part[i].f.torque[0]+=coulomb.Dprefactor*tx[dip_particles2]; 00412 part[i].f.torque[1]+=coulomb.Dprefactor*ty[dip_particles2]; 00413 part[i].f.torque[2]+=coulomb.Dprefactor*tz[dip_particles2]; 00414 #endif 00415 dip_particles2++; 00416 00417 } 00418 } 00419 } 00420 00421 /* small checking */ 00422 if(dip_particles != dip_particles2) { fprintf(stderr,"magnetic direct sum calculations: error mismatch of particles \n"); exit(1);} 00423 } /*of if force_flag */ 00424 00425 /* free memory used */ 00426 00427 free(x); 00428 free(y); 00429 free(z); 00430 free(mx); 00431 free(my); 00432 free(mz); 00433 00434 if(force_flag) { 00435 free(fx); 00436 free(fy); 00437 free(fz); 00438 #ifdef ROTATION 00439 free(tx); 00440 free(ty); 00441 free(tz); 00442 #endif 00443 } 00444 00445 return 0.5*u; 00446 } 00447 00448 int dawaanr_set_params() 00449 { 00450 if (n_nodes > 1) { 00451 return ES_ERROR; 00452 } 00453 if (coulomb.Dmethod != DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA ) { 00454 coulomb.Dmethod = DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA; 00455 } 00456 // also necessary on 1 CPU, does more than just broadcasting 00457 mpi_bcast_coulomb_params(); 00458 00459 return ES_OK; 00460 } 00461 00462 int mdds_set_params(int n_cut) 00463 { 00464 if (n_nodes > 1) { 00465 return ES_ERROR; 00466 } 00467 00468 Ncut_off_magnetic_dipolar_direct_sum = n_cut; 00469 00470 if (Ncut_off_magnetic_dipolar_direct_sum == 0) { 00471 fprintf(stderr,"Careful: the number of extra replicas to take into account during the direct sum calculation is zero \n"); 00472 } 00473 00474 if (coulomb.Dmethod != DIPOLAR_DS && coulomb.Dmethod != DIPOLAR_MDLC_DS) { 00475 coulomb.Dmethod = DIPOLAR_DS; 00476 } 00477 00478 // also necessary on 1 CPU, does more than just broadcasting 00479 mpi_bcast_coulomb_params(); 00480 return ES_OK; 00481 } 00482 00483 #endif
1.7.5.1