Skip to content
Snippets Groups Projects
bond_orders.c 43.3 KiB
Newer Older
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
/*----------------------------------------------------------------------
  PuReMD - Purdue ReaxFF Molecular Dynamics Program
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

  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/>.
  ----------------------------------------------------------------------*/

#if (defined(HAVE_CONFIG_H) && !defined(__CONFIG_H_))
  #define __CONFIG_H_
  #include "../../common/include/config.h"
#endif
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#if defined(PURE_REAX)
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#elif defined(LAMMPS_REAX)
  #include "reax_list.h"
  #include "reax_vector.h"
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#endif
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

static inline real Cf45( real p1, real p2 )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
{
    return  -EXP(-p2 / 2.0) /
        ( SQR( EXP(-p1 / 2.0) + EXP(p1 / 2.0) ) * (EXP(-p2 / 2.0) + EXP(p2 / 2.0)) );
}


#if defined(TEST_FORCES)
void Add_dBO( reax_system *system, reax_list **lists,
        int i, int pj, real C, rvec *v )
{
    int start_pj, end_pj, k;
    reax_list *bonds, *dBOs;

    bonds = lists[BONDS];
    dBOs = lists[DBO];
    pj = bonds->bond_list[pj].dbond_index;
    start_pj = Start_Index( pj, dBOs );
    end_pj = End_Index( pj, dBOs );

#if defined(DEBUG_FOCUS)
    fprintf( stderr, "[Add_dBO] i: %d, j: %d, start: %d, end: %d\n", i, pj, start_pj, end_pj );
#endif

    for ( k = start_pj; k < end_pj; ++k )
    {
        rvec_ScaledAdd( v[dBOs->dbo_list[k].wrt],
                C, dBOs->dbo_list[k].dBO );
    }
}


void Add_dBOpinpi2( reax_system *system, reax_list **lists,
        int i, int pj, real Cpi, real Cpi2, rvec *vpi, rvec *vpi2 )
{
    int start_pj, end_pj, k;
    reax_list *bonds, *dBOs;
    dbond_data *dbo_k;

    bonds = lists[BONDS];
    dBOs = lists[DBO];
    pj = bonds->bond_list[pj].dbond_index;
    start_pj = Start_Index( pj, dBOs );
    end_pj = End_Index( pj, dBOs );

#if defined(DEBUG_FOCUS)
    fprintf( stderr, "[Add_dBOpinpi2] i: %d, j: %d, start: %d, end: %d\n", i, pj, start_pj, end_pj );
#endif

    for ( k = start_pj; k < end_pj; ++k )
    {
        dbo_k = &dBOs->dbo_list[k];
        rvec_ScaledAdd( vpi[dbo_k->wrt], Cpi, dbo_k->dBOpi );
        rvec_ScaledAdd( vpi2[dbo_k->wrt], Cpi2, dbo_k->dBOpi2 );
    }
}


void Add_dBO_to_Forces( reax_system *system, reax_list **lists,
                        int i, int pj, real C )
{
    reax_list *bonds;
    reax_list *dBOs;
    int start_pj, end_pj, k;

    bonds = lists[BONDS];
    dBOs = lists[DBO];
    pj = bonds->bond_list[pj].dbond_index;
    start_pj = Start_Index( pj, dBOs );
    end_pj = End_Index( pj, dBOs );

    for ( k = start_pj; k < end_pj; ++k )
    {
        rvec_ScaledAdd( system->atoms[dBOs->dbo_list[k].wrt].f,
                C, dBOs->dbo_list[k].dBO );
    }
}


void Add_dBOpinpi2_to_Forces( reax_system *system, reax_list **lists,
        int i, int pj, real Cpi, real Cpi2 )
{
    reax_list *bonds;
    reax_list *dBOs;
    dbond_data *dbo_k;
    int start_pj, end_pj, k;

    bonds = lists[BONDS];
    dBOs = lists[DBO];
    pj = bonds->bond_list[pj].dbond_index;
    start_pj = Start_Index(pj, dBOs);
    end_pj = End_Index(pj, dBOs);

    for ( k = start_pj; k < end_pj; ++k )
    {
        dbo_k = &dBOs->dbo_list[k];
        rvec_ScaledAdd( system->atoms[dbo_k->wrt].f, Cpi, dbo_k->dBOpi );
        rvec_ScaledAdd( system->atoms[dbo_k->wrt].f, Cpi2, dbo_k->dBOpi2 );
    }
}


void Add_dDelta( reax_system *system, reax_list **lists, int i, real C, rvec *v )
{
    int start, end, k;
    reax_list *dDeltas;

    dDeltas = lists[DDELTA];
    start = Start_Index( i, dDeltas );
    end = End_Index( i, dDeltas );

#if defined(DEBUG_FOCUS)
    fprintf( stderr, "[Add_dDelta] i: %d, start: %d, end: %d\n", i, start, end );
#endif

    for ( k = start; k < end; ++k )
    {
        rvec_ScaledAdd( v[dDeltas->dDelta_list[k].wrt],
                C, dDeltas->dDelta_list[k].dVal );
    }
}


void Add_dDelta_to_Forces( reax_system *system, reax_list **lists, int i, real C )
{
    reax_list *dDeltas;
    int start, end, k;

    dDeltas = lists[DDELTA];
    start = Start_Index( i, dDeltas );
    end = End_Index( i, dDeltas );

    for ( k = start; k < end; ++k )
    {
        rvec_ScaledAdd( system->atoms[dDeltas->dDelta_list[k].wrt].f,
                C, dDeltas->dDelta_list[k].dVal );
    }
}


