![]() |
ESPResSo 3.2.0-159-gf5c8922-git
Extensible Simulation Package for Soft Matter Research
|
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
1.7.5.1