Skip to content
Snippets Groups Projects
two_body_interactions.c 30.2 KiB
Newer Older
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
/*----------------------------------------------------------------------
  SerialReax - Reax Force Field Simulator
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
  Copyright (2010) Purdue University
  Hasan Metin Aktulga, haktulga@cs.purdue.edu
  Joseph Fogarty, jcfogart@mail.usf.edu
  Sagar Pandit, pandit@usf.edu
  Ananth Y Grama, ayg@cs.purdue.edu
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License as
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
  published by the Free Software Foundation; either version 2 of
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
  the License, or (at your option) any later version.
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
  See the GNU General Public License for more details:
  <http://www.gnu.org/licenses/>.
  ----------------------------------------------------------------------*/

#include "two_body_interactions.h"
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#include "bond_orders.h"
#include "list.h"
#include "lookup.h"
#include "vector.h"


Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
void Bond_Energy( reax_system *system, control_params *control,
        simulation_data *data, static_storage *workspace,
        reax_list **lists, output_controls *out_control )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
{
    real gp3, gp4, gp7, gp10, gp37, ebond_total;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    gp3 = system->reaxprm.gp.l[3];
    gp4 = system->reaxprm.gp.l[4];
    gp7 = system->reaxprm.gp.l[7];
    gp10 = system->reaxprm.gp.l[10];
    gp37 = (int) system->reaxprm.gp.l[37];
#ifdef _OPENMP
//    #pragma omp parallel default(shared) reduction(+: ebond_total)
#endif
        int start_i, end_i;
        int type_i, type_j;
        real ebond, pow_BOs_be2, exp_be12, CEbo;
        real exphu, exphua1, exphub1, exphuov, hulpov, estriph;
        real decobdbo, decobdboua, decobdboub;
        single_body_parameters *sbp_i, *sbp_j;
        two_body_parameters *twbp;
        bond_order_data *bo_ij;

#ifdef _OPENMP
//        #pragma omp for schedule(guided)
#endif
        for ( i = 0; i < system->N; ++i )
        {
            start_i = Start_Index(i, bonds);
            end_i = End_Index(i, bonds);
                    type_i = system->atoms[i].type;
                    type_j = system->atoms[j].type;
                    sbp_i = &system->reaxprm.sbp[type_i];
                    sbp_j = &system->reaxprm.sbp[type_j];
                    twbp = &system->reaxprm.tbp[type_i][type_j];
                    bo_ij = &bonds->bond_list[pj].bo_data;

                    /* calculate the constants */
                    pow_BOs_be2 = POW( bo_ij->BO_s, twbp->p_be2 );
                    exp_be12 = EXP( twbp->p_be1 * ( 1.0 - pow_BOs_be2 ) );
                    CEbo = -twbp->De_s * exp_be12 *
                           ( 1.0 - twbp->p_be1 * twbp->p_be2 * pow_BOs_be2 );

                    /* calculate the Bond Energy */
                    ebond = -twbp->De_s * bo_ij->BO_s * exp_be12
                        - twbp->De_p * bo_ij->BO_pi
                        - twbp->De_pp * bo_ij->BO_pi2;
                    ebond_total += ebond;

                    /* calculate derivatives of Bond Orders */
                    bo_ij->Cdbo += CEbo;
                    bo_ij->Cdbopi -= (CEbo + twbp->De_p);
                    bo_ij->Cdbopi2 -= (CEbo + twbp->De_pp);
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

#ifdef TEST_ENERGY
                    fprintf( out_control->ebond, "%6d%6d%24.15e%24.15e\n",
                             workspace->orig_id[i], workspace->orig_id[j],
                             // i+1, j+1,
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#endif
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#ifdef TEST_FORCES
                    Add_dBO( system, lists, i, pj, CEbo, workspace->f_be );
                    Add_dBOpinpi2( system, lists, i, pj,
                                   -(CEbo + twbp->De_p), -(CEbo + twbp->De_pp),
                                   workspace->f_be, workspace->f_be );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#endif

                    /* Stabilisation terminal triple bond */
                    if ( bo_ij->BO >= 1.00 )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
                    {
                        if ( gp37 == 2
                                || (sbp_i->mass == 12.0000 && sbp_j->mass == 15.9990)
                                || (sbp_j->mass == 12.0000 && sbp_i->mass == 15.9990) )
                            //ba = SQR( bo_ij->BO - 2.5 );
                            exphu = EXP( -gp7 * SQR(bo_ij->BO - 2.5) );
                            //oboa = abo(j1) - boa;
                            //obob = abo(j2) - boa;
                            exphua1 = EXP(-gp3 * (workspace->total_bond_order[i] - bo_ij->BO));
                            exphub1 = EXP(-gp3 * (workspace->total_bond_order[j] - bo_ij->BO));
                            //ovoab = abo(j1) - aval(it1) + abo(j2) - aval(it2);
                            exphuov = EXP(gp4 * (workspace->Delta[i] + workspace->Delta[j]));
                            hulpov = 1.0 / (1.0 + 25.0 * exphuov);

                            estriph = gp10 * exphu * hulpov * (exphua1 + exphub1);
                            //estrain(j1) = estrain(j1) + 0.5 * estriph;
                            //estrain(j2) = estrain(j2) + 0.5 * estriph;
                            ebond_total += estriph;

                            decobdbo = gp10 * exphu * hulpov * (exphua1 + exphub1) *
                                ( gp3 - 2.0 * gp7 * (bo_ij->BO - 2.5) );
                                (gp3 * exphua1 + 25.0 * gp4 * exphuov * hulpov * (exphua1 + exphub1));
                                (gp3 * exphub1 + 25.0 * gp4 * exphuov * hulpov * (exphua1 + exphub1));

                            bo_ij->Cdbo += decobdbo;
                            workspace->CdDelta[i] += decobdboua;
                            workspace->CdDelta[j] += decobdboub;

Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#ifdef TEST_ENERGY
                            fprintf( out_control->ebond,
                                     "%6d%6d%24.15e%24.15e%24.15e%24.15e\n",
                                     workspace->orig_id[i], workspace->orig_id[j],
                                     estriph, decobdbo, decobdboua, decobdboub );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#endif
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#ifdef TEST_FORCES
                            Add_dBO( system, lists, i, pj, decobdbo, workspace->f_be );
                            Add_dDelta( system, lists, i, decobdboua, workspace->f_be );
                            Add_dDelta( system, lists, j, decobdboub, workspace->f_be );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#endif
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
                    }
                }
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    }
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
void vdW_Coulomb_Energy( reax_system *system, control_params *control,
        simulation_data *data, static_storage *workspace,
        reax_list **lists, output_controls *out_control )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
{
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    real p_vdW1, p_vdW1i;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    p_vdW1 = system->reaxprm.gp.l[28];
    p_vdW1i = 1.0 / p_vdW1;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    #pragma omp parallel default(shared) reduction(+: e_vdW_total, e_ele_total)
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    {
        int start_i, end_i;
        real self_coef;
        real powr_vdW1, powgi_vdW1;
        real tmp, r_ij, fn13, exp1, exp2;
        real Tap, dTap, dfn13, CEvd, CEclmb;
        real dr3gamij_1, dr3gamij_3;
        real e_ele, e_vdW, e_core, de_core;
        real d, xcut, bond_softness, d_bond_softness, effpot_diff;
        rvec temp, ext_press;
        //rtensor temp_rtensor, total_rtensor;
        two_body_parameters *twbp;
        far_neighbor_data *nbr_pj;
#ifdef _OPENMP
        int tid;

        tid = omp_get_thread_num( );
#endif
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

        e_ele = 0.0;
        e_vdW = 0.0;
        e_core = 0.0;
        de_core = 0.0;
        for ( i = 0; i < system->N; ++i )
        {
            start_i = Start_Index( i, far_nbrs );
            end_i = End_Index( i, far_nbrs );

            for ( pj = start_i; pj < end_i; ++pj )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
            {
                if ( far_nbrs->far_nbr_list[pj].d <= control->nonb_cut )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
                {
                    twbp = &system->reaxprm.tbp[ system->atoms[i].type ]
                             [ system->atoms[j].type ];
                    self_coef = (i == j) ? 0.5 : 1.0; // for supporting small boxes!

                    /* Calculate Taper and its derivative */
                    // Tap = nbr_pj->Tap;   -- precomputed during compte_H
                    Tap = workspace->Tap[7] * r_ij + workspace->Tap[6];
                    Tap = Tap * r_ij + workspace->Tap[5];
                    Tap = Tap * r_ij + workspace->Tap[4];
                    Tap = Tap * r_ij + workspace->Tap[3];
                    Tap = Tap * r_ij + workspace->Tap[2];
                    Tap = Tap * r_ij + workspace->Tap[1];
                    Tap = Tap * r_ij + workspace->Tap[0];

                    dTap = 7 * workspace->Tap[7] * r_ij + 6 * workspace->Tap[6];
                    dTap = dTap * r_ij + 5 * workspace->Tap[5];
                    dTap = dTap * r_ij + 4 * workspace->Tap[4];
                    dTap = dTap * r_ij + 3 * workspace->Tap[3];
                    dTap = dTap * r_ij + 2 * workspace->Tap[2];
                    dTap += workspace->Tap[1] / r_ij;

                    /* vdWaals Calculations */
                    if ( system->reaxprm.gp.vdw_type == 1 || system->reaxprm.gp.vdw_type == 3 )
                    {
                        /* shielding */
                        powr_vdW1 = POW( r_ij, p_vdW1 );
                        powgi_vdW1 = POW( 1.0 / twbp->gamma_w, p_vdW1 );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                        fn13 = POW( powr_vdW1 + powgi_vdW1, p_vdW1i );
                        exp1 = EXP( twbp->alpha * (1.0 - fn13 / twbp->r_vdW) );
                        exp2 = EXP( 0.5 * twbp->alpha * (1.0 - fn13 / twbp->r_vdW) );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                        e_vdW = self_coef * Tap * twbp->D * (exp1 - 2.0 * exp2);
                        e_vdW_total += e_vdW;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                        dfn13 = POW( powr_vdW1 + powgi_vdW1, p_vdW1i - 1.0) *
                            POW( r_ij, p_vdW1 - 2.0 );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                        CEvd = self_coef * ( dTap * twbp->D * (exp1 - 2 * exp2) -
                                Tap * twbp->D * (twbp->alpha / twbp->r_vdW) *
                                (exp1 - exp2) * dfn13 );
                    }
                    /* no shielding */
                    else
                    {
                        exp1 = EXP( twbp->alpha * (1.0 - r_ij / twbp->r_vdW) );
                        exp2 = EXP( 0.5 * twbp->alpha * (1.0 - r_ij / twbp->r_vdW) );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                        e_vdW = self_coef * Tap * twbp->D * (exp1 - 2.0 * exp2);
                        e_vdW_total += e_vdW;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                        CEvd = self_coef * ( dTap * twbp->D * (exp1 - 2.0 * exp2) -
                                Tap * twbp->D * (twbp->alpha / twbp->r_vdW) *
                                (exp1 - exp2) );
                    }
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                    if ( system->reaxprm.gp.vdw_type == 2 || system->reaxprm.gp.vdw_type == 3 )
                    {
                        /* innner wall */
                        e_core = twbp->ecore * EXP( twbp->acore * (1.0 - (r_ij / twbp->rcore)) );
                        e_vdW += self_coef * Tap * e_core;
                        e_vdW_total += self_coef * Tap * e_core;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                        de_core = -(twbp->acore / twbp->rcore) * e_core;
                        CEvd += self_coef * ( dTap * e_core + Tap * de_core );
                    }
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                    /* Coulomb Calculations */
                    dr3gamij_1 = ( r_ij * r_ij * r_ij + twbp->gamma );
                    dr3gamij_3 = POW( dr3gamij_1 , 1.0 / 3.0 );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                    e_ele = self_coef * C_ELE * system->atoms[i].q * system->atoms[j].q * tmp;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                    CEclmb = self_coef * C_ELE * system->atoms[i].q * system->atoms[j].q *
                             ( dTap -  Tap * r_ij / dr3gamij_1 ) / dr3gamij_3;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                    if ( control->ensemble == NVE || control->ensemble == nhNVT
                            || control->ensemble == bNVT )
                    {
#ifndef _OPENMP
                        rvec_ScaledAdd( system->atoms[i].f,
                                -(CEvd + CEclmb), nbr_pj->dvec );
                        rvec_ScaledAdd( system->atoms[j].f,
                                +(CEvd + CEclmb), nbr_pj->dvec );
#else
                        rvec_ScaledAdd( workspace->f_local[tid * system->N + i],
                                -(CEvd + CEclmb), nbr_pj->dvec );
                        rvec_ScaledAdd( workspace->f_local[tid * system->N + j],
                                +(CEvd + CEclmb), nbr_pj->dvec );
#endif
                    }
                    else
                    {
                        /* for pressure coupling, terms not related to bond order
                           derivatives are added directly into pressure vector/tensor */
                        rvec_Scale( temp, CEvd + CEclmb, nbr_pj->dvec );

#ifndef _OPENMP
                        rvec_ScaledAdd( system->atoms[i].f, -1., temp );
                        rvec_Add( system->atoms[j].f, temp );
#else
                        rvec_ScaledAdd( workspace->f_local[tid * system->N + i], -1., temp );
                        rvec_Add( workspace->f_local[tid * system->N + j], temp );
#endif
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                        rvec_iMultiply( ext_press, nbr_pj->rel_box, temp );
#ifdef _OPENMP
                        #pragma omp critical (vdW_Coulomb_Energy_ext_press)
#endif
#if defined(DEBUG_FOCUS)
                        fprintf( stderr, "nonbonded(%d,%d): rel_box (%f %f %f)",
                                i, j, nbr_pj->rel_box[0],
                                nbr_pj->rel_box[1], nbr_pj->rel_box[2] );

                        fprintf( stderr, "force(%f %f %f)", temp[0], temp[1], temp[2] );

                        fprintf( stderr, "ext_press (%12.6f %12.6f %12.6f)\n",
                                data->ext_press[0], data->ext_press[1],
                                data->ext_press[2] );
#endif

//                        /* This part is intended for a fully-flexible box */
//                        rvec_OuterProduct( temp_rtensor, nbr_pj->dvec, system->atoms[i].x );
//                        rtensor_Scale( total_rtensor, F_C * -(CEvd + CEclmb), temp_rtensor );
//                        rvec_OuterProduct( temp_rtensor, nbr_pj->dvec, system->atoms[j].x );
//                        rtensor_ScaledAdd( total_rtensor, F_C * +(CEvd + CEclmb), temp_rtensor );
//
//                        /* This is an external force due to an imaginary nbr */
//                        if ( nbr_pj->imaginary )
//                            rtensor_ScaledAdd( data->flex_bar.P, -1.0, total_rtensor );
//                        /* This interaction is completely internal */
//                        else
//                            rtensor_Add( data->flex_bar.P, total_rtensor );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#ifdef TEST_ENERGY
                    rvec_MakeZero( temp );
                    rvec_ScaledAdd( temp, +CEvd, nbr_pj->dvec );
                    fprintf( out_control->evdw,
                             "%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n",
                             //i+1, j+1,
                             MIN( workspace->orig_id[i], workspace->orig_id[j] ),
                             MAX( workspace->orig_id[i], workspace->orig_id[j] ),
                             r_ij, e_vdW, temp[0], temp[1], temp[2]/*, e_vdW_total*/ );

                    fprintf( out_control->ecou, "%6d%6d%24.15e%24.15e%24.15e%24.15e\n",
                             MIN( workspace->orig_id[i], workspace->orig_id[j] ),
                             MAX( workspace->orig_id[i], workspace->orig_id[j] ),
                             r_ij, system->atoms[i].q, system->atoms[j].q,
                             e_ele/*, e_ele_total*/ );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#endif
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#ifdef TEST_FORCES
                    rvec_ScaledAdd( workspace->f_vdw[i], -CEvd, nbr_pj->dvec );
                    rvec_ScaledAdd( workspace->f_vdw[j], +CEvd, nbr_pj->dvec );
                    rvec_ScaledAdd( workspace->f_ele[i], -CEclmb, nbr_pj->dvec );
                    rvec_ScaledAdd( workspace->f_ele[j], +CEclmb, nbr_pj->dvec );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#endif
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
            }

        //TODO: better integration of ACKS2 code below with above code for performance
#ifdef _OPENMP
        #pragma omp barrier
#endif

        /* contribution to energy and gradients (atoms and cell)
         * due to geometry-dependent terms in the ACKS2
         * kinetic energy */
        if ( control->charge_method == ACKS2_CM )
        {
#ifdef _OPENMP
            #pragma omp for schedule(guided)
#endif
            for ( i = 0; i < system->N; ++i )
            {
                for ( pj = Start_Index(i, far_nbrs); pj < End_Index(i, far_nbrs); ++pj )
                {
                    nbr_pj = &far_nbrs->far_nbr_list[pj];
                    j = nbr_pj->nbr;

                    /* kinetic energy terms */
                    xcut = 0.5 * ( system->reaxprm.sbp[ system->atoms[i].type ].b_s_acks2
                            + system->reaxprm.sbp[ system->atoms[j].type ].b_s_acks2 );
                    if ( far_nbrs->far_nbr_list[pj].d < xcut )
                    {
                        d = far_nbrs->far_nbr_list[pj].d / xcut;
                        bond_softness = system->reaxprm.gp.l[34] * POW( d, 3.0 )
                            * POW( 1.0 - d, 6.0 );
                            /* Coulombic energy contribution */
                            effpot_diff = workspace->s[0][system->N + i]
                                - workspace->s[0][system->N + j];
                            e_ele = -0.5 * KCALpMOL_to_EV * bond_softness
                                * SQR( effpot_diff );
                            e_ele_total += e_ele;

                            /* forces contribution */
                            d_bond_softness = system->reaxprm.gp.l[34]
                                * 3.0 / xcut * POW( d, 2.0 )
                                * POW( 1.0 - d, 5.0 ) * (1.0 - 3.0 * d);
                            d_bond_softness = -0.5 * d_bond_softness
                                * SQR( effpot_diff );
                            d_bond_softness = KCALpMOL_to_EV * d_bond_softness
                                / far_nbrs->far_nbr_list[pj].d;

#if defined(DEBUG_FOCUS)
                            fprintf( stderr, "%6d%6d%12.5f%12.5f%12.5f\n",
                                    j + 1, i + 1,
                                    d_bond_softness * nbr_pj->dvec[0],
                                    d_bond_softness * nbr_pj->dvec[1],
                                    d_bond_softness * nbr_pj->dvec[2] ); fflush( stderr );
#endif
                            rvec_ScaledAdd( system->atoms[i].f,
                                    -d_bond_softness, nbr_pj->dvec );
                            rvec_ScaledAdd( system->atoms[j].f,
                                    d_bond_softness, nbr_pj->dvec );
                            rvec_ScaledAdd( workspace->f_local[tid * system->N + i],
                                    -d_bond_softness, nbr_pj->dvec );
                            rvec_ScaledAdd( workspace->f_local[tid * system->N + j],
                                    d_bond_softness, nbr_pj->dvec );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    }

    data->E_vdW = e_vdW_total;
    data->E_Ele = e_ele_total;

#if defined(DEBUG)
    fprintf( stderr, "nonbonded: ext_press (%24.15e %24.15e %24.15e)\n",
            data->ext_press[0], data->ext_press[1], data->ext_press[2] );
#endif
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
void LR_vdW_Coulomb( reax_system *system, control_params *control,
        static_storage *workspace, int i, int j, real r_ij, LR_data *lr )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
{
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    real p_vdW1 = system->reaxprm.gp.l[28];
    real p_vdW1i = 1.0 / p_vdW1;
    real powr_vdW1, powgi_vdW1;
    real tmp, fn13, exp1, exp2;
    real Tap, dTap, dfn13;
    real dr3gamij_1, dr3gamij_3;
    real e_core, de_core;
    two_body_parameters *twbp;

Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    e_core = 0;
    de_core = 0;

    /* calculate taper and its derivative */
    Tap = workspace->Tap[7] * r_ij + workspace->Tap[6];
    Tap = Tap * r_ij + workspace->Tap[5];
    Tap = Tap * r_ij + workspace->Tap[4];
    Tap = Tap * r_ij + workspace->Tap[3];
    Tap = Tap * r_ij + workspace->Tap[2];
    Tap = Tap * r_ij + workspace->Tap[1];
    Tap = Tap * r_ij + workspace->Tap[0];

    dTap = 7 * workspace->Tap[7] * r_ij + 6 * workspace->Tap[6];
    dTap = dTap * r_ij + 5 * workspace->Tap[5];
    dTap = dTap * r_ij + 4 * workspace->Tap[4];
    dTap = dTap * r_ij + 3 * workspace->Tap[3];
    dTap = dTap * r_ij + 2 * workspace->Tap[2];
    dTap += workspace->Tap[1] / r_ij;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    /* vdWaals calculations */
    powr_vdW1 = POW( r_ij, p_vdW1 );
    powgi_vdW1 = POW( 1.0 / twbp->gamma_w, p_vdW1 );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    fn13 = POW( powr_vdW1 + powgi_vdW1, p_vdW1i );
    exp1 = EXP( twbp->alpha * (1.0 - fn13 / twbp->r_vdW) );
    exp2 = EXP( 0.5 * twbp->alpha * (1.0 - fn13 / twbp->r_vdW) );

Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    lr->e_vdW = Tap * twbp->D * (exp1 - 2.0 * exp2);
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    /* fprintf(stderr,"vdW: Tap:%f, r: %f, f13:%f, D:%f, Energy:%f,\
       Gamma_w:%f, p_vdw: %f, alpha: %f, r_vdw: %f, %lf %lf\n",
       Tap, r_ij, fn13, twbp->D, Tap * twbp->D * (exp1 - 2.0 * exp2),
       powgi_vdW1, p_vdW1, twbp->alpha, twbp->r_vdW, exp1, exp2); */

    dfn13 = POW( powr_vdW1 + powgi_vdW1, p_vdW1i - 1.0 )
        * POW( r_ij, p_vdW1 - 2.0 );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    lr->CEvd = dTap * twbp->D * (exp1 - 2 * exp2) -
        Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2) * dfn13;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    /* vdWaals Calculations */
    if ( system->reaxprm.gp.vdw_type == 1 || system->reaxprm.gp.vdw_type == 3 )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    {
        // shielding
        powr_vdW1 = POW( r_ij, p_vdW1 );
        powgi_vdW1 = POW( 1.0 / twbp->gamma_w, p_vdW1 );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

        fn13 = POW( powr_vdW1 + powgi_vdW1, p_vdW1i );
        exp1 = EXP( twbp->alpha * (1.0 - fn13 / twbp->r_vdW) );
        exp2 = EXP( 0.5 * twbp->alpha * (1.0 - fn13 / twbp->r_vdW) );

        lr->e_vdW = Tap * twbp->D * (exp1 - 2.0 * exp2);

        dfn13 = POW( powr_vdW1 + powgi_vdW1, p_vdW1i - 1.0) *
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

        lr->CEvd = dTap * twbp->D * (exp1 - 2.0 * exp2) -
            Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2) * dfn13;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    }
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    {
        exp1 = EXP( twbp->alpha * (1.0 - r_ij / twbp->r_vdW) );
        exp2 = EXP( 0.5 * twbp->alpha * (1.0 - r_ij / twbp->r_vdW) );

        lr->e_vdW = Tap * twbp->D * (exp1 - 2.0 * exp2);

        lr->CEvd = dTap * twbp->D * (exp1 - 2.0 * exp2) -
            Tap * twbp->D * (twbp->alpha / twbp->r_vdW) * (exp1 - exp2);
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    }

    if ( system->reaxprm.gp.vdw_type == 2 || system->reaxprm.gp.vdw_type == 3 )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    {
        // innner wall
        e_core = twbp->ecore * EXP(twbp->acore * (1.0 - (r_ij / twbp->rcore)));
        lr->e_vdW += Tap * e_core;

        de_core = -(twbp->acore / twbp->rcore) * e_core;
        lr->CEvd += dTap * e_core + Tap * de_core;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    }
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    /* Coulomb calculations */
    dr3gamij_1 = ( r_ij * r_ij * r_ij + twbp->gamma );
    dr3gamij_3 = POW( dr3gamij_1 , 1.0 / 3.0 );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    tmp = Tap / dr3gamij_3;
    lr->H = EV_to_KCALpMOL * tmp;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    /* fprintf( stderr,"i:%d(%d), j:%d(%d), gamma:%f,\
       Tap:%f, dr3gamij_3:%f, qi: %f, qj: %f\n",
       i, system->atoms[i].type, j, system->atoms[j].type,
       twbp->gamma, Tap, dr3gamij_3,
       system->atoms[i].q, system->atoms[j].q ); */

    lr->CEclmb = C_ELE * ( dTap -  Tap * r_ij / dr3gamij_1 ) / dr3gamij_3;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    /* fprintf( stdout, "%d %d\t%g\t%g  %g\t%g  %g\t%g  %g\n",
       i+1, j+1, r_ij, e_vdW, CEvd * r_ij,
       system->atoms[i].q, system->atoms[j].q, e_ele, CEclmb * r_ij ); */

    /* fprintf( stderr,"LR_Lookup:%3d%3d%5.3f-%8.5f,%8.5f%8.5f,%8.5f%8.5f\n",
       i, j, r_ij, lr->H, lr->e_vdW, lr->CEvd, lr->e_ele, lr->CEclmb ); */
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
}


void Tabulated_vdW_Coulomb_Energy( reax_system *system, control_params *control,
        simulation_data *data, static_storage *workspace, reax_list **lists,
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
{
    int steps, update_freq, update_energies;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    steps = data->step - data->prev_steps;
    update_freq = out_control->energy_update_freq;
    update_energies = update_freq > 0 && steps % update_freq == 0;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    #pragma omp parallel default(shared) reduction(+: e_vdW_total, e_ele_total)
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    {
        int i, j, pj, r;
        int type_i, type_j, tmin, tmax;
        int start_i, end_i;
        real r_ij, self_coef, base, dif;
        real e_vdW, e_ele;
        real CEvd, CEclmb;
        rvec temp, ext_press;
        far_neighbor_data *nbr_pj;
        LR_lookup_table *t;
#ifdef _OPENMP
        int tid;

        tid = omp_get_thread_num( );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

        for ( i = 0; i < system->N; ++i )
        {
            type_i = system->atoms[i].type;
            start_i = Start_Index(i, far_nbrs);
            end_i = End_Index(i, far_nbrs);

            for ( pj = start_i; pj < end_i; ++pj )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
            {
                if ( far_nbrs->far_nbr_list[pj].d <= control->nonb_cut )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
                {
                    j = nbr_pj->nbr;
                    type_j = system->atoms[j].type;
                    r_ij = nbr_pj->d;
                    self_coef = (i == j) ? 0.5 : 1.0;
                    tmin = MIN( type_i, type_j );
                    tmax = MAX( type_i, type_j );

#if defined(DEBUG)
                    fprintf( stderr, "r: %f, i: %d, base: %f, dif: %f\n", r, i, base, dif );
#endif
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                        e_vdW = ((t->vdW[r].d * dif + t->vdW[r].c) * dif + t->vdW[r].b)
                            * dif + t->vdW[r].a;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                        e_ele = ((t->ele[r].d * dif + t->ele[r].c) * dif + t->ele[r].b)
                            * dif + t->ele[r].a;
                        e_ele *= self_coef * system->atoms[i].q * system->atoms[j].q;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                    CEvd = ((t->CEvd[r].d * dif + t->CEvd[r].c) * dif + t->CEvd[r].b)
                        * dif + t->CEvd[r].a;
//                    CEvd = (3 * t->vdW[r].d * dif + 2 * t->vdW[r].c) * dif + t->vdW[r].b;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

                    CEclmb = ((t->CEclmb[r].d * dif + t->CEclmb[r].c) * dif + t->CEclmb[r].b)
                        * dif + t->CEclmb[r].a;
                    CEclmb *= self_coef * system->atoms[i].q * system->atoms[j].q;

                    if ( control->ensemble == NVE || control->ensemble == nhNVT
                            || control->ensemble == bNVT )
                    {
#ifndef _OPENMP
                        rvec_ScaledAdd( system->atoms[i].f, -(CEvd + CEclmb), nbr_pj->dvec );
                        rvec_ScaledAdd( system->atoms[j].f, +(CEvd + CEclmb), nbr_pj->dvec );
#else
                        rvec_ScaledAdd( workspace->f_local[tid * system->N + i],
                                -(CEvd + CEclmb), nbr_pj->dvec );
                        rvec_ScaledAdd( workspace->f_local[tid * system->N + j],
                                +(CEvd + CEclmb), nbr_pj->dvec );
#endif
                    }
                    {
                        /* for pressure coupling, terms not related to bond order
                           derivatives are added directly into pressure vector/tensor */
                        rvec_Scale( temp, CEvd + CEclmb, nbr_pj->dvec );
#ifndef _OPENMP
                        rvec_ScaledAdd( system->atoms[i].f, -1., temp );
                        rvec_Add( system->atoms[j].f, temp );
#else
                        rvec_ScaledAdd( workspace->f_local[tid * system->N + i], -1., temp );
                        rvec_Add( workspace->f_local[tid * system->N + j], temp );
#endif
                        rvec_iMultiply( ext_press, nbr_pj->rel_box, temp );
#ifdef _OPENMP
                        #pragma omp critical (Tabulated_vdW_Coulomb_Energy_ext_press)
#endif
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#ifdef TEST_ENERGY
                    fprintf( out_control->evdw, "%6d%6d%24.15e%24.15e%24.15e\n",
                            workspace->orig_id[i], workspace->orig_id[j],
                            r_ij, e_vdW, data->E_vdW );
                    fprintf( out_control->ecou, "%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n",
                            workspace->orig_id[i], workspace->orig_id[j],
                            r_ij, system->atoms[i].q, system->atoms[j].q,
                            e_ele, data->E_Ele );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#endif
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#ifdef TEST_FORCES
                    rvec_ScaledAdd( workspace->f_vdw[i], -CEvd, nbr_pj->dvec );
                    rvec_ScaledAdd( workspace->f_vdw[j], +CEvd, nbr_pj->dvec );
                    rvec_ScaledAdd( workspace->f_ele[i], -CEclmb, nbr_pj->dvec );
                    rvec_ScaledAdd( workspace->f_ele[j], +CEclmb, nbr_pj->dvec );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#endif
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
            }
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    }

    data->E_vdW += e_vdW_total;
    data->E_Ele += e_ele_total;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
}