void Calculate_dBO( int i, int pj, static_storage *workspace, reax_list **lists,
        int *top )
{
    int j, k, l, start_i, end_i, end_j;
    reax_list *bonds, *dBOs;
    bond_data *nbr_l, *nbr_k;
    bond_order_data *bo_ij;
    dbond_data *top_dbo;

    bonds = lists[BONDS];
    dBOs = lists[DBO];
    j = bonds->bond_list[pj].nbr;
    bo_ij = &bonds->bond_list[pj].bo_data;
    start_i = Start_Index( i, bonds );
    end_i = End_Index( i, bonds );
    l = Start_Index( j, bonds );
    end_j = End_Index( j, bonds );
    top_dbo = &dBOs->dbo_list[ *top ];

//    fprintf( stderr, "[Calculate_dBO] i: %d, pj: %d, start_i: %d, end_i: %d, start_j: %d, end_j: %d\n", i, pj, start_i, end_i, l, end_j );

    for ( k = start_i; k < end_i; ++k )
    {
        nbr_k = &bonds->bond_list[k];

        for ( ; l < end_j && bonds->bond_list[l].nbr < nbr_k->nbr; ++l )
        {
            /* These are the neighbors of j which aren't in the neighbor_list of i
             * Note that they might also include i! */
            nbr_l = &bonds->bond_list[l];
            top_dbo->wrt = nbr_l->nbr;

            rvec_Scale( top_dbo->dBO, -bo_ij->C3dbo, nbr_l->bo_data.dBOp );
            rvec_Scale( top_dbo->dBOpi, -bo_ij->C4dbopi, nbr_l->bo_data.dBOp );
            rvec_Scale( top_dbo->dBOpi2, -bo_ij->C4dbopi2, nbr_l->bo_data.dBOp );

            if ( nbr_l->nbr == i )
            {
                /* dBO */
                rvec_ScaledAdd( top_dbo->dBO, bo_ij->C1dbo, bo_ij->dBOp );
                rvec_ScaledAdd( top_dbo->dBO, bo_ij->C2dbo, workspace->dDeltap_self[i] );

                /* dBOpi */
                rvec_ScaledAdd( top_dbo->dBOpi, bo_ij->C1dbopi, bo_ij->dln_BOp_pi );
                rvec_ScaledAdd( top_dbo->dBOpi, bo_ij->C2dbopi, bo_ij->dBOp );
                rvec_ScaledAdd( top_dbo->dBOpi, bo_ij->C3dbopi, workspace->dDeltap_self[i] );

                /* dBOpp */
                rvec_ScaledAdd( top_dbo->dBOpi2, bo_ij->C1dbopi2, bo_ij->dln_BOp_pi2 );
                rvec_ScaledAdd( top_dbo->dBOpi2, bo_ij->C2dbopi2, bo_ij->dBOp );
                rvec_ScaledAdd( top_dbo->dBOpi2, bo_ij->C3dbopi2, workspace->dDeltap_self[i] );
            }

            ++(*top);
            ++top_dbo;
        }

        /* Now we are processing neighbor k of i. */
        top_dbo->wrt = nbr_k->nbr;

        rvec_Scale( top_dbo->dBO, -bo_ij->C2dbo, nbr_k->bo_data.dBOp );      //dBO-2
        rvec_Scale( top_dbo->dBOpi, -bo_ij->C3dbopi, nbr_k->bo_data.dBOp );  //dBOpi-3
        rvec_Scale( top_dbo->dBOpi2, -bo_ij->C3dbopi2, nbr_k->bo_data.dBOp );//dBOpp-3

        if ( l < end_j && bonds->bond_list[l].nbr == nbr_k->nbr )
        {
            /* common neighbor of i and j */
            nbr_l = &bonds->bond_list[l];
            rvec_Copy( dBOp, nbr_l->bo_data.dBOp );

            rvec_ScaledAdd( top_dbo->dBO, -bo_ij->C3dbo, nbr_l->bo_data.dBOp );      //dBO,3rd
            rvec_ScaledAdd( top_dbo->dBOpi, -bo_ij->C4dbopi, nbr_l->bo_data.dBOp );  //dBOpi,4th
            rvec_ScaledAdd( top_dbo->dBOpi2, -bo_ij->C4dbopi2, nbr_l->bo_data.dBOp );//dBOpp.4th
            ++l;
        }
        else if ( k == pj )
        {
            /* 1st, dBO */
            rvec_ScaledAdd( top_dbo->dBO, -bo_ij->C1dbo, bo_ij->dBOp );
            /* 3rd, dBO */
            rvec_ScaledAdd( top_dbo->dBO, bo_ij->C3dbo, workspace->dDeltap_self[j] );

            /* dBOpi, 1st */
            rvec_ScaledAdd( top_dbo->dBOpi, -bo_ij->C1dbopi, bo_ij->dln_BOp_pi );
            /* 2nd */
            rvec_ScaledAdd( top_dbo->dBOpi, -bo_ij->C2dbopi, bo_ij->dBOp );
            /* 4th */
            rvec_ScaledAdd( top_dbo->dBOpi, bo_ij->C4dbopi, workspace->dDeltap_self[j] );

            /* dBOpi2, 1st */
            rvec_ScaledAdd( top_dbo->dBOpi2, -bo_ij->C1dbopi2, bo_ij->dln_BOp_pi2 );
            /* 2nd */
            rvec_ScaledAdd( top_dbo->dBOpi2, -bo_ij->C2dbopi2, bo_ij->dBOp );
            /* 4th */
            rvec_ScaledAdd( top_dbo->dBOpi2, bo_ij->C4dbopi2, workspace->dDeltap_self[j] );
        }

        ++(*top);
        ++top_dbo;
    }

    for ( ; l < end_j; ++l )
    {
        /* These are the remaining neighbors of j which are not in the
           neighbor_list of i. Note that they might also include i!*/
        nbr_l = &bonds->bond_list[l];
        top_dbo->wrt = nbr_l->nbr;
        rvec_Copy( dBOp, nbr_l->bo_data.dBOp );

        rvec_Scale( top_dbo->dBO, -bo_ij->C3dbo, nbr_l->bo_data.dBOp );      //3rd, dBO
        rvec_Scale( top_dbo->dBOpi, -bo_ij->C4dbopi, nbr_l->bo_data.dBOp );  //4th, dBOpi
        rvec_Scale( top_dbo->dBOpi2, -bo_ij->C4dbopi2, nbr_l->bo_data.dBOp );//4th, dBOpp

        if ( nbr_l->nbr == i )
        {
            /* dBO, 1st */
            rvec_ScaledAdd( top_dbo->dBO, bo_ij->C1dbo, bo_ij->dBOp );
            rvec_ScaledAdd( top_dbo->dBO, bo_ij->C2dbo, workspace->dDeltap_self[i] ); //2nd, dBO

            /* dBOpi, 1st */
            rvec_ScaledAdd( top_dbo->dBOpi, bo_ij->C1dbopi, bo_ij->dln_BOp_pi );
            rvec_ScaledAdd( top_dbo->dBOpi, bo_ij->C2dbopi, bo_ij->dBOp );  //2nd
            rvec_ScaledAdd( top_dbo->dBOpi, bo_ij->C3dbopi, workspace->dDeltap_self[i] ); //3rd

            /* dBOpipi, 1st */
            rvec_ScaledAdd(top_dbo->dBOpi2, bo_ij->C1dbopi2, bo_ij->dln_BOp_pi2);
            rvec_ScaledAdd( top_dbo->dBOpi2, bo_ij->C2dbopi2, bo_ij->dBOp ); //2nd
            rvec_ScaledAdd( top_dbo->dBOpi2, bo_ij->C3dbopi2, workspace->dDeltap_self[i] );//3rd
        }

        ++(*top);
        ++top_dbo;
    }
}
#endif


void Add_dBond_to_Forces_NPT( int i, int pj, reax_system *system,
        simulation_data *data, storage *workspace, reax_list **lists )
{
    reax_list *bonds;
    bond_data *nbr_j, *nbr_k;
    bond_order_data *bo_ij, *bo_ji;
    dbond_coefficients coef;
    rvec temp, ext_press;
    ivec rel_box;
    bonds = lists[BONDS];
    nbr_j = &bonds->bond_list[pj];
    bo_ji = &bonds->bond_list[ nbr_j->sym_index ].bo_data;
    coef.C1dbo = bo_ij->C1dbo * (bo_ij->Cdbo + bo_ji->Cdbo);
    coef.C2dbo = bo_ij->C2dbo * (bo_ij->Cdbo + bo_ji->Cdbo);
    coef.C3dbo = bo_ij->C3dbo * (bo_ij->Cdbo + bo_ji->Cdbo);
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    coef.C1dbopi = bo_ij->C1dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
    coef.C2dbopi = bo_ij->C2dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
    coef.C3dbopi = bo_ij->C3dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
    coef.C4dbopi = bo_ij->C4dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    coef.C1dbopi2 = bo_ij->C1dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
    coef.C2dbopi2 = bo_ij->C2dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
    coef.C3dbopi2 = bo_ij->C3dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
    coef.C4dbopi2 = bo_ij->C4dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    coef.C1dDelta = bo_ij->C1dbo * (workspace->CdDelta[i] + workspace->CdDelta[j]);
    coef.C2dDelta = bo_ij->C2dbo * (workspace->CdDelta[i] + workspace->CdDelta[j]);
    coef.C3dDelta = bo_ij->C3dbo * (workspace->CdDelta[i] + workspace->CdDelta[j]);
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    /************************************
    * forces related to atom i          *
    * first neighbors of atom i         *
    ************************************/
    for ( pk = Start_Index(i, bonds); pk < End_Index(i, bonds); ++pk )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    {
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

        /* 2nd, dBO */
        rvec_Scale( temp, -coef.C2dbo, nbr_k->bo_data.dBOp );
        /* dDelta */
        rvec_ScaledAdd( temp, -coef.C2dDelta, nbr_k->bo_data.dBOp );
        /* 3rd, dBOpi */
        rvec_ScaledAdd( temp, -coef.C3dbopi, nbr_k->bo_data.dBOp );
        /* 3rd, dBOpi2 */
        rvec_ScaledAdd( temp, -coef.C3dbopi2, nbr_k->bo_data.dBOp );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

        /* force */
        rvec_Add( workspace->f[k], temp );
        /* pressure */
        rvec_iMultiply( ext_press, nbr_k->rel_box, temp );
        rvec_Add( data->my_ext_press, ext_press );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    /* then atom i itself */
    /* 1st, dBO */
    rvec_Scale( temp, coef.C1dbo, bo_ij->dBOp );
    /* 2nd, dBO */
    rvec_ScaledAdd( temp, coef.C2dbo, workspace->dDeltap_self[i] );

    /* 1st, dBO */
    rvec_ScaledAdd( temp, coef.C1dDelta, bo_ij->dBOp );
    /* 2nd, dBO */
    rvec_ScaledAdd( temp, coef.C2dDelta, workspace->dDeltap_self[i] );

    /* 1st, dBOpi */
    rvec_ScaledAdd( temp, coef.C1dbopi, bo_ij->dln_BOp_pi );
    /* 2nd, dBOpi */
    rvec_ScaledAdd( temp, coef.C2dbopi, bo_ij->dBOp );
    /* 3rd, dBOpi */
    rvec_ScaledAdd( temp, coef.C3dbopi, workspace->dDeltap_self[i] );

    /* 1st, dBO_pi2 */
    rvec_ScaledAdd( temp, coef.C1dbopi2, bo_ij->dln_BOp_pi2 );
    /* 2nd, dBO_pi2 */
    rvec_ScaledAdd( temp, coef.C2dbopi2, bo_ij->dBOp );
    /* 3rd, dBO_pi2 */
    rvec_ScaledAdd( temp, coef.C3dbopi2, workspace->dDeltap_self[i] );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    /* force */
    rvec_Add( workspace->f[i], temp );
    /* ext pressure due to i is dropped, counting force on j will be enough */
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    /******************************************************
     * forces and pressure related to atom j               *
     * first neighbors of atom j                           *
     ******************************************************/
    for ( pk = Start_Index(j, bonds); pk < End_Index(j, bonds); ++pk )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    {
        /* 3rd, dBO */
        rvec_Scale( temp, -coef.C3dbo, nbr_k->bo_data.dBOp );
        /* dDelta */
        rvec_ScaledAdd( temp, -coef.C3dDelta, nbr_k->bo_data.dBOp );
        /* 4th, dBOpi */
        rvec_ScaledAdd( temp, -coef.C4dbopi, nbr_k->bo_data.dBOp );
        /* 4th, dBOpi2 */
        rvec_ScaledAdd( temp, -coef.C4dbopi2, nbr_k->bo_data.dBOp );

        /* force */
        rvec_Add( workspace->f[k], temp );
        /* pressure */
        if ( k != i )
        {
            ivec_Sum( rel_box, nbr_k->rel_box, nbr_j->rel_box ); //rel_box(k, i)
            rvec_iMultiply( ext_press, rel_box, temp );
            rvec_Add( data->my_ext_press, ext_press );
        }
    /* 1st, dBO */
    rvec_Scale( temp, -coef.C1dbo, bo_ij->dBOp );
    /* 2nd, dBO */
    rvec_ScaledAdd( temp, coef.C3dbo, workspace->dDeltap_self[j] );

    /* 1st, dBO */
    rvec_ScaledAdd( temp, -coef.C1dDelta, bo_ij->dBOp );
    /* 2nd, dBO */
    rvec_ScaledAdd( temp, coef.C3dDelta, workspace->dDeltap_self[j] );

    /* 1st, dBOpi */
    rvec_ScaledAdd( temp, -coef.C1dbopi, bo_ij->dln_BOp_pi );
    /* 2nd, dBOpi */
    rvec_ScaledAdd( temp, -coef.C2dbopi, bo_ij->dBOp );
    /* 3rd, dBOpi */
    rvec_ScaledAdd( temp, coef.C4dbopi, workspace->dDeltap_self[j] );

    /* 1st, dBOpi2 */
    rvec_ScaledAdd( temp, -coef.C1dbopi2, bo_ij->dln_BOp_pi2 );
    /* 2nd, dBOpi2 */
    rvec_ScaledAdd( temp, -coef.C2dbopi2, bo_ij->dBOp );
    /* 3rd, dBOpi2 */
    rvec_ScaledAdd( temp, coef.C4dbopi2, workspace->dDeltap_self[j] );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    /* force */
    rvec_Add( workspace->f[j], temp );
    /* pressure */
    rvec_iMultiply( ext_press, nbr_j->rel_box, temp );
    rvec_Add( data->my_ext_press, ext_press );

void Add_dBond_to_Forces( int i, int pj, reax_system *system,
        simulation_data *data, storage *workspace, reax_list **lists )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
{
    bond_data *nbr_j, *nbr_k;
    bond_order_data *bo_ij, *bo_ji;
    dbond_coefficients coef;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    bonds = lists[BONDS];
    nbr_j = &bonds->bond_list[pj];
    bo_ji = &bonds->bond_list[ nbr_j->sym_index ].bo_data;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    coef.C1dbo = bo_ij->C1dbo * (bo_ij->Cdbo + bo_ji->Cdbo);
    coef.C2dbo = bo_ij->C2dbo * (bo_ij->Cdbo + bo_ji->Cdbo);
    coef.C3dbo = bo_ij->C3dbo * (bo_ij->Cdbo + bo_ji->Cdbo);

    coef.C1dbopi = bo_ij->C1dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
    coef.C2dbopi = bo_ij->C2dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
    coef.C3dbopi = bo_ij->C3dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
    coef.C4dbopi = bo_ij->C4dbopi * (bo_ij->Cdbopi + bo_ji->Cdbopi);
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    coef.C1dbopi2 = bo_ij->C1dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
    coef.C2dbopi2 = bo_ij->C2dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
    coef.C3dbopi2 = bo_ij->C3dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
    coef.C4dbopi2 = bo_ij->C4dbopi2 * (bo_ij->Cdbopi2 + bo_ji->Cdbopi2);
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    coef.C1dDelta = bo_ij->C1dbo * (workspace->CdDelta[i] + workspace->CdDelta[j]);
    coef.C2dDelta = bo_ij->C2dbo * (workspace->CdDelta[i] + workspace->CdDelta[j]);
    coef.C3dDelta = bo_ij->C3dbo * (workspace->CdDelta[i] + workspace->CdDelta[j]);
    for ( pk = Start_Index(i, bonds); pk < End_Index(i, bonds); ++pk )
        /* 2nd, dBO */
        rvec_ScaledAdd( workspace->f[k], -coef.C2dbo, nbr_k->bo_data.dBOp );
        /* dDelta */
        rvec_ScaledAdd( workspace->f[k], -coef.C2dDelta, nbr_k->bo_data.dBOp );
        /* 3rd, dBOpi */
        rvec_ScaledAdd( workspace->f[k], -coef.C3dbopi, nbr_k->bo_data.dBOp );
        /* 3rd, dBOpi2 */
        rvec_ScaledAdd( workspace->f[k], -coef.C3dbopi2, nbr_k->bo_data.dBOp );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    rvec_ScaledAdd( workspace->f[i], coef.C1dbo, bo_ij->dBOp );
    rvec_ScaledAdd( workspace->f[i], coef.C2dbo, workspace->dDeltap_self[i] );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    rvec_ScaledAdd( workspace->f[i], coef.C1dDelta, bo_ij->dBOp );
    rvec_ScaledAdd( workspace->f[i], coef.C2dDelta, workspace->dDeltap_self[i] );
    rvec_ScaledAdd( workspace->f[i], coef.C1dbopi, bo_ij->dln_BOp_pi );
    rvec_ScaledAdd( workspace->f[i], coef.C2dbopi, bo_ij->dBOp );
    rvec_ScaledAdd( workspace->f[i], coef.C3dbopi, workspace->dDeltap_self[i] );

    rvec_ScaledAdd( workspace->f[i], coef.C1dbopi2, bo_ij->dln_BOp_pi2 );
    rvec_ScaledAdd( workspace->f[i], coef.C2dbopi2, bo_ij->dBOp );
    rvec_ScaledAdd( workspace->f[i], coef.C3dbopi2, workspace->dDeltap_self[i] );

    for ( pk = Start_Index(j, bonds); pk < End_Index(j, bonds); ++pk )
        /* 3rd, dBO */
        rvec_ScaledAdd( workspace->f[k], -coef.C3dbo, nbr_k->bo_data.dBOp );
        /* dDelta */
        rvec_ScaledAdd( workspace->f[k], -coef.C3dDelta, nbr_k->bo_data.dBOp );
        /* 4th, dBOpi */
        rvec_ScaledAdd( workspace->f[k], -coef.C4dbopi, nbr_k->bo_data.dBOp );
        /* 4th, dBOpi2 */
        rvec_ScaledAdd( workspace->f[k], -coef.C4dbopi2, nbr_k->bo_data.dBOp );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    /* 1st, dBO */
    rvec_ScaledAdd( workspace->f[j], -coef.C1dbo, bo_ij->dBOp );
    /* 2nd, dBO */
    rvec_ScaledAdd( workspace->f[j], coef.C3dbo, workspace->dDeltap_self[j] );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    /* 1st, dBO */
    rvec_ScaledAdd( workspace->f[j], -coef.C1dDelta, bo_ij->dBOp );
    /* 2nd, dBO */
    rvec_ScaledAdd( workspace->f[j], coef.C3dDelta, workspace->dDeltap_self[j] );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    /* 1st, dBOpi */
    rvec_ScaledAdd( workspace->f[j], -coef.C1dbopi, bo_ij->dln_BOp_pi );
    /* 2nd, dBOpi */
    rvec_ScaledAdd( workspace->f[j], -coef.C2dbopi, bo_ij->dBOp );
    /* 3rd, dBOpi */
    rvec_ScaledAdd( workspace->f[j], coef.C4dbopi, workspace->dDeltap_self[j] );
    /* 1st, dBOpi2 */
    rvec_ScaledAdd( workspace->f[j], -coef.C1dbopi2, bo_ij->dln_BOp_pi2 );
    /* 2nd, dBOpi2 */
    rvec_ScaledAdd( workspace->f[j], -coef.C2dbopi2, bo_ij->dBOp );
    /* 3rd, dBOpi2 */
    rvec_ScaledAdd( workspace->f[j], coef.C4dbopi2, workspace->dDeltap_self[j] );
}
static inline void Copy_Bond_Order_Data( bond_order_data *dest, bond_order_data *src )
{
    dest->BO = src->BO;
    dest->BO_s = src->BO_s;
    dest->BO_pi = src->BO_pi;
    dest->BO_pi2 = src->BO_pi2;

    rvec_Scale( dest->dBOp, -1.0, src->dBOp );
    rvec_Scale( dest->dln_BOp_s, -1.0, src->dln_BOp_s );
    rvec_Scale( dest->dln_BOp_pi, -1.0, src->dln_BOp_pi );
    rvec_Scale( dest->dln_BOp_pi2, -1.0, src->dln_BOp_pi2 );
}


/* Compute the bond order term between atoms i and j,
 * and if this term exceeds the cutoff bo_cut, then adds
 * BOTH atoms the bonds list (i.e., compute term once
 * and copy to avoid redundant computation) */
int BOp( storage * const workspace, reax_list * const bonds, real bo_cut,
         int i, int btop_i, int j, ivec * const rel_box, real d, rvec * const dvec,
         int far_nbr_list_format, single_body_parameters const * const sbp_i,
         single_body_parameters const * const sbp_j, two_body_parameters const * const twbp )
{
    real r2, C12, C34, C56;
    real Cln_BOp_s, Cln_BOp_pi, Cln_BOp_pi2;
    real BO, BO_s, BO_pi, BO_pi2;
    bond_data *ibond, *jbond;
    bond_order_data *bo_ij, *bo_ji;
        C12 = twbp->p_bo1 * POW( d / twbp->r_s, twbp->p_bo2 );
        BO_s = (1.0 + bo_cut) * exp( C12 );
    if ( sbp_i->r_pi > 0.0 && sbp_j->r_pi > 0.0 )
    {
        C34 = twbp->p_bo3 * POW( d / twbp->r_p, twbp->p_bo4 );
        BO_pi = exp( C34 );
    if ( sbp_i->r_pi_pi > 0.0 && sbp_j->r_pi_pi > 0.0 )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    {
        C56 = twbp->p_bo5 * POW( d / twbp->r_pp, twbp->p_bo6 );
        BO_pi2 = exp( C56 );
    /* Initially BO values are the uncorrected ones, page 1 */
    BO = BO_s + BO_pi + BO_pi2;
        /****** bonds i-j and j-i ******/
        ibond = &bonds->bond_list[btop_i];
        btop_j = End_Index( j, bonds );
        jbond = &bonds->bond_list[btop_j];
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

        ibond->nbr = j;
        ibond->d = d;
        rvec_Copy( ibond->dvec, *dvec );
        ivec_Copy( ibond->rel_box, *rel_box );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
        ibond->dbond_index = btop_i;
        ibond->sym_index = btop_j;
        jbond->d = d;
        rvec_Scale( jbond->dvec, -1.0, *dvec );
        ivec_Scale( jbond->rel_box, -1.0, *rel_box );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
        jbond->sym_index = btop_i;

        bo_ij = &ibond->bo_data;
        bo_ij->BO = BO;
        bo_ij->BO_s = BO_s;
        bo_ij->BO_pi = BO_pi;
        bo_ij->BO_pi2 = BO_pi2;
        bo_ji = &jbond->bo_data;
        bo_ji->BO = BO;
        bo_ji->BO_s = BO_s;
        bo_ji->BO_pi = BO_pi;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

        /* Bond Order page2-3, derivative of total bond order prime */
        Cln_BOp_s = twbp->p_bo2 * C12 / r2;
        Cln_BOp_pi = twbp->p_bo4 * C34 / r2;
        Cln_BOp_pi2 = twbp->p_bo6 * C56 / r2;

        /* Only dln_BOp_xx wrt. dr_i is stored here, note that
         * dln_BOp_xx/dr_i = -dln_BOp_xx/dr_j and all others are 0 */
        rvec_Scale( bo_ij->dln_BOp_s, -1.0 * bo_ij->BO_s * Cln_BOp_s, ibond->dvec );
        rvec_Scale( bo_ij->dln_BOp_pi, -1.0 * bo_ij->BO_pi * Cln_BOp_pi, ibond->dvec );
        rvec_Scale( bo_ij->dln_BOp_pi2, -1.0 * bo_ij->BO_pi2 * Cln_BOp_pi2, ibond->dvec );
        rvec_Scale( bo_ji->dln_BOp_s, -1.0, bo_ij->dln_BOp_s );
        rvec_Scale( bo_ji->dln_BOp_pi, -1.0, bo_ij->dln_BOp_pi );
        rvec_Scale( bo_ji->dln_BOp_pi2, -1.0, bo_ij->dln_BOp_pi2 );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

        /* Only dBOp wrt. dr_i is stored here, note that
         * dBOp/dr_i = -dBOp/dr_j and all others are 0 */
        rvec_Scale( bo_ij->dBOp, -1.0 * (bo_ij->BO_s * Cln_BOp_s 
                    + bo_ij->BO_pi * Cln_BOp_pi 
                    + bo_ij->BO_pi2 * Cln_BOp_pi2), ibond->dvec );
        rvec_Scale( bo_ji->dBOp, -1.0, bo_ij->dBOp );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

        rvec_Add( workspace->dDeltap_self[i], bo_ij->dBOp );
        rvec_Add( workspace->dDeltap_self[j], bo_ji->dBOp );

        bo_ij->BO_s -= bo_cut;
        bo_ij->BO -= bo_cut;
        /* currently total_BOp */
        workspace->total_bond_order[i] += bo_ij->BO;
        bo_ij->Cdbo = 0.0;
        bo_ij->Cdbopi = 0.0;
        bo_ij->Cdbopi2 = 0.0;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
        bo_ji->BO_s -= bo_cut;
        bo_ji->BO -= bo_cut;
        workspace->total_bond_order[j] += bo_ji->BO; //currently total_BOp
        bo_ji->Cdbo = 0.0;
        bo_ji->Cdbopi = 0.0;
        bo_ji->Cdbopi2 = 0.0;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
}
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

/* Compute the bond order term between atoms i and j,
 * and if this term exceeds the cutoff bo_cut, then adds
 * to the bond list according to the following convention:
 *   * if the far neighbor list is stored in half format,
 *      add BOTH atoms to each other's portion of the bond list
 *   * if the far neighbor list is stored in full format,
 *      add atom i to atom j's bonds list ONLY */
int BOp_redundant( storage *workspace, reax_list *bonds, real bo_cut,
         int i, int btop_i, int j, ivec *rel_box, real d, rvec *dvec,
         int far_nbr_list_format, single_body_parameters *sbp_i,
         single_body_parameters *sbp_j, two_body_parameters *twbp )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
{
    real r2, C12, C34, C56;
    real Cln_BOp_s, Cln_BOp_pi, Cln_BOp_pi2;
    real BO, BO_s, BO_pi, BO_pi2;
    bond_data *ibond;
    bond_order_data *bo_ij;
    int btop_j;
    bond_data *jbond;
    bond_order_data *bo_ji;

    r2 = SQR(d);

    if ( sbp_i->r_s > 0.0 && sbp_j->r_s > 0.0 )
    {
        C12 = twbp->p_bo1 * pow( d / twbp->r_s, twbp->p_bo2 );
        BO_s = (1.0 + bo_cut) * exp( C12 );
    }
    else
    {
        C12 = 0.0;
        BO_s = 0.0;
    }

    if ( sbp_i->r_pi > 0.0 && sbp_j->r_pi > 0.0 )
    {
        C34 = twbp->p_bo3 * pow( d / twbp->r_p, twbp->p_bo4 );
        BO_pi = exp( C34 );
    }
    else
    {
        C34 = 0.0;
        BO_pi = 0.0;
    }

    if ( sbp_i->r_pi_pi > 0.0 && sbp_j->r_pi_pi > 0.0 )
    {
        C56 = twbp->p_bo5 * pow( d / twbp->r_pp, twbp->p_bo6 );
        BO_pi2 = exp( C56 );
    }
    else
    {
        C56 = 0.0;
        BO_pi2 = 0.0;
    }

    /* Initially BO values are the uncorrected ones, page 1 */
    BO = BO_s + BO_pi + BO_pi2;

    if ( BO >= bo_cut )
    {
        /****** bonds i-j and j-i ******/
        ibond = &bonds->bond_list[btop_i];
        if ( far_nbr_list_format == HALF_LIST )
        {
            btop_j = End_Index( j, bonds );
            jbond = &bonds->bond_list[btop_j];
        }

        ibond->nbr = j;
        ibond->d = d;
        rvec_Copy( ibond->dvec, *dvec );
        ivec_Copy( ibond->rel_box, *rel_box );
        ibond->dbond_index = btop_i;
        if ( far_nbr_list_format == HALF_LIST )
        {
            ibond->sym_index = btop_j;
            jbond->nbr = i;
            jbond->d = d;
            rvec_Scale( jbond->dvec, -1.0, *dvec );
            ivec_Scale( jbond->rel_box, -1.0, *rel_box );
            jbond->dbond_index = btop_i;
            jbond->sym_index = btop_i;

            Set_End_Index( j, btop_j + 1, bonds );
        }
        
        bo_ij = &ibond->bo_data;
        bo_ij->BO = BO;
        bo_ij->BO_s = BO_s;
        bo_ij->BO_pi = BO_pi;
        bo_ij->BO_pi2 = BO_pi2;
        if ( far_nbr_list_format == HALF_LIST )
        {
            bo_ji = &jbond->bo_data;
            bo_ji->BO = BO;
            bo_ji->BO_s = BO_s;
            bo_ji->BO_pi = BO_pi;
            bo_ji->BO_pi2 = BO_pi2;
        }

        /* Bond Order page2-3, derivative of total bond order prime */
        Cln_BOp_s = twbp->p_bo2 * C12 / r2;
        Cln_BOp_pi = twbp->p_bo4 * C34 / r2;
        Cln_BOp_pi2 = twbp->p_bo6 * C56 / r2;

        /* Only dln_BOp_xx wrt. dr_i is stored here, note that
         * dln_BOp_xx/dr_i = -dln_BOp_xx/dr_j and all others are 0 */
        rvec_Scale( bo_ij->dln_BOp_s, -1.0 * bo_ij->BO_s * Cln_BOp_s, ibond->dvec );
        rvec_Scale( bo_ij->dln_BOp_pi, -1.0 * bo_ij->BO_pi * Cln_BOp_pi, ibond->dvec );
        rvec_Scale( bo_ij->dln_BOp_pi2, -1.0 * bo_ij->BO_pi2 * Cln_BOp_pi2, ibond->dvec );
        if ( far_nbr_list_format == HALF_LIST )
        {
            rvec_Scale( bo_ji->dln_BOp_s, -1.0, bo_ij->dln_BOp_s );
            rvec_Scale( bo_ji->dln_BOp_pi, -1.0, bo_ij->dln_BOp_pi );
            rvec_Scale( bo_ji->dln_BOp_pi2, -1.0, bo_ij->dln_BOp_pi2 );
        }

        /* Only dBOp wrt. dr_i is stored here, note that
         * dBOp/dr_i = -dBOp/dr_j and all others are 0 */
        rvec_Scale( bo_ij->dBOp, -1.0 * (bo_ij->BO_s * Cln_BOp_s 
                    + bo_ij->BO_pi * Cln_BOp_pi 
                    + bo_ij->BO_pi2 * Cln_BOp_pi2), ibond->dvec );
        if ( far_nbr_list_format == HALF_LIST )
        {
            rvec_Scale( bo_ji->dBOp, -1.0, bo_ij->dBOp );
        }

        rvec_Add( workspace->dDeltap_self[i], bo_ij->dBOp );
        if ( far_nbr_list_format == HALF_LIST )
        {
            rvec_Add( workspace->dDeltap_self[j], bo_ji->dBOp );
        }

        bo_ij->BO_s -= bo_cut;
        bo_ij->BO -= bo_cut;
        workspace->total_bond_order[i] += bo_ij->BO; //currently total_BOp
        bo_ij->Cdbo = 0.0;
        bo_ij->Cdbopi = 0.0;
        bo_ij->Cdbopi2 = 0.0;
        if ( far_nbr_list_format == HALF_LIST )
        {
            bo_ji->BO_s -= bo_cut;
            bo_ji->BO -= bo_cut;
            workspace->total_bond_order[j] += bo_ji->BO; //currently total_BOp
            bo_ji->Cdbo = 0.0;
            bo_ji->Cdbopi = 0.0;
            bo_ji->Cdbopi2 = 0.0;
        }

        return TRUE;
    }

    return FALSE;
/* A very important and crucial assumption here is that each segment
 * belonging to a different atom in nbrhoods->nbr_list is sorted in its own.
 * This can either be done in the general coordinator function or here */
void BO( reax_system *system, control_params *control,
        simulation_data *data, 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
    int i, j, pj, type_i, type_j;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    real val_i, Deltap_i, Deltap_boc_i;
    real val_j, Deltap_j, Deltap_boc_j;
    real f1, f2, f3, f4, f5, f4f5, exp_f4, exp_f5;
    real exp_p1i, exp_p2i, exp_p1j, exp_p2j;
    real temp, u1_ij, u1_ji, Cf1A_ij, Cf1B_ij, Cf1_ij, Cf1_ji;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    real A0_ij, A1_ij, A2_ij, A2_ji, A3_ij, A3_ji;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    single_body_parameters *sbp_i, *sbp_j;
    two_body_parameters *twbp;
    bond_order_data *bo_ij, *bo_ji;
    reax_list *bond_list;
#if defined(TEST_FORCES)
    int k, pk, start_j, end_j;
    int top_dbo, top_dDelta;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    dbond_data *pdbo;
    dDelta_data *ptop_dDelta;
    p_lp1 = system->reax_param.gp.l[15];
    p_boc1 = system->reax_param.gp.l[0];
    p_boc2 = system->reax_param.gp.l[1];
    bond_list = lists[BONDS];
#if defined(TEST_FORCES)
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    top_dbo = 0;
    top_dDelta = 0;
    dDeltas = lists[DDELTAS];
    dBOs = lists[DBOS];
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

    /* Calculate Deltaprime, Deltaprime_boc values */
    for ( i = 0; i < system->N; ++i )
    {
        type_i = system->my_atoms[i].type;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
        workspace->Deltap[i] = workspace->total_bond_order[i] - sbp_i->valency;
        workspace->Deltap_boc[i] =
            workspace->total_bond_order[i] - sbp_i->valency_val;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
    }

    /* Corrected Bond Order calculations */
    for ( i = 0; i < system->N; ++i )
    {
        type_i = system->my_atoms[i].type;
        sbp_i = &system->reax_param.sbp[type_i];
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
        val_i = sbp_i->valency;
        Deltap_i = workspace->Deltap[i];
        Deltap_boc_i = workspace->Deltap_boc[i];
        start_i = Start_Index( i, bond_list );
        end_i = End_Index( i, bond_list );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

        for ( pj = start_i; pj < end_i; ++pj )
        {
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
            type_j = system->my_atoms[j].type;
            if ( i < j || workspace->bond_mark[j] > 3 )
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
            {
                twbp = &system->reax_param.tbp[
                    index_tbp(type_i, type_j, system->reax_param.num_atom_types) ];
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
                Set_Start_Index( pj, top_dbo, dBOs );
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
#endif

Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
                if ( twbp->ovc < 0.001 && twbp->v13cor < 0.001 )
                {
                    /* There is no correction to bond orders nor to derivatives of
                     * bond order prime! So we leave bond orders unchanged and
                     * set derivative of bond order coefficients s.t.
                     * dBO = dBOp & dBOxx = dBOxxp in Add_dBO_to_Forces */
                    bo_ij->C1dbo = 1.0;
                    bo_ij->C2dbo = 0.0;
                    bo_ij->C3dbo = 0.0;

                    bo_ij->C1dbopi = 1.0;
                    bo_ij->C2dbopi = 0.0;
                    bo_ij->C3dbopi = 0.0;
                    bo_ij->C4dbopi = 0.0;

                    bo_ij->C1dbopi2 = 1.0;
                    bo_ij->C2dbopi2 = 0.0;
                    bo_ij->C3dbopi2 = 0.0;
                    bo_ij->C4dbopi2 = 0.0;
Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed

Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
                    pdbo->wrt = i;
                    rvec_Copy( pdbo->dBO, bo_ij->dBOp );
                    rvec_Scale( pdbo->dBOpi, bo_ij->BO_pi, bo_ij->dln_BOp_pi );
                    rvec_Scale( pdbo->dBOpi2, bo_ij->BO_pi2, bo_ij->dln_BOp_pi2);

Kurt A. O'Hearn's avatar
Kurt A. O'Hearn committed
                    pdbo->wrt = j;
                    rvec_Scale( pdbo->dBO, -1.0, bo_ij->dBOp );
                    rvec_Scale( pdbo->dBOpi, -bo_ij->BO_pi, bo_ij->dln_BOp_pi );
                    rvec_Scale(pdbo->dBOpi2, -bo_ij->BO_pi2, bo_ij->dln_BOp_pi2);