ESPResSo 3.2.0-159-gf5c8922-git
Extensible Simulation Package for Soft Matter Research
metadynamics.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 "metadynamics.h"
00023 #include "errorhandling.h"
00024 #include "grid.h"
00025 #include "cells.h"
00026 
00027 /** \file metadynamics.h 
00028 *
00029 *  This file contains routines to perform metadynamics.  Right now, the
00030 *  reaction coordinate is defined between two particles (either distance 
00031 *  or z-projected distance). Note that these
00032 *  particles can be virtual sites, in order to handle molecules.
00033 *
00034 *  - set metadynamics options 
00035 *  - initialize bias forces and free energy profiles 
00036 *  - calculate reaction coordinate for each integration step 
00037 *  - apply bias force on particles
00038 */
00039 
00040 
00041 #ifdef METADYNAMICS
00042 /* metadynamics switch */
00043 int    meta_switch       = META_OFF;
00044 /** pid of particle 1 */
00045 int    meta_pid1         =       -1;
00046 /** pid of particle 2 */
00047 int    meta_pid2         =       -1;
00048 /** bias height */
00049 double meta_bias_height  =    0.001;
00050 /** bias width */
00051 double meta_bias_width   =      0.5;
00052 
00053 /** REACTION COORDINATE */
00054 /** RC min */
00055 double meta_xi_min       =        1;
00056 /** RC max */
00057 double meta_xi_max       =        0;
00058 /** Force at boundaries */
00059 double meta_f_bound      =       10;
00060 /** Number of bins of RC */
00061 int    meta_xi_num_bins  =      100;
00062 double meta_xi_step      =        1;
00063 
00064 
00065 /** Accumulated force array */
00066 double *meta_acc_force   =     NULL;
00067 /** Accumulated free energy profile */
00068 double *meta_acc_fprofile=     NULL;
00069 
00070 
00071 double *meta_cur_xi      =     NULL;
00072 double meta_val_xi       =       0.;
00073 double *meta_apply_direction = NULL;
00074 
00075 void meta_init(){
00076    if(meta_switch == META_OFF)   return;
00077    
00078    
00079    /* Initialize arrays if they're empty. These get freed upon calling the Tcl
00080     * parser */
00081    if (meta_acc_force == NULL || meta_acc_fprofile == NULL) {
00082       meta_acc_force       = calloc(meta_xi_num_bins * sizeof *meta_acc_force, sizeof *meta_acc_force);
00083       meta_acc_fprofile    = calloc(meta_xi_num_bins * sizeof *meta_acc_fprofile, sizeof *meta_acc_fprofile);
00084       meta_cur_xi          = calloc(3 * sizeof *meta_cur_xi, sizeof *meta_cur_xi);
00085       meta_apply_direction = calloc(3 * sizeof *meta_apply_direction, sizeof *meta_apply_direction);   
00086    }
00087    
00088    /* Check that the simulation uses onle a single processor. Otherwise exit. 
00089    *  MPI interface *not* implemented. */
00090    if (n_nodes != 1) {
00091       char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE);
00092       ERROR_SPRINTF(errtxt,"Can't use metadynamics on more than one processor.\n");
00093       return;
00094    }
00095    
00096    meta_xi_step = (meta_xi_max-meta_xi_min)/(1.*meta_xi_num_bins);
00097 }
00098 
00099 
00100 /** Metadynamics main function:
00101 * - Calculate reaction coordinate
00102 * - Update profile and biased force
00103 * - apply external force
00104 */
00105 void meta_perform()
00106 {
00107    if(meta_switch == META_OFF)  return;
00108    
00109    double ppos1[3] = {0,0,0}, ppos2[3] = {0,0,0}, factor;
00110    int img1[3], img2[3], c, i, np, flag1 = 0, flag2 = 0;
00111    Particle *p, *p1 = NULL, *p2 = NULL;
00112    Cell *cell;
00113    
00114    for (c = 0; c < local_cells.n; c++) {
00115       cell = local_cells.cell[c];
00116       p  = cell->part;
00117       np = cell->n;
00118       for(i = 0; i < np; i++) {
00119          if (p[i].p.identity == meta_pid1) {
00120             flag1 = 1;
00121             p1 = &p[i];
00122             memcpy(ppos1, p[i].r.p, 3*sizeof(double));
00123             memcpy(img1, p[i].l.i, 3*sizeof(int));
00124             unfold_position(ppos1, img1);
00125             if (flag1 && flag2) {
00126                /* vector r2-r1 - Not a minimal image! Unfolded position */
00127                vector_subt(meta_cur_xi,ppos2,ppos1);
00128                break;
00129             }
00130          }
00131          if (p[i].p.identity == meta_pid2) {
00132             flag2 = 1;
00133             p2 = &p[i];
00134             memcpy(ppos2, p[i].r.p, 3*sizeof(double));
00135             memcpy(img2, p[i].l.i, 3*sizeof(int));
00136             unfold_position(ppos2, img2);
00137             if (flag1 && flag2) {
00138                /* vector r2-r1 - Not a minimal image! Unfolded position */
00139                vector_subt(meta_cur_xi,ppos2,ppos1);
00140                break;
00141             }
00142          }
00143       }
00144    }
00145    
00146    if (flag1 == 0 || flag2 == 0) {
00147       char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE);
00148       ERROR_SPRINTF(errtxt,"Metadynamics: can't find pid1 or pid2.\n");
00149       return;
00150    }
00151    
00152    /* Now update free energy profile 
00153    * Here, we're following the functional form of 
00154    * Marsili etal., J Comp. Chem, 31 (2009).
00155    * Instead of gaussians, we use so-called Lucy's functions */
00156    
00157    for (i = 0; i < meta_xi_num_bins; ++i) {
00158       if (meta_switch == META_DIST) {
00159          // reaction coordinate value
00160          meta_val_xi = sqrt(sqrlen(meta_cur_xi));
00161          // Update free energy profile and biased force
00162          meta_acc_fprofile[i] -= calculate_lucy(meta_xi_min+i*meta_xi_step,meta_val_xi);
00163          meta_acc_force[i] -= calculate_deriv_lucy(meta_xi_min+i*meta_xi_step,meta_val_xi);
00164          
00165          // direction of the bias force
00166          unit_vector(meta_cur_xi,meta_apply_direction);
00167       } else if (meta_switch == META_REL_Z) {
00168          // reaction coordinate value: relative height of z_pid1 with respect to z_pid2
00169          meta_val_xi = -1.*meta_cur_xi[2];
00170          // Update free energy profile and biased force
00171          meta_acc_fprofile[i] -= calculate_lucy(meta_xi_min+i*meta_xi_step,meta_val_xi);
00172          meta_acc_force[i] -= calculate_deriv_lucy(meta_xi_min+i*meta_xi_step,meta_val_xi);
00173          
00174          // direction of the bias force (-1 to be consistent with META_DIST: from 1 to 2)
00175          meta_apply_direction[0] = meta_apply_direction[1] = 0.;
00176          meta_apply_direction[2] = -1.;
00177       } else {
00178          char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE);
00179          ERROR_SPRINTF(errtxt,"Undefined metadynamics scheme.\n");
00180          return;      
00181       }
00182    }
00183    
00184    /** Apply force */
00185    
00186    // Calculate the strength of the applied force
00187    if (meta_val_xi < meta_xi_min) {
00188       // below the lower bound
00189       factor = -1. * meta_f_bound * (meta_xi_min-meta_val_xi)/meta_xi_step;
00190    } else if (meta_val_xi > meta_xi_max) {
00191       // above the upper bound
00192       factor = meta_f_bound * (meta_val_xi-meta_xi_max)/meta_xi_step;
00193    } else {
00194       // within the RC interval
00195       i = (int) dround((meta_val_xi-meta_xi_min)/meta_xi_step);
00196       if (i < 0) i = 0;
00197       if (i >= meta_xi_num_bins) i=meta_xi_num_bins-1;
00198       factor = meta_acc_force[i];
00199    }
00200    
00201    /* cancel previous force to external force of particle */
00202    for (i = 0; i<3; ++i) {
00203       p1->f.f[i] +=       factor * meta_apply_direction[i];
00204       p2->f.f[i] += -1. * factor * meta_apply_direction[i];
00205    }
00206 }
00207 
00208 
00209 /** Calculate Lucy's function */
00210 double calculate_lucy(double xi, double xi_0)
00211 {  
00212    double dist = fabs(xi-xi_0);
00213    if (dist <= meta_bias_width) {
00214       return meta_bias_height 
00215       * (1+2*dist/meta_bias_width) 
00216       * pow(1-dist/meta_bias_width,2);
00217    } else 
00218       return 0.;
00219 }
00220 
00221 /** Calculate derivative of Lucy function */
00222 double calculate_deriv_lucy(double xi, double xi_0)
00223 {
00224    double dist = fabs(xi-xi_0);
00225    if (dist <= meta_bias_width) {
00226       double result = -2*meta_bias_height/meta_bias_width
00227       * (pow(1-dist/meta_bias_width,2)
00228       -(1+2*dist/meta_bias_width)*(1-dist/meta_bias_width));
00229       if (xi < xi_0)
00230          result *= -1.;
00231       return result;
00232    } else
00233       return 0.;
00234 }
00235 
00236 
00237 
00238 #endif