ESPResSo 3.2.0-11-g9950804-git
Extensible Simulation Package for Soft Matter Research
energy.h
Go to the documentation of this file.
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