ESPResSo 3.2.0-159-gf5c8922-git
Extensible Simulation Package for Soft Matter Research
magnetic_non_p3m_methods.c
Go to the documentation of this file.
00001 /*
00002   Copyright (C) 2010,2011,2012,2013 The ESPResSo project
00003   Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 
00004     Max-Planck-Institute for Polymer Research, Theory Group
00005   
00006   This file is part of ESPResSo.
00007   
00008   ESPResSo is free software: you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation, either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   ESPResSo is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
00020 */
00021 /** \file 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