![]() |
ESPResSo 3.2.0-11-g9950804-git
Extensible Simulation Package for Soft Matter Research
|
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 energy.h 00022 Implementation of the energy calculation. 00023 */ 00024 #ifndef _ENERGY_H 00025 #define _ENERGY_H 00026 #include "utils.h" 00027 #include "integrate.h" 00028 #include "statistics.h" 00029 #include "thermostat.h" 00030 00031 /* include the energy files */ 00032 #include "p3m.h" 00033 #include "p3m-dipolar.h" 00034 #include "lj.h" 00035 #include "ljgen.h" 00036 #include "steppot.h" 00037 #include "hertzian.h" 00038 #include "gaussian.h" 00039 #include "bmhtf-nacl.h" 00040 #include "buckingham.h" 00041 #include "soft_sphere.h" 00042 #include "hat.h" 00043 #include "ljcos.h" 00044 #include "ljcos2.h" 00045 #include "ljangle.h" 00046 #include "tab.h" 00047 #include "overlap.h" 00048 #include "gb.h" 00049 #include "fene.h" 00050 #include "object-in-fluid/stretching_force.h" 00051 #include "object-in-fluid/area_force_local.h" 00052 #include "object-in-fluid/area_force_global.h" 00053 #include "object-in-fluid/bending_force.h" 00054 #include "object-in-fluid/volume_force.h" 00055 #include "harmonic.h" 00056 #include "subt_lj.h" 00057 #include "angle.h" 00058 #include "angle_harmonic.h" 00059 #include "angle_cosine.h" 00060 #include "angle_cossquare.h" 00061 #include "angledist.h" 00062 #include "dihedral.h" 00063 #include "debye_hueckel.h" 00064 #include "endangledist.h" 00065 #include "reaction_field.h" 00066 #include "mmm1d.h" 00067 #include "mmm2d.h" 00068 #include "maggs.h" 00069 #include "morse.h" 00070 #include "elc.h" 00071 #include "mdlc_correction.h" 00072 00073 /** \name Exported Variables */ 00074 /************************************************************/ 00075 /*@{*/ 00076 /// 00077 extern Observable_stat energy, total_energy; 00078 /*@}*/ 00079 00080 /** \name Exported Functions */ 00081 /************************************************************/ 00082 /*@{*/ 00083 00084 /** allocate energy arrays and initialize with zero */ 00085 void init_energies(Observable_stat *stat); 00086 00087 /** on the master node: calc energies only if necessary */ 00088 void master_energy_calc(); 00089 00090 /** parallel energy calculation. 00091 @param result non-zero only on master node; will contain the cumulative over all nodes. */ 00092 void energy_calc(double *result); 00093 00094 /** Calculate non bonded energies between a pair of particles. 00095 @param p1 pointer to particle 1. 00096 @param p2 pointer to particle 2. 00097 @param ia_params the interaction parameters between the two particles 00098 @param d vector between p1 and p2. 00099 @param dist distance between p1 and p2. 00100 @param dist2 distance squared between p1 and p2. 00101 @return the short ranged interaction energy between the two particles 00102 */ 00103 MDINLINE double calc_non_bonded_pair_energy(Particle *p1, Particle *p2, 00104 IA_parameters *ia_params, 00105 double d[3], double dist, double dist2) 00106 { 00107 double ret = 0; 00108 00109 #ifdef NO_INTRA_NB 00110 if (p1->p.mol_id==p2->p.mol_id) return 0; 00111 #endif 00112 00113 #ifdef MOL_CUT 00114 //You may want to put a correction factor for smoothing function else then theta 00115 if (checkIfParticlesInteractViaMolCut(p1,p2,ia_params)==0) return 0; 00116 #endif 00117 00118 #ifdef LENNARD_JONES 00119 /* lennard jones */ 00120 ret += lj_pair_energy(p1,p2,ia_params,d,dist); 00121 #endif 00122 00123 #ifdef LENNARD_JONES_GENERIC 00124 /* Generic lennard jones */ 00125 ret += ljgen_pair_energy(p1,p2,ia_params,d,dist); 00126 #endif 00127 00128 #ifdef LJ_ANGLE 00129 /* Directional LJ */ 00130 ret += ljangle_pair_energy(p1,p2,ia_params,d,dist); 00131 #endif 00132 00133 #ifdef SMOOTH_STEP 00134 /* smooth step */ 00135 ret += SmSt_pair_energy(p1,p2,ia_params,d,dist,dist2); 00136 #endif 00137 00138 #ifdef HERTZIAN 00139 /* Hertzian potential */ 00140 ret += hertzian_pair_energy(p1,p2,ia_params,d,dist,dist2); 00141 #endif 00142 00143 #ifdef GAUSSIAN 00144 /* Gaussian potential */ 00145 ret += gaussian_pair_energy(p1,p2,ia_params,d,dist,dist2); 00146 #endif 00147 00148 #ifdef BMHTF_NACL 00149 /* BMHTF NaCl */ 00150 ret += BMHTF_pair_energy(p1,p2,ia_params,d,dist,dist2); 00151 #endif 00152 00153 #ifdef MORSE 00154 /* morse */ 00155 ret +=morse_pair_energy(p1,p2,ia_params,d,dist); 00156 #endif 00157 00158 #ifdef BUCKINGHAM 00159 /* lennard jones */ 00160 ret += buck_pair_energy(p1,p2,ia_params,d,dist); 00161 #endif 00162 00163 #ifdef SOFT_SPHERE 00164 /* soft-sphere */ 00165 ret += soft_pair_energy(p1,p2,ia_params,d,dist); 00166 #endif 00167 00168 #ifdef HAT 00169 /* hat */ 00170 ret += hat_pair_energy(p1,p2,ia_params,d,dist); 00171 #endif 00172 00173 #ifdef LJCOS2 00174 /* lennard jones */ 00175 ret += ljcos2_pair_energy(p1,p2,ia_params,d,dist); 00176 #endif 00177 00178 #ifdef TABULATED 00179 /* tabulated */ 00180 ret += tabulated_pair_energy(p1,p2,ia_params,d,dist); 00181 #endif 00182 00183 #ifdef LJCOS 00184 /* lennard jones cosine */ 00185 ret += ljcos_pair_energy(p1,p2,ia_params,d,dist); 00186 #endif 00187 00188 #ifdef GAY_BERNE 00189 /* Gay-Berne */ 00190 ret += gb_pair_energy(p1,p2,ia_params,d,dist); 00191 #endif 00192 00193 #ifdef INTER_RF 00194 ret += interrf_pair_energy(p1,p2,ia_params,dist); 00195 #endif 00196 00197 return ret; 00198 } 00199 00200 /** Add non bonded energies and short range coulomb between a pair of particles. 00201 @param p1 pointer to particle 1. 00202 @param p2 pointer to particle 2. 00203 @param d vector between p1 and p2. 00204 @param dist distance between p1 and p2. 00205 @param dist2 distance squared between p1 and p2. */ 00206 MDINLINE void add_non_bonded_pair_energy(Particle *p1, Particle *p2, double d[3], 00207 double dist, double dist2) 00208 { 00209 IA_parameters *ia_params = get_ia_param(p1->p.type,p2->p.type); 00210 00211 #if defined(ELECTROSTATICS) || defined(DIPOLES) 00212 double ret = 0; 00213 #endif 00214 00215 *obsstat_nonbonded(&energy, p1->p.type, p2->p.type) += 00216 calc_non_bonded_pair_energy(p1, p2, ia_params, d, dist, dist2); 00217 00218 #ifdef ELECTROSTATICS 00219 if (coulomb.method != COULOMB_NONE) { 00220 /* real space coulomb */ 00221 switch (coulomb.method) { 00222 #ifdef P3M 00223 case COULOMB_P3M: 00224 ret = p3m_pair_energy(p1->p.q*p2->p.q,d,dist2,dist); 00225 break; 00226 case COULOMB_ELC_P3M: 00227 ret = p3m_pair_energy(p1->p.q*p2->p.q,d,dist2,dist); 00228 if (elc_params.dielectric_contrast_on) 00229 ret += 0.5*ELC_P3M_dielectric_layers_energy_contribution(p1,p2); 00230 break; 00231 #endif 00232 case COULOMB_DH: 00233 ret = dh_coulomb_pair_energy(p1,p2,dist); 00234 break; 00235 case COULOMB_RF: 00236 ret = rf_coulomb_pair_energy(p1,p2,dist); 00237 break; 00238 case COULOMB_INTER_RF: 00239 //this is done above as interaction 00240 ret = 0; 00241 break; 00242 case COULOMB_MMM1D: 00243 ret = mmm1d_coulomb_pair_energy(p1,p2,d,dist2,dist); 00244 break; 00245 case COULOMB_MMM2D: 00246 ret = mmm2d_coulomb_pair_energy(p1->p.q*p2->p.q,d,dist2,dist); 00247 break; 00248 default : 00249 ret = 0.; 00250 } 00251 energy.coulomb[0] += ret; 00252 } 00253 #endif 00254 00255 #ifdef DIPOLES 00256 if (coulomb.Dmethod != DIPOLAR_NONE) { 00257 ret=0; 00258 switch (coulomb.Dmethod) { 00259 #ifdef DP3M 00260 case DIPOLAR_MDLC_P3M: 00261 //fall trough 00262 case DIPOLAR_P3M: 00263 ret = dp3m_pair_energy(p1,p2,d,dist2,dist); 00264 break; 00265 #endif 00266 } 00267 energy.dipolar[0] += ret; 00268 } 00269 #endif 00270 00271 } 00272 00273 /** Calculate bonded energies for one particle. 00274 @param p1 particle for which to calculate energies 00275 */ 00276 MDINLINE void add_bonded_energy(Particle *p1) 00277 { 00278 char *errtxt; 00279 Particle *p2, *p3 = NULL, *p4 = NULL; 00280 Bonded_ia_parameters *iaparams; 00281 int i, type_num, type, n_partners, bond_broken; 00282 double ret=0, dx[3] = {0, 0, 0}; 00283 00284 i = 0; 00285 while(i<p1->bl.n) { 00286 type_num = p1->bl.e[i++]; 00287 iaparams = &bonded_ia_params[type_num]; 00288 type = iaparams->type; 00289 n_partners = iaparams->num; 00290 00291 /* fetch particle 2, which is always needed */ 00292 p2 = local_particles[p1->bl.e[i++]]; 00293 if (!p2) { 00294 errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); 00295 ERROR_SPRINTF(errtxt,"{069 bond broken between particles %d and %d (particles not stored on the same node)} ", 00296 p1->p.identity, p1->bl.e[i-1]); 00297 return; 00298 } 00299 00300 /* fetch particle 3 eventually */ 00301 if (n_partners >= 2) { 00302 p3 = local_particles[p1->bl.e[i++]]; 00303 if (!p3) { 00304 errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); 00305 ERROR_SPRINTF(errtxt,"{070 bond broken between particles %d, %d and %d (particles not stored on the same node)} ", 00306 p1->p.identity, p1->bl.e[i-2], p1->bl.e[i-1]); 00307 return; 00308 } 00309 } 00310 00311 /* fetch particle 4 eventually */ 00312 if (n_partners >= 3) { 00313 p4 = local_particles[p1->bl.e[i++]]; 00314 if (!p4) { 00315 errtxt = runtime_error(128 + 4*ES_INTEGER_SPACE); 00316 ERROR_SPRINTF(errtxt,"{071 bond broken between particles %d, %d, %d and %d (particles not stored on the same node)} ", 00317 p1->p.identity, p1->bl.e[i-3], p1->bl.e[i-2], p1->bl.e[i-1]); 00318 return; 00319 } 00320 } 00321 00322 /* similar to the force, we prepare the center-center vector */ 00323 if (n_partners == 1) 00324 get_mi_vector(dx, p1->r.p, p2->r.p); 00325 00326 switch(type) { 00327 case BONDED_IA_FENE: 00328 bond_broken = fene_pair_energy(p1, p2, iaparams, dx, &ret); 00329 break; 00330 case BONDED_IA_HARMONIC: 00331 bond_broken = harmonic_pair_energy(p1, p2, iaparams, dx, &ret); 00332 break; 00333 #ifdef LENNARD_JONES 00334 case BONDED_IA_SUBT_LJ: 00335 bond_broken = subt_lj_pair_energy(p1, p2, iaparams, dx, &ret); 00336 break; 00337 #endif 00338 #ifdef BOND_ANGLE_OLD 00339 /* the first case is not needed and should not be called */ 00340 case BONDED_IA_ANGLE_OLD: 00341 bond_broken = angle_energy(p1, p2, p3, iaparams, &ret); 00342 break; 00343 #endif 00344 #ifdef BOND_ANGLE 00345 case BONDED_IA_ANGLE_HARMONIC: 00346 bond_broken = angle_harmonic_energy(p1, p2, p3, iaparams, &ret); 00347 break; 00348 case BONDED_IA_ANGLE_COSINE: 00349 bond_broken = angle_cosine_energy(p1, p2, p3, iaparams, &ret); 00350 break; 00351 case BONDED_IA_ANGLE_COSSQUARE: 00352 bond_broken = angle_cossquare_energy(p1, p2, p3, iaparams, &ret); 00353 break; 00354 #endif 00355 #ifdef BOND_ANGLEDIST 00356 case BONDED_IA_ANGLEDIST: 00357 bond_broken = angledist_energy(p1, p2, p3, iaparams, &ret); 00358 break; 00359 #endif 00360 #ifdef BOND_ENDANGLEDIST 00361 case BONDED_IA_ENDANGLEDIST: 00362 bond_broken = endangledist_pair_energy(p1, p2, iaparams, dx, &ret); 00363 break; 00364 #endif 00365 case BONDED_IA_DIHEDRAL: 00366 bond_broken = dihedral_energy(p2, p1, p3, p4, iaparams, &ret); 00367 break; 00368 #ifdef BOND_CONSTRAINT 00369 case BONDED_IA_RIGID_BOND: 00370 bond_broken = 0; 00371 ret = 0; 00372 break; 00373 #endif 00374 #ifdef TABULATED 00375 case BONDED_IA_TABULATED: 00376 switch(iaparams->p.tab.type) { 00377 case TAB_BOND_LENGTH: 00378 bond_broken = tab_bond_energy(p1, p2, iaparams, dx, &ret); 00379 break; 00380 case TAB_BOND_ANGLE: 00381 bond_broken = tab_angle_energy(p1, p2, p3, iaparams, &ret); 00382 break; 00383 case TAB_BOND_DIHEDRAL: 00384 bond_broken = tab_dihedral_energy(p2, p1, p3, p4, iaparams, &ret); 00385 break; 00386 default : 00387 errtxt = runtime_error(128 + ES_INTEGER_SPACE); 00388 ERROR_SPRINTF(errtxt,"{072 add_bonded_energy: tabulated bond type of atom %d unknown\n", p1->p.identity); 00389 return; 00390 } 00391 break; 00392 #endif 00393 #ifdef OVERLAPPED 00394 case BONDED_IA_OVERLAPPED: 00395 switch(iaparams->p.overlap.type) { 00396 case OVERLAP_BOND_LENGTH: 00397 bond_broken = overlap_bond_energy(p1, p2, iaparams, dx, &ret); 00398 break; 00399 case OVERLAP_BOND_ANGLE: 00400 bond_broken = overlap_angle_energy(p1, p2, p3, iaparams, &ret); 00401 break; 00402 case OVERLAP_BOND_DIHEDRAL: 00403 bond_broken = overlap_dihedral_energy(p2, p1, p3, p4, iaparams, &ret); 00404 break; 00405 default : 00406 errtxt = runtime_error(128 + ES_INTEGER_SPACE); 00407 ERROR_SPRINTF(errtxt,"{072 add_bonded_energy: overlapped bond type of atom %d unknown\n", p1->p.identity); 00408 return; 00409 } 00410 break; 00411 #endif 00412 #ifdef BOND_VIRTUAL 00413 case BONDED_IA_VIRTUAL_BOND: 00414 bond_broken = 0; 00415 ret = 0; 00416 break; 00417 #endif 00418 default : 00419 errtxt = runtime_error(128 + ES_INTEGER_SPACE); 00420 ERROR_SPRINTF(errtxt,"{073 add_bonded_energy: bond type of atom %d unknown\n", p1->p.identity); 00421 return; 00422 } 00423 00424 if (bond_broken) { 00425 switch (n_partners) { 00426 case 1: { 00427 char *errtext = runtime_error(128 + 2*ES_INTEGER_SPACE); 00428 ERROR_SPRINTF(errtext,"{083 bond broken between particles %d and %d} ", 00429 p1->p.identity, p2->p.identity); 00430 break; 00431 } 00432 case 2: { 00433 char *errtext = runtime_error(128 + 3*ES_INTEGER_SPACE); 00434 ERROR_SPRINTF(errtext,"{084 bond broken between particles %d, %d and %d} ", 00435 p1->p.identity, p2->p.identity, p3->p.identity); 00436 break; 00437 } 00438 case 3: { 00439 char *errtext = runtime_error(128 + 4*ES_INTEGER_SPACE); 00440 ERROR_SPRINTF(errtext,"{085 bond broken between particles %d, %d, %d and %d} ", 00441 p1->p.identity, p2->p.identity, p3->p.identity, p4->p.identity); 00442 break; 00443 } 00444 } 00445 // bond broken, don't add whatever we find in the energy 00446 continue; 00447 } 00448 00449 *obsstat_bonded(&energy, type_num) += ret; 00450 } 00451 } 00452 00453 /** Calculate kinetic energies for one particle. 00454 @param p1 particle for which to calculate energies 00455 */ 00456 MDINLINE void add_kinetic_energy(Particle *p1) 00457 { 00458 #ifdef VIRTUAL_SITES 00459 if (ifParticleIsVirtual(p1)) return; 00460 #endif 00461 00462 /* kinetic energy */ 00463 energy.data.e[0] += (SQR(p1->m.v[0]) + SQR(p1->m.v[1]) + SQR(p1->m.v[2]))*PMASS(*p1); 00464 00465 #ifdef ROTATION 00466 #ifdef ROTATION_PER_PARTICLE 00467 if (p1->p.rotation) 00468 #endif 00469 { 00470 #ifdef ROTATIONAL_INERTIA 00471 /* the rotational part is added to the total kinetic energy; 00472 Here we use the rotational inertia */ 00473 00474 energy.data.e[0] += (SQR(p1->m.omega[0])*p1->p.rinertia[0] + 00475 SQR(p1->m.omega[1])*p1->p.rinertia[1] + 00476 SQR(p1->m.omega[2])*p1->p.rinertia[2])*time_step*time_step; 00477 #else 00478 /* the rotational part is added to the total kinetic energy; 00479 at the moment, we assume unit inertia tensor I=(1,1,1) */ 00480 energy.data.e[0] += (SQR(p1->m.omega[0]) + SQR(p1->m.omega[1]) + SQR(p1->m.omega[2]))*time_step*time_step; 00481 #endif 00482 } 00483 #endif 00484 } 00485 00486 /*@}*/ 00487 00488 #endif
1.7.5.1