ESPResSo 3.2.0-11-g9950804-git
Extensible Simulation Package for Soft Matter Research
energy.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 /** \file energy.c
00022     Implementation of \ref energy.h "energy.h".
00023 */
00024 #include "energy.h"
00025 #include "cells.h"
00026 #include "integrate.h"
00027 #include "initialize.h"
00028 #include "domain_decomposition.h"
00029 #include "nsquare.h"
00030 #include "layered.h"
00031 #include "elc.h"
00032 #include "magnetic_non_p3m_methods.h"
00033 #include "mdlc_correction.h"
00034 
00035 Observable_stat energy = {0, {NULL,0,0}, 0,0,0};
00036 Observable_stat total_energy = {0, {NULL,0,0}, 0,0,0};
00037 
00038 /************************************************************/
00039 /* local prototypes                                         */
00040 /************************************************************/
00041 
00042 /** Calculate long range energies (P3M, MMM2d...). */
00043 void calc_long_range_energies();
00044 
00045 /************************************************************/
00046 
00047 void energy_calc(double *result)
00048 {
00049   if (!check_obs_calc_initialized())
00050     return;
00051 
00052   init_energies(&energy);
00053 
00054   on_observable_calc();
00055   
00056   switch (cell_structure.type) {
00057   case CELL_STRUCTURE_LAYERED:
00058     layered_calculate_energies();
00059     break;
00060   case CELL_STRUCTURE_DOMDEC: 
00061     if(dd.use_vList) {
00062       if (rebuild_verletlist)  
00063         build_verlet_lists();
00064       calculate_verlet_energies();
00065     }
00066     else
00067       calculate_link_cell_energies();
00068     break;
00069   case CELL_STRUCTURE_NSQUARE:
00070     nsq_calculate_energies();
00071   }
00072   /* rescale kinetic energy */
00073   energy.data.e[0] /= (2.0*time_step*time_step);
00074 
00075   calc_long_range_energies();
00076   
00077   /* gather data */
00078   MPI_Reduce(energy.data.e, result, energy.data.n, MPI_DOUBLE, MPI_SUM, 0, comm_cart);
00079 }
00080 
00081 /************************************************************/
00082 
00083 void calc_long_range_energies()
00084 {
00085 #ifdef ELECTROSTATICS  
00086   /* calculate k-space part of electrostatic interaction. */
00087   switch (coulomb.method) {
00088 #ifdef P3M
00089   case COULOMB_P3M:
00090     p3m_charge_assign(); 
00091     energy.coulomb[1] = p3m_calc_kspace_forces(0,1);
00092     break;
00093   case COULOMB_ELC_P3M:
00094     // assign the original charges first
00095     // they may not have been assigned yet
00096     p3m_charge_assign(); 
00097     if(!elc_params.dielectric_contrast_on)
00098       energy.coulomb[1] = p3m_calc_kspace_forces(0,1);
00099     else {
00100       energy.coulomb[1] = 0.5*p3m_calc_kspace_forces(0,1); 
00101       energy.coulomb[1]+= 0.5*ELC_P3M_dielectric_layers_energy_self(); 
00102 
00103       //  assign both original and image charges now
00104       ELC_p3m_charge_assign_both();
00105       ELC_P3M_modify_p3m_sums_both();
00106 
00107       energy.coulomb[1] += 0.5*p3m_calc_kspace_forces(0,1); 
00108 
00109       //assign only the image charges now
00110       ELC_p3m_charge_assign_image();
00111       ELC_P3M_modify_p3m_sums_image();
00112 
00113       energy.coulomb[1]-= 0.5*p3m_calc_kspace_forces(0,1); 
00114     }
00115     energy.coulomb[2] = ELC_energy();
00116     break;
00117 #endif
00118   case COULOMB_MMM2D:
00119     *energy.coulomb += MMM2D_far_energy();
00120     *energy.coulomb += MMM2D_dielectric_layers_energy_contribution();
00121     break;
00122     /* calculate electric part of energy (only for MAGGS) */
00123   case COULOMB_MAGGS:
00124     *energy.coulomb += maggs_electric_energy();
00125     break;
00126   }
00127 #endif  /* ifdef ELECTROSTATICS */
00128 
00129 #ifdef DIPOLES
00130   switch (coulomb.Dmethod) {
00131 #ifdef DP3M
00132   case DIPOLAR_P3M:
00133     dp3m_dipole_assign(); 
00134     energy.dipolar[1] = dp3m_calc_kspace_forces(0,1);
00135     break;
00136   case DIPOLAR_MDLC_P3M:
00137     dp3m_dipole_assign(); 
00138     energy.dipolar[1] = dp3m_calc_kspace_forces(0,1);
00139     energy.dipolar[2] = add_mdlc_energy_corrections();
00140     break;
00141 #endif
00142   case DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA:
00143     energy.dipolar[1] = dawaanr_calculations(0,1);
00144     break;
00145   case DIPOLAR_MDLC_DS:
00146     energy.dipolar[1] = magnetic_dipolar_direct_sum_calculations(0,1);
00147     energy.dipolar[2] = add_mdlc_energy_corrections();
00148     break;
00149   case DIPOLAR_DS:
00150     energy.dipolar[1] = magnetic_dipolar_direct_sum_calculations(0,1);
00151     break;
00152   
00153   } 
00154 #endif /* ifdef DIPOLES */
00155 
00156 }
00157 
00158 /************************************************************/
00159 
00160 void init_energies(Observable_stat *stat)
00161 {
00162     int n_pre, n_non_bonded, n_coulomb, n_dipolar;
00163 
00164   n_pre        = 1;
00165   n_non_bonded = (n_particle_types*(n_particle_types+1))/2;
00166 
00167   n_coulomb    = 0;
00168 #ifdef ELECTROSTATICS
00169   switch (coulomb.method) {
00170   case COULOMB_NONE:  n_coulomb = 0; break;
00171 #ifdef P3M
00172   case COULOMB_ELC_P3M: n_coulomb = 3; break;
00173   case COULOMB_P3M:   n_coulomb = 2; break;
00174 #endif
00175   default: n_coulomb  = 1;
00176   }
00177 #endif
00178 
00179   n_dipolar    = 0;
00180 #ifdef DIPOLES
00181 
00182   switch (coulomb.Dmethod) {
00183   case DIPOLAR_NONE:  n_dipolar = 1; break;
00184 #ifdef DP3M
00185   case DIPOLAR_MDLC_P3M: n_dipolar=3; break;
00186   case DIPOLAR_P3M:   n_dipolar = 2; break;
00187 #endif
00188   case DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA:   n_dipolar = 2; break;
00189  case DIPOLAR_MDLC_DS: n_dipolar=3; break;
00190  case DIPOLAR_DS:   n_dipolar = 2; break;
00191   }
00192 
00193 #endif
00194   
00195   obsstat_realloc_and_clear(stat, n_pre, n_bonded_ia, n_non_bonded, n_coulomb, n_dipolar, 1);
00196   stat->init_status = 0;
00197 }
00198 
00199 /************************************************************/
00200 
00201 void master_energy_calc() {
00202   mpi_gather_stats(1, total_energy.data.e, NULL, NULL, NULL);
00203 
00204   total_energy.init_status=1;
00205 }