ESPResSo 3.2.0-167-g2c9ead1-git
Extensible Simulation Package for Soft Matter Research
rattle.c
Go to the documentation of this file.
00001 /*
00002   Copyright (C) 2010,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 #include <mpi.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <math.h>
00027 #include "domain_decomposition.h"
00028 #include "rattle.h"
00029 
00030 int n_rigidbonds = 0;
00031 
00032 #ifdef BOND_CONSTRAINT
00033 
00034 /** \name Private functions */
00035 /************************************************************/
00036 /*@{*/
00037 
00038 /** Calculates the corrections required for each of the particle coordinates
00039     according to the RATTLE algorithm. Invoked from \ref correct_pos_shake()*/
00040 void compute_pos_corr_vec(int *repeat_);
00041 
00042 /** Positional Corrections are added to the current particle positions. Invoked from \ref correct_pos_shake() */
00043 void app_pos_correction();
00044 
00045 /** Transfers temporarily the current forces from f.f[3] of the \ref Particle
00046     structure to r.p_old[3] location and also intializes velocity correction
00047     vector. Invoked from \ref correct_vel_shake()*/
00048 void transfer_force_init_vel();
00049 
00050 /** Calculates corrections of the  current particle velocities according to RATTLE
00051     algorithm. Invoked from \ref correct_vel_shake()*/
00052 void compute_vel_corr_vec(int *repeat_);
00053 
00054 /** Velocity corrections are added to the current particle velocities. Invoked from
00055     \ref correct_vel_shake()*/
00056 void apply_vel_corr();
00057 
00058 /**Invoked from \ref correct_vel_shake(). Put back the forces from r.p_old to f.f*/
00059 void revert_force();
00060 
00061 /**For debugging purpose--prints the bond lengths between particles that have
00062 rigid_bonds*/
00063 void print_bond_len();
00064 
00065 /*@}*/
00066 
00067 /*Initialize old positions (particle positions at previous time step)
00068   of the particles*/
00069 void save_old_pos()
00070 {
00071   int c, i, j, np;
00072   Particle *p;
00073   Cell *cell;
00074   for (c = 0; c < local_cells.n; c++)
00075   {
00076     cell = local_cells.cell[c];
00077     p  = cell->part;
00078     np = cell->n;
00079     for(i = 0; i < np; i++) {
00080       for(j=0;j<3;j++)
00081         p[i].r.p_old[j]=p[i].r.p[j];
00082     } //for i loop
00083   }// for c loop
00084 
00085   for (c = 0; c < ghost_cells.n; c++)
00086   {
00087     cell = ghost_cells.cell[c];
00088     p  = cell->part;
00089     np = cell->n;
00090     for(i = 0; i < np; i++) {
00091        for(j=0;j<3;j++)
00092           p[i].r.p_old[j]=p[i].r.p[j];
00093     }
00094   }
00095 }
00096 
00097 /**Initialize the correction vector. The correction vector is stored in f.f of particle strcuture. */
00098 void init_correction_vector()
00099 {
00100 
00101   int c, i, j, np;
00102   Particle *p;
00103   Cell *cell;
00104 
00105   for (c = 0; c < local_cells.n; c++)
00106   {
00107     cell = local_cells.cell[c];
00108     p  = cell->part;
00109     np = cell->n;
00110     for(i = 0; i < np; i++) {
00111       for(j=0;j<3;j++)
00112         p[i].f.f[j] = 0.0;
00113      } //for i loop
00114   }// for c loop
00115 
00116   for (c = 0; c < ghost_cells.n; c++)
00117   {
00118     cell = ghost_cells.cell[c];
00119     p  = cell->part;
00120     np = cell->n;
00121     for(i = 0; i < np; i++) {
00122        for(j=0;j<3;j++)
00123           p[i].f.f[j] = 0.0;
00124     }
00125   }
00126 }
00127 
00128 /**Compute positional corrections*/
00129 void compute_pos_corr_vec(int *repeat_)
00130 {
00131   Bonded_ia_parameters *ia_params;
00132   int i, j, k, c, np, cnt=-1;
00133   Cell *cell;
00134   Particle *p, *p1, *p2;
00135   double r_ij_t[3], r_ij[3], r_ij_dot, G, pos_corr, r_ij2;
00136 
00137   for (c = 0; c < local_cells.n; c++) {
00138     cell = local_cells.cell[c];
00139     p  = cell->part;
00140     np = cell->n;
00141     for(i = 0; i < np; i++) {
00142       p1 = &p[i];
00143       k=0;
00144       while(k<p1->bl.n) {
00145         ia_params = &bonded_ia_params[p1->bl.e[k++]];
00146         if( ia_params->type == BONDED_IA_RIGID_BOND ) {
00147           cnt++;
00148           p2 = local_particles[p1->bl.e[k++]];
00149           if (!p2) {
00150             char *errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
00151             ERROR_SPRINTF(errtxt,"{051 rigid bond broken between particles %d and %d (particles not stored on the same node)} ",
00152                     p1->p.identity, p1->bl.e[k-1]);
00153             return;
00154           }
00155 
00156           get_mi_vector(r_ij  , p1->r.p    , p2->r.p    );
00157           r_ij2 = sqrlen(r_ij);
00158           if(fabs(1.0 - r_ij2/ia_params->p.rigid_bond.d2) > ia_params->p.rigid_bond.p_tol) {
00159             get_mi_vector(r_ij_t, p1->r.p_old, p2->r.p_old);
00160             r_ij_dot = scalar(r_ij_t, r_ij);
00161             G = 0.50*(ia_params->p.rigid_bond.d2 - r_ij2 )/r_ij_dot;
00162 #ifdef MASS
00163             G /= (PMASS(*p1)+PMASS(*p2));
00164 #else
00165             G /= 2;
00166 #endif
00167             for (j=0;j<3;j++) {
00168               pos_corr = G*r_ij_t[j];
00169               p1->f.f[j] += pos_corr*PMASS(*p2);
00170               p2->f.f[j] -= pos_corr*PMASS(*p1);
00171             }
00172             /*Increase the 'repeat' flag by one */
00173               *repeat_ = *repeat_ + 1;
00174           }
00175         }
00176         else
00177           /* skip bond partners of nonrigid bond */
00178           k+=ia_params->num;
00179       } //while loop
00180     } //for i loop
00181   } //for c loop
00182 }
00183 
00184 /**Apply corrections to each particle**/
00185 void app_pos_correction()
00186 {
00187   int c, i, j, np;
00188   Particle *p, *p1;
00189   Cell *cell;
00190 
00191 
00192      /*Apply corrections*/
00193      for (c = 0; c < local_cells.n; c++)
00194      {
00195       cell = local_cells.cell[c];
00196       p  = cell->part;
00197       np = cell->n;
00198       for(i = 0; i < np; i++) {
00199         p1 = &p[i];
00200         for (j=0;j<3;j++) {
00201            p1->r.p[j] += p1->f.f[j];
00202            p1->m.v[j] += p1->f.f[j];
00203         }
00204 
00205         /**Completed for one particle*/
00206        } //for i loop
00207      } //for c loop
00208 }
00209 
00210 void correct_pos_shake()
00211 {
00212    int    repeat_,  cnt=0;
00213    int repeat=1;
00214 
00215    while (repeat!=0 && cnt<SHAKE_MAX_ITERATIONS)
00216    {
00217      init_correction_vector();
00218      repeat_ = 0;
00219      compute_pos_corr_vec(&repeat_);
00220      ghost_communicator(&cell_structure.collect_ghost_force_comm);
00221      app_pos_correction();
00222      /**Ghost Positions Update*/
00223      ghost_communicator(&cell_structure.update_ghost_pos_comm);
00224      if(this_node==0)
00225          MPI_Reduce(&repeat_, &repeat, 1, MPI_INT, MPI_SUM, 0, comm_cart);
00226      else
00227          MPI_Reduce(&repeat_, NULL, 1, MPI_INT, MPI_SUM, 0, comm_cart);
00228      MPI_Bcast(&repeat, 1, MPI_INT, 0, comm_cart);
00229 
00230        cnt++;
00231    }// while(repeat) loop
00232    if (cnt >= SHAKE_MAX_ITERATIONS) {
00233      char *errtxt = runtime_error(100 + ES_INTEGER_SPACE);
00234      ERROR_SPRINTF(errtxt, "{053 RATTLE failed to converge after %d iterations} ", cnt);
00235    }
00236 
00237    check_resort_particles();
00238 }
00239 
00240 /**The forces are transfered temporarily from f.f member of particle structure to r.p_old,
00241     which is idle now and initialize the velocity correction vector to zero at f.f[3]
00242     of Particle structure*/
00243 void transfer_force_init_vel()
00244 {
00245 
00246   int c, i, j, np;
00247   Particle *p;
00248   Cell *cell;
00249 
00250   for (c = 0; c < local_cells.n; c++)
00251     {
00252       cell = local_cells.cell[c];
00253       p  = cell->part;
00254       np = cell->n;
00255       for(i = 0; i < np; i++) {
00256         for(j=0;j<3;j++)
00257           {
00258             p[i].r.p_old[j]=p[i].f.f[j];
00259             p[i].f.f[j]=0.0;
00260           }
00261       } //for i loop
00262     }// for c loop
00263 
00264   for (c = 0; c < ghost_cells.n; c++)
00265     {
00266       cell = ghost_cells.cell[c];
00267       p  = cell->part;
00268       np = cell->n;
00269       for(i = 0; i < np; i++) {
00270         for(j=0;j<3;j++)
00271           {
00272             p[i].r.p_old[j]=p[i].f.f[j];
00273             p[i].f.f[j]=0.0;
00274           }
00275       }
00276     }
00277 }
00278 
00279 /** Velocity correction vectors are computed*/
00280 void compute_vel_corr_vec(int *repeat_)
00281 {
00282   Bonded_ia_parameters *ia_params;
00283   int i, j, k, c, np;
00284   Cell *cell;
00285   Particle *p, *p1, *p2;
00286   double v_ij[3], r_ij[3], K, vel_corr;
00287 
00288   for (c = 0; c < local_cells.n; c++)
00289     {
00290       cell = local_cells.cell[c];
00291       p  = cell->part;
00292       np = cell->n;
00293       for(i = 0; i < np; i++) {
00294         p1 = &p[i];
00295         k=0;
00296         while(k<p1->bl.n)
00297           {
00298             ia_params = &bonded_ia_params[p1->bl.e[k++]];
00299             if( ia_params->type == BONDED_IA_RIGID_BOND )
00300               {
00301                 p2 = local_particles[p1->bl.e[k++]];
00302                 if (!p2) {
00303                   char *errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
00304                   ERROR_SPRINTF(errtxt,"{054 rigid bond broken between particles %d and %d (particles not stored on the same node)} ",
00305                           p1->p.identity, p1->bl.e[k-1]);
00306                   return;
00307                 }
00308 
00309                 vecsub(p1->m.v, p2->m.v, v_ij);
00310                 get_mi_vector(r_ij, p1->r.p, p2->r.p);
00311                 if(fabs(scalar(v_ij, r_ij)) > ia_params->p.rigid_bond.v_tol)
00312                 {
00313                   K = scalar(v_ij, r_ij)/ia_params->p.rigid_bond.d2;
00314 #ifdef MASS
00315                   K /= (PMASS(*p1) + PMASS(*p2));
00316 #else
00317                   K /= 2.0;
00318 #endif
00319                 for (j=0;j<3;j++)
00320                   {
00321                     vel_corr = K*r_ij[j];
00322                     p1->f.f[j] -= vel_corr*PMASS(*p2);
00323                     p2->f.f[j] += vel_corr*PMASS(*p1);
00324                   }
00325                   *repeat_ = *repeat_ + 1 ;
00326                 }
00327               }
00328             else
00329               k += ia_params->num;
00330           } //while loop
00331       } //for i loop
00332     } //for c loop
00333 }
00334 
00335 /**Apply velocity corrections*/
00336 void apply_vel_corr()
00337 {
00338 
00339   int c, i, j, np;
00340   Particle *p, *p1;
00341   Cell *cell;
00342 
00343      /*Apply corrections*/
00344      for (c = 0; c < local_cells.n; c++)
00345      {
00346       cell = local_cells.cell[c];
00347       p  = cell->part;
00348       np = cell->n;
00349       for(i = 0; i < np; i++) {
00350         p1 = &p[i];
00351         for (j=0;j<3;j++) {
00352            p1->m.v[j] += p1->f.f[j];
00353 
00354         }
00355         /**Completed for one particle*/
00356        } //for i loop
00357      } //for c loop
00358 
00359 }
00360 
00361 /**Put back the forces from r.p_old to f.f*/
00362 void revert_force()
00363 {
00364   int c, i, j, np;
00365   Particle *p;
00366   Cell *cell;
00367   for (c = 0; c < local_cells.n; c++)
00368   {
00369     cell = local_cells.cell[c];
00370     p  = cell->part;
00371     np = cell->n;
00372     for(i = 0; i < np; i++) {
00373       for(j=0;j<3;j++)
00374         p[i].f.f[j]=p[i].r.p_old[j];
00375 
00376      } //for i loop
00377   }// for c loop
00378 
00379 
00380   for (c = 0; c < ghost_cells.n; c++)
00381   {
00382     cell = ghost_cells.cell[c];
00383     p  = cell->part;
00384     np = cell->n;
00385     for(i = 0; i < np; i++)
00386     {
00387        for(j=0;j<3;j++)
00388           p[i].f.f[j]=p[i].r.p_old[j];
00389     }
00390   }
00391 }
00392 
00393 void correct_vel_shake()
00394 {
00395    int    repeat_, repeat=1, cnt=0;
00396    /**transfer the current forces to r.p_old of the particle structure so that
00397    velocity corrections can be stored temporarily at the f.f[3] of the particle
00398    structure  */
00399    transfer_force_init_vel();
00400    while (repeat!=0 && cnt<SHAKE_MAX_ITERATIONS)
00401    {
00402      init_correction_vector();
00403      repeat_ = 0;
00404      compute_vel_corr_vec(&repeat_);
00405      ghost_communicator(&cell_structure.collect_ghost_force_comm);
00406      apply_vel_corr();
00407      ghost_communicator(&cell_structure.update_ghost_pos_comm);
00408      if(this_node == 0)
00409        MPI_Reduce(&repeat_, &repeat, 1, MPI_INT, MPI_SUM, 0, comm_cart);
00410      else
00411        MPI_Reduce(&repeat_, NULL, 1, MPI_INT, MPI_SUM, 0, comm_cart);
00412 
00413      MPI_Bcast(&repeat, 1, MPI_INT, 0, comm_cart);
00414      cnt++;
00415    }
00416 
00417    if (cnt >= SHAKE_MAX_ITERATIONS) {
00418          fprintf(stderr, "%d: VEL CORRECTIONS IN RATTLE failed to converge after %d iterations !!\n", this_node, cnt);
00419          errexit();
00420    }
00421    /**Puts back the forces from r.p_old to f.f[3]*/
00422    revert_force();
00423 }
00424 
00425 
00426 void print_bond_len()
00427 {
00428   int i, k, c, np;
00429   Cell *cell;
00430   Particle *p;
00431   Bonded_ia_parameters *b_ia;
00432   double r_ij[3];
00433   printf("%d: ", this_node);
00434   for (c = 0; c < local_cells.n; c++) {
00435     cell = local_cells.cell[c];
00436     p  = cell->part;
00437     np = cell->n;
00438     for(i = 0; i < np; i++) {
00439        k=0;
00440        while(k<p[i].bl.n)
00441        {
00442              b_ia = &bonded_ia_params[p[i].bl.e[k]];
00443              if(b_ia->type == BONDED_IA_RIGID_BOND)
00444              {
00445                Particle *p2 = local_particles[p[i].bl.e[k++]];
00446                if (!p2) {
00447                  char *errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE);
00448                  ERROR_SPRINTF(errtxt,"{056 rigid bond broken between particles %d and %d (particles not stored on the same node)} ", p[i].p.identity, p[i].bl.e[k-1]);
00449                  return;
00450                }
00451 
00452                get_mi_vector(r_ij, p[i].r.p , p2->r.p);
00453                printf(" bl (%d %d): %f\t", p[i].p.identity, p2->p.identity,sqrlen(r_ij));
00454              }
00455              else
00456                k += b_ia->num;
00457        } //while k loop
00458     } //for i loop
00459   }// for c loop
00460   printf("\n");
00461 }
00462 
00463 /*****************************************************************************
00464  *   setting parameters
00465  *****************************************************************************/
00466 int rigid_bond_set_params(int bond_type, double d, double p_tol, double v_tol)
00467 {
00468   if(bond_type < 0)
00469     return ES_ERROR;
00470 
00471   make_bond_type_exist(bond_type);
00472 
00473   bonded_ia_params[bond_type].p.rigid_bond.d2 = d*d;
00474   bonded_ia_params[bond_type].p.rigid_bond.p_tol = 2.0*p_tol;
00475   bonded_ia_params[bond_type].p.rigid_bond.v_tol = v_tol*time_step;
00476   bonded_ia_params[bond_type].type = BONDED_IA_RIGID_BOND;
00477   bonded_ia_params[bond_type].num = 1;
00478   n_rigidbonds += 1;
00479   mpi_bcast_ia_params(bond_type, -1);
00480   mpi_bcast_parameter(FIELD_RIGIDBONDS);
00481 
00482   return ES_OK;
00483 }
00484 
00485 #endif