ESPResSo 3.2.0-11-g9950804-git
Extensible Simulation Package for Soft Matter Research
molforces.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 "utils.h"
00024 #include "grid.h"
00025 #include "molforces.h"
00026 #include "topology.h"
00027 #include "particle_data.h"
00028 #include "cells.h"
00029 #include "communication.h"
00030 #include "forces.h"
00031 
00032 /** \file molforces.c
00033  *  Routines for calculating and applying trap forces upon molecules.
00034  *  This trap force can be set to
00035  *  - a harmonic potential with a restlength of zero on the molecular centre of mass
00036  *  - a drag on the molecular velocity
00037  *  - a cancelation of the total force on the molecule (including thermostat forces)
00038  *  The centre of mass can be fixed to an absolute position or to a relative position in the
00039  *  simulation box.
00040  *  The molecular trap forces is distributed evenly upon all particles in a molecule.
00041  *  (see \ref topology.c and \ref molforces.c)  
00042  */
00043 
00044 #ifdef MOLFORCES
00045 
00046 
00047 /* global variable which indicates whether any molecules are trapped */
00048 /* set in  mpi_sync_topo_part_info_slave and set_molecule_trap */
00049 int IsTrapped = 0;
00050 
00051 void apply_mol_constraints()
00052 {
00053   Particle *p;
00054   int i, np, c, mi;
00055   Cell *cell;
00056   int j;
00057 
00058   for (c = 0; c < local_cells.n; c++) {
00059     cell = local_cells.cell[c];
00060     p  = cell->part;
00061     np = cell->n;
00062     for(i = 0; i < np; i++) {
00063       mi = p[i].p.mol_id;
00064       for(j = 0; j < 3; j++) {
00065         /* Applies the trap force for this coordinate and this particle. */  
00066         p[i].f.f[j] += topology[mi].trap_force[j];
00067       }
00068     }
00069   }
00070 }
00071 
00072 /* calculates the force applies by traps on all molecules */
00073 void calc_trap_force()
00074 {
00075   Molecule *m;
00076   int mi,j;
00077 #ifdef EXTERNAL_FORCES
00078   double trappos;
00079 #endif
00080   
00081 
00082   if ( !topo_part_info_synced ) {
00083     char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE);
00084     ERROR_SPRINTF(errtxt, "{ 093 can't calculate moltrap: must execute analyse set topo_part_sync first }");
00085     return;
00086   } else {
00087     
00088     m = &topology[0];
00089     
00090     for (mi = 0; mi < n_molecules; mi++) {
00091       m = &topology[mi];
00092       for(j = 0; j < 3; j++) {
00093 #ifdef EXTERNAL_FORCES
00094         if (m->trap_flag & COORD_FIXED(j)) {
00095           /* Is the molecule trapped at a certain position in space? */
00096           if (m->isrelative == 1) {
00097             /* Is the trap set to absolute coordinates... */
00098             trappos = m->trap_center[j]*box_l[j];
00099           } else {
00100             /* or to relative ones? */
00101             trappos = m->trap_center[j];
00102           }
00103           m->trap_force[j] = 0;
00104           /* the trap_force holding the molecule to the set position in calculated */
00105           m->trap_force[j] += -((m->com[j]-trappos)*m->trap_spring_constant)/(double)(m->part.n);
00106           /* the drag force applied to the molecule is calculated */
00107           m->trap_force[j] += -(m->v[j]*m->drag_constant)/(double)(m->part.n);
00108           /* the force applies by the traps is added to fav */
00109           /* favcounter counts how many times we have added the force to fav since last time "analyze mol force" was called */
00110           /* upon Espresso initialization it is set to -1 because in the first call of "integrate" there is an extra initial time step */
00111           /* calling "analyze mol force" resets favcounter to 0 */
00112           if (m->favcounter > -1) m->fav[j] -= m->v[j]*m->drag_constant + (m->com[j]-trappos)*m->trap_spring_constant;
00113         }
00114         if (m->noforce_flag & COORD_FIXED(j)) {
00115           /* the trap force required to cancel out the total force acting on the molecule is calculated */
00116           m->trap_force[j] -= m->f[j]/(double)m->part.n;
00117           if (m->favcounter > -1) m->fav[j] -= m->f[j];
00118         }
00119 #endif
00120       }
00121       m->favcounter++;
00122     }
00123   }
00124 }
00125 
00126 /* A list of trapped molecules present on this node is created (local_trapped_mols)*/
00127 void get_local_trapped_mols (IntList *local_trapped_mols)
00128 {
00129   int c, i, mol, j, fixed;
00130 
00131   for (c = 0; c < local_cells.n; c++) {
00132     for(i = 0; i < local_cells.cell[c]->n; i++) {
00133       mol = local_cells.cell[c]->part[i].p.mol_id;
00134       if ( mol >= n_molecules ) {
00135         char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE);
00136         ERROR_SPRINTF(errtxt, "{ 094 can't calculate molforces no such molecule as %d }",mol);
00137         return;
00138       }
00139 
00140       /* Check to see if this molecule is fixed */
00141       fixed =0;
00142       for(j = 0; j < 3; j++) {
00143 #ifdef EXTERNAL_FORCES
00144         if (topology[mol].trap_flag & COORD_FIXED(j)) fixed = 1;
00145         if (topology[mol].noforce_flag & COORD_FIXED(j)) fixed = 1;
00146 #endif
00147       }  
00148       if (fixed) {
00149         /* if this molecule isn't already in local_trapped_mols then add it in */
00150         if (!intlist_contains(local_trapped_mols,mol)) {
00151           realloc_intlist(local_trapped_mols, local_trapped_mols->max + 1);
00152           local_trapped_mols->e[local_trapped_mols->max-1] = mol;
00153           local_trapped_mols->n = local_trapped_mols->max;
00154         }
00155       }
00156     }
00157   }
00158 }
00159 
00160 /* Calculate forces, mass,  and unnormalized center of mass and velocity*/
00161 /* This is only done for the trapped molecules to save time */
00162 void calc_local_mol_info (IntList *local_trapped_mols)
00163 {
00164   int mi, i,j, mol;
00165   Particle *p;
00166   int np, c;
00167   Cell *cell;
00168   int lm;
00169   int fixed;
00170 
00171   /* First reset all molecule masses,forces,centers of mass*/
00172   for ( mi = 0 ; mi < n_molecules ; mi++ ) {
00173     topology[mi].mass = 0;
00174     for ( i = 0 ; i < 3 ; i++) {
00175       topology[mi].f[i] = 0.0;
00176       topology[mi].com[i] = 0.0;
00177       topology[mi].v[i] = 0.0;
00178     }
00179   }
00180 
00181   for (c = 0; c < local_cells.n; c++) {
00182     cell = local_cells.cell[c];
00183     p  = cell->part;
00184     np = cell->n;
00185     for(i = 0; i < np; i++) {
00186       mol = p[i].p.mol_id;
00187       if ( mol >= n_molecules ) {
00188         char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE);
00189         ERROR_SPRINTF(errtxt, "{ 094 can't calculate molforces no such molecule as %d }",mol);
00190         return;
00191       }
00192 
00193       /* Check to see if this molecule is fixed */
00194       fixed =0;
00195       for(j = 0; j < 3; j++) {
00196 #ifdef EXTERNAL_FORCES
00197         if (topology[mol].trap_flag & COORD_FIXED(j)) fixed = 1;
00198         if (topology[mol].noforce_flag & COORD_FIXED(j)) fixed = 1;
00199 #endif
00200       }  
00201       if (fixed) {
00202         topology[mol].mass += PMASS(p[i]);
00203         /* Unfold the particle */
00204         unfold_position(p[i].r.p,p[i].l.i);
00205         for ( j = 0 ; j < 3 ; j++ ) {
00206           topology[mol].f[j] += p[i].f.f[j];
00207           topology[mol].com[j] += p[i].r.p[j]*PMASS(p[i]); 
00208           topology[mol].v[j] += p[i].m.v[j]*PMASS(p[i]); 
00209         }
00210         /* Fold the particle back */
00211         fold_position(p[i].r.p,p[i].l.i);
00212 
00213       }
00214     }
00215   }
00216 
00217   /* Final normalisation of centers of mass and velocity*/
00218   for ( lm = 0 ; lm < local_trapped_mols->n; lm++ ) {
00219     mi = local_trapped_mols->e[lm];
00220     for ( i = 0 ; i < 3 ; i++) {
00221       topology[mi].com[i] = topology[mi].com[i]/(double)(topology[mi].mass);
00222       topology[mi].v[i] = topology[mi].v[i]/(double)(topology[mi].mass);
00223     }
00224   }
00225 
00226 }
00227 
00228 /* Receives molecule information from the slave nodes. Combines this information,
00229    calculates trap forces, and returns information to slave nodes */
00230 
00231 void mpi_comm_mol_info(IntList *local_trapped_mols) {
00232   int i, j, k, mol, count;
00233   double com[3] = {0,0,0};
00234   double v[3] = {0,0,0};
00235   double f[3] = {0,0,0};
00236   double mass = 0;
00237   /* number of trapped molecules on each node */
00238   int *n_local_mols;
00239   /* sum of all elements of n_local_mols */
00240   int sum_n_local_mols;
00241   /* lists of which molecules are on each node in order of ascending node number */
00242   int *local_mols;
00243   MPI_Status status;
00244 
00245   n_local_mols = malloc(n_nodes*sizeof(int));
00246   sum_n_local_mols = 0;
00247 
00248   /* Everyone tells me how many trapped molecules are on their node */
00249   for (i=1; i <n_nodes; i++) {
00250     MPI_Recv(&(n_local_mols[i]),1,MPI_INT,i,99,comm_cart,&status);
00251   }
00252 
00253   for (i=1; i <n_nodes; i++) {
00254     sum_n_local_mols += n_local_mols[i];
00255   }
00256   local_mols = malloc(sum_n_local_mols*sizeof(int));
00257 
00258   /* Everyone tells me which trapped molecules are on their node */
00259   count = 0;
00260   for (i=1; i <n_nodes; i++) {
00261     MPI_Recv(&(local_mols[count]),n_local_mols[i],MPI_INT,i,99,comm_cart,&status);
00262     count += n_local_mols[i];
00263   }
00264 
00265   /* Initialise the centre of masses, velocities and forces to 0
00266      except for molecules present on master node which are initialized to the local values on the master node
00267      The centre of masses and velocities are weighted by the total mass on the master node */
00268   for (i = 0; i < n_molecules; i++) {
00269     mol =i;
00270     if (intlist_contains(local_trapped_mols,i)) {
00271       for (j = 0; j < 3; j++) {
00272         topology[mol].com[j] = topology[mol].com[j] * topology[mol].mass;
00273         topology[mol].v[j] = topology[mol].v[j] * topology[mol].mass;
00274         topology[mol].f[j] = topology[mol].f[j];
00275       }
00276     } else {
00277       topology[mol].mass = 0;
00278       for (j = 0; j < 3; j++) {
00279         topology[mol].com[j] = 0;
00280         topology[mol].v[j] = 0;
00281         topology[mol].f[j] = 0;
00282       }
00283     }
00284   }
00285   
00286   /* The masses, coms, velocities and forces for trapped molecules are received from the slave nodes.
00287      They are added into the running sums in topology[mol] */
00288   count = 0;
00289   for (i = 1; i < n_nodes; i++) {
00290     for (j = 0; j < n_local_mols[i]; j++) {
00291       mol = local_mols[count];
00292       count += 1;
00293       MPI_Recv(&mass,1,MPI_DOUBLE,i,99,comm_cart,&status);
00294       MPI_Recv(com,3,MPI_DOUBLE,i,99,comm_cart,&status);
00295       MPI_Recv(v,3,MPI_DOUBLE,i,99,comm_cart,&status);
00296       MPI_Recv(f,3,MPI_DOUBLE,i,99,comm_cart,&status);
00297       topology[mol].mass = topology[mol].mass + mass;
00298       for (k = 0; k< 3; k++) {
00299         topology[mol].com[k] += com[k]*mass;
00300         topology[mol].v[k] += v[k]*mass;
00301         topology[mol].f[k] += f[k];
00302       }
00303     }    
00304   }
00305 
00306   /* The centre of masses and velocities are renormalized by the total molecular weights */
00307   for (mol = 0; mol < n_molecules; mol++) {
00308     for (k=0;k <3; k ++) {
00309       topology[mol].com[k] = topology[mol].com[k]/topology[mol].mass;
00310       topology[mol].v[k] = topology[mol].v[k]/topology[mol].mass;
00311     }
00312   }
00313 
00314   /* The force exerted by the traps on the molecules are calculated */
00315   calc_trap_force();
00316 
00317   /* The molecule information and trap forces are sent back to the slave nodes. */
00318   count = 0;
00319   for (i = 1; i < n_nodes ; i++) {
00320     for (j = 0; j < n_local_mols[i]; j++) {
00321       mol = local_mols[count];
00322       count += 1;
00323       MPI_Send(&(topology[mol].mass),1,MPI_DOUBLE,i,99,comm_cart);
00324       MPI_Send(topology[mol].com,3,MPI_DOUBLE,i,99,comm_cart);
00325       MPI_Send(topology[mol].v,3,MPI_DOUBLE,i,99,comm_cart);
00326       MPI_Send(topology[mol].f,3,MPI_DOUBLE,i,99,comm_cart);
00327       MPI_Send(topology[mol].trap_force,3,MPI_DOUBLE,i,99,comm_cart);
00328     }
00329   }
00330 
00331   free(local_mols);
00332   free(n_local_mols);
00333 
00334 }
00335 
00336 /* Send molecule information to the master node.
00337    Recieve the combined molecule information and the trap forces */
00338 
00339 void mpi_comm_mol_info_slave(IntList *local_trapped_mols) {
00340   int i, mol;
00341   MPI_Status status;
00342 
00343   /* Tells master how many trapped molecules are on this node */
00344   MPI_Send(&(local_trapped_mols->n),1,MPI_INT,0,99,comm_cart);
00345 
00346   /* Tells master which trapped molecules are on this node */
00347   MPI_Send(local_trapped_mols->e,local_trapped_mols->n,MPI_INT,0,99,comm_cart);
00348 
00349   for (i = 0; i < local_trapped_mols->n ; i++) {
00350     mol = local_trapped_mols->e[i];
00351     /* Send all the masses and coms of the local molecules to the master node */
00352     MPI_Send(&(topology[mol].mass),1,MPI_DOUBLE,0,99,comm_cart);
00353     MPI_Send(topology[mol].com,3,MPI_DOUBLE,0,99,comm_cart);
00354     MPI_Send(topology[mol].v,3,MPI_DOUBLE,0,99,comm_cart);
00355     MPI_Send(topology[mol].f,3,MPI_DOUBLE,0,99,comm_cart);
00356   }
00357 
00358   for (i = 0; i < local_trapped_mols->n ; i++) {
00359     /* Receive all the masses and coms of the local molecules to the master node including info from other nodes*/
00360     mol = local_trapped_mols->e[i];
00361     MPI_Recv(&(topology[mol].mass),1,MPI_DOUBLE,0,99,comm_cart,&status);
00362     MPI_Recv(topology[mol].com,3,MPI_DOUBLE,0,99,comm_cart,&status);
00363     MPI_Recv(topology[mol].v,3,MPI_DOUBLE,0,99,comm_cart,&status);
00364     MPI_Recv(topology[mol].f,3,MPI_DOUBLE,0,99,comm_cart,&status);
00365     MPI_Recv(topology[mol].trap_force,3,MPI_DOUBLE,0,99,comm_cart,&status);
00366   }
00367 
00368 }
00369 
00370 /** 
00371     Calculate the center of mass, total mass, velocity, total force, and trap force on all trapped molecules 
00372 */
00373 void calc_mol_info () {
00374 
00375   /* list of trapped molecules on this node */
00376   IntList local_trapped_mols;
00377 
00378   /* check to see if all the topology information has been synced to the various slave nodes */
00379   if ( !topo_part_info_synced ) {
00380     char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE);
00381     ERROR_SPRINTF(errtxt, "{ 093 can't calculate molforces: must execute analyse set topo_part_sync first }");
00382     return;
00383   }
00384 
00385   init_intlist(&local_trapped_mols);
00386 
00387   /* Find out which trapped molecules are on this node */
00388   get_local_trapped_mols(&local_trapped_mols);
00389 
00390   /* Calculate the center of mass, mass, velocity, force of whatever fraction of each trapped molecule is on this node*/
00391   calc_local_mol_info(&local_trapped_mols);
00392 
00393   /* Communicate all this molecular information between nodes.
00394      It is all sent to the master node which combines it, calculates the trap forces,
00395      and sends the information back */
00396   if (this_node == 0) { 
00397     mpi_comm_mol_info(&local_trapped_mols);
00398   } else {
00399     mpi_comm_mol_info_slave(&local_trapped_mols);
00400   }
00401 
00402   realloc_intlist(&local_trapped_mols,0);
00403 }
00404 
00405 void calc_and_apply_mol_constraints ()
00406 {
00407   if (IsTrapped) {
00408     /* the molecular information and trap forces are calculated */
00409     calc_mol_info();
00410     /* the trap forces are applied to the particles */
00411     apply_mol_constraints();
00412   }
00413 }
00414 
00415 #endif