void Hydrogen_Bonds( reax_system *system, control_params *control,
                     simulation_data *data, storage *workspace,
                     reax_list **lists, output_controls *out_control )
{
  int  i, j, k, pi, pk;
  int  type_i, type_j, type_k;
  int  start_j, end_j, hb_start_j, hb_end_j;
  int  hblist[MAX_BONDS];
  int  itr, top;
  int  num_hb_intrs = 0;
  ivec rel_jk;
  real r_ij, r_jk, theta, cos_theta, sin_xhz4, cos_xhz1, sin_theta2;
  real e_hb, exp_hb2, exp_hb3, CEhb1, CEhb2, CEhb3;
  rvec dcos_theta_di, dcos_theta_dj, dcos_theta_dk;
  rvec dvec_jk, force, ext_press;
  // rtensor temp_rtensor, total_rtensor;
  hbond_parameters *hbp;
  bond_order_data *bo_ij;
  bond_data *pbond_ij;
  far_neighbor_data *nbr_jk;
  reax_list *bonds, *hbonds;
  bond_data *bond_list;
  hbond_data *hbond_list;

  // tally variables
  real fi_tmp[3], fk_tmp[3], delij[3], delkj[3];

  bonds = (*lists) + BONDS;
  bond_list = bonds->select.bond_list;
  hbonds = (*lists) + HBONDS;
  hbond_list = hbonds->select.hbond_list;

  /* loops below discover the Hydrogen bonds between i-j-k triplets.
     here j is H atom and there has to be some bond between i and j.
     Hydrogen bond is between j and k.
     so in this function i->X, j->H, k->Z when we map
     variables onto the ones in the handout.*/
  for( j = 0; j < system->n; ++j )
    /* j has to be of type H */
    if( system->reax_param.sbp[system->my_atoms[j].type].p_hbond == 1 ) {
      /*set j's variables */
      type_j     = system->my_atoms[j].type;
      start_j    = Start_Index(j, bonds);
      end_j      = End_Index(j, bonds);
      hb_start_j = Start_Index( system->my_atoms[j].Hindex, hbonds );
      hb_end_j   = End_Index( system->my_atoms[j].Hindex, hbonds );

      top = 0;
      for( pi = start_j; pi < end_j; ++pi )  {
        pbond_ij = &( bond_list[pi] );
        i = pbond_ij->nbr;
        bo_ij = &(pbond_ij->bo_data);
        type_i = system->my_atoms[i].type;

        if( system->reax_param.sbp[type_i].p_hbond == 2 &&
            bo_ij->BO >= HB_THRESHOLD )
          hblist[top++] = pi;
      }

      // fprintf( stderr, "j: %d, top: %d, hb_start_j: %d, hb_end_j:%d\n",
      //          j, top, hb_start_j, hb_end_j );

      for( pk = hb_start_j; pk < hb_end_j; ++pk ) {
        /* set k's varibles */
        k = hbond_list[pk].nbr;
        type_k = system->my_atoms[k].type;
        nbr_jk = hbond_list[pk].ptr;
        r_jk = nbr_jk->d;
        rvec_Scale( dvec_jk, hbond_list[pk].scl, nbr_jk->dvec );

        for( itr = 0; itr < top; ++itr ) {
          pi = hblist[itr];
          pbond_ij = &( bonds->select.bond_list[pi] );
          i = pbond_ij->nbr;

          if( system->my_atoms[i].orig_id != system->my_atoms[k].orig_id ) {
            bo_ij = &(pbond_ij->bo_data);
            type_i = system->my_atoms[i].type;
            r_ij = pbond_ij->d;
            hbp = &(system->reax_param.hbp[ type_i ][ type_j ][ type_k ]);
            ++num_hb_intrs;

            Calculate_Theta( pbond_ij->dvec, pbond_ij->d, dvec_jk, r_jk,
                             &theta, &cos_theta );
            /* the derivative of cos(theta) */
            Calculate_dCos_Theta( pbond_ij->dvec, pbond_ij->d, dvec_jk, r_jk,
                                  &dcos_theta_di, &dcos_theta_dj,
                                  &dcos_theta_dk );

            /* hyrogen bond energy*/
            sin_theta2 = sin( theta/2.0 );
            sin_xhz4 = SQR(sin_theta2);
            sin_xhz4 *= sin_xhz4;
            cos_xhz1 = ( 1.0 - cos_theta );
            exp_hb2 = exp( -hbp->p_hb2 * bo_ij->BO );
            exp_hb3 = exp( -hbp->p_hb3 * ( hbp->r0_hb / r_jk +
                                           r_jk / hbp->r0_hb - 2.0 ) );

            data->my_en.e_hb += e_hb =
              hbp->p_hb1 * (1.0 - exp_hb2) * exp_hb3 * sin_xhz4;

            CEhb1 = hbp->p_hb1 * hbp->p_hb2 * exp_hb2 * exp_hb3 * sin_xhz4;
            CEhb2 = -hbp->p_hb1/2.0 * (1.0 - exp_hb2) * exp_hb3 * cos_xhz1;
            CEhb3 = -hbp->p_hb3 *
              (-hbp->r0_hb / SQR(r_jk) + 1.0 / hbp->r0_hb) * e_hb;

            /*fprintf( stdout,
              "%6d%6d%6d%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f%12.6f\n",
              system->my_atoms[i].orig_id, system->my_atoms[j].orig_id,
              system->my_atoms[k].orig_id,
              r_jk, theta, hbp->p_hb1, exp_hb2, hbp->p_hb3, hbp->r0_hb,
              exp_hb3, sin_xhz4, e_hb ); */

            /* hydrogen bond forces */
            bo_ij->Cdbo += CEhb1; // dbo term

            if( control->virial == 0 ) {
              // dcos terms
              rvec_ScaledAdd( workspace->f[i], +CEhb2, dcos_theta_di );
              rvec_ScaledAdd( workspace->f[j], +CEhb2, dcos_theta_dj );
              rvec_ScaledAdd( workspace->f[k], +CEhb2, dcos_theta_dk );
              // dr terms
              rvec_ScaledAdd( workspace->f[j], -CEhb3/r_jk, dvec_jk );
              rvec_ScaledAdd( workspace->f[k], +CEhb3/r_jk, dvec_jk );
            }
            else {
              /* for pressure coupling, terms that are not related to bond order
                 derivatives are added directly into pressure vector/tensor */
              rvec_Scale( force, +CEhb2, dcos_theta_di ); // dcos terms
              rvec_Add( workspace->f[i], force );
              rvec_iMultiply( ext_press, pbond_ij->rel_box, force );
              rvec_ScaledAdd( data->my_ext_press, 1.0, ext_press );

              rvec_ScaledAdd( workspace->f[j], +CEhb2, dcos_theta_dj );

              ivec_Scale( rel_jk, hbond_list[pk].scl, nbr_jk->rel_box );
              rvec_Scale( force, +CEhb2, dcos_theta_dk );
              rvec_Add( workspace->f[k], force );
              rvec_iMultiply( ext_press, rel_jk, force );
              rvec_ScaledAdd( data->my_ext_press, 1.0, ext_press );
              // dr terms
              rvec_ScaledAdd( workspace->f[j], -CEhb3/r_jk, dvec_jk );

              rvec_Scale( force, CEhb3/r_jk, dvec_jk );
              rvec_Add( workspace->f[k], force );
              rvec_iMultiply( ext_press, rel_jk, force );
              rvec_ScaledAdd( data->my_ext_press, 1.0, ext_press );
            }

            /* tally into per-atom virials */
            if (system->pair_ptr->vflag_atom || system->pair_ptr->evflag) {
              rvec_ScaledSum( delij, 1., system->my_atoms[i].x,
                                    -1., system->my_atoms[j].x );
              rvec_ScaledSum( delkj, 1., system->my_atoms[k].x,
                                     -1., system->my_atoms[j].x );

              rvec_Scale(fi_tmp, CEhb2, dcos_theta_di);
              rvec_Scale(fk_tmp, CEhb2, dcos_theta_dk);
              rvec_ScaledAdd(fk_tmp, CEhb3/r_jk, dvec_jk);

              system->pair_ptr->ev_tally3(i,j,k,e_hb,0.0,fi_tmp,fk_tmp,delij,delkj);
            }

#ifdef TEST_ENERGY
            /* fprintf( out_control->ehb,
               "%24.15e%24.15e%24.15e\n%24.15e%24.15e%24.15e\n%24.15e%24.15e%24.15e\n",
               dcos_theta_di[0], dcos_theta_di[1], dcos_theta_di[2],
               dcos_theta_dj[0], dcos_theta_dj[1], dcos_theta_dj[2],
               dcos_theta_dk[0], dcos_theta_dk[1], dcos_theta_dk[2]);
               fprintf( out_control->ehb, "%24.15e%24.15e%24.15e\n",
               CEhb1, CEhb2, CEhb3 ); */
            fprintf( out_control->ehb,
                     //"%6d%6d%6d%24.15e%24.15e%24.15e%24.15e%24.15e\n",
                     "%6d%6d%6d%12.4f%12.4f%12.4f%12.4f%12.4f\n",
                     system->my_atoms[i].orig_id, system->my_atoms[j].orig_id,
                     system->my_atoms[k].orig_id,
                     r_jk, theta, bo_ij->BO, e_hb, data->my_en.e_hb );
#endif
#ifdef TEST_FORCES
            Add_dBO( system, lists, j, pi, +CEhb1, workspace->f_hb ); //dbo term
            // dcos terms
            rvec_ScaledAdd( workspace->f_hb[i], +CEhb2, dcos_theta_di );
            rvec_ScaledAdd( workspace->f_hb[j], +CEhb2, dcos_theta_dj );
            rvec_ScaledAdd( workspace->f_hb[k], +CEhb2, dcos_theta_dk );
            // dr terms
            rvec_ScaledAdd( workspace->f_hb[j], -CEhb3/r_jk, dvec_jk );
            rvec_ScaledAdd( workspace->f_hb[k], +CEhb3/r_jk, dvec_jk );
#endif
          }
        }
      }
    }

#if defined(DEBUG)
  fprintf( stderr, "Number of hydrogen bonds: %d\n", num_hb_intrs );
  fprintf( stderr, "Hydrogen Bond Energy: %g\n", data->my_en.e_hb );
  fprintf( stderr, "hydbonds: ext_press (%24.15e %24.15e %24.15e)\n",
           data->ext_press[0], data->ext_press[1], data->ext_press[2] );
#endif
}
Example #2
0
void Bonds( reax_system *system, control_params *control, 
	    simulation_data *data, storage *workspace, reax_list **lists, 
	    output_controls *out_control )
{
  int i, j, pj, natoms;
  int start_i, end_i;
  int type_i, type_j;
  real ebond, pow_BOs_be2, exp_be12, CEbo;
  real gp3, gp4, gp7, gp10, gp37;
  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;
  reax_list *bonds;

  bonds = (*lists) + BONDS;
  gp3 = system->reax_param.gp.l[3];
  gp4 = system->reax_param.gp.l[4];
  gp7 = system->reax_param.gp.l[7];
  gp10 = system->reax_param.gp.l[10];
  gp37 = (int) system->reax_param.gp.l[37];
  natoms = system->n;

  for( i = 0; i < natoms; ++i ) {
    start_i = Start_Index(i, bonds);
    end_i = End_Index(i, bonds);

    for( pj = start_i; pj < end_i; ++pj ) {
      j = bonds->select.bond_list[pj].nbr;
      
      if( system->my_atoms[i].orig_id <= system->my_atoms[j].orig_id ) {
	/* set the pointers */
	type_i = system->my_atoms[i].type;
	type_j = system->my_atoms[j].type;
	sbp_i = &( system->reax_param.sbp[type_i] );
	sbp_j = &( system->reax_param.sbp[type_j] );
	twbp = &( system->reax_param.tbp[type_i][type_j] );
	bo_ij = &( bonds->select.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 */
	data->my_en.e_bond += ebond = 
	  -twbp->De_s * bo_ij->BO_s * exp_be12 
	  -twbp->De_p * bo_ij->BO_pi 
	  -twbp->De_pp * bo_ij->BO_pi2;
	
	/* tally into per-atom energy */
        if( system->evflag)
          system->pair_ptr->ev_tally(i,j,natoms,1,ebond,0.0,0.0,0.0,0.0,0.0);
	
	/* calculate derivatives of Bond Orders */
	bo_ij->Cdbo += CEbo;
	bo_ij->Cdbopi -= (CEbo + twbp->De_p);
	bo_ij->Cdbopi2 -= (CEbo + twbp->De_pp);
	      
#ifdef TEST_ENERGY
	//fprintf( out_control->ebond, "%6d%6d%24.15e%24.15e%24.15e\n",
	fprintf( out_control->ebond, "%6d%6d%12.4f%12.4f%12.4f\n",
		 system->my_atoms[i].orig_id, 
		 system->my_atoms[j].orig_id, 
		 bo_ij->BO, ebond, data->my_en.e_bond );
#endif
#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 );
#endif
	/* Stabilisation terminal triple bond */
	if( bo_ij->BO >= 1.00 ) {
	  if( gp37 == 2 ||
	      (sbp_i->mass == 12.0000 && sbp_j->mass == 15.9990) || 
	      (sbp_j->mass == 12.0000 && sbp_i->mass == 15.9990) ) {
	    exphu = exp( -gp7 * SQR(bo_ij->BO - 2.50) );
	    exphua1 = exp(-gp3 * (workspace->total_bond_order[i]-bo_ij->BO));
	    exphub1 = exp(-gp3 * (workspace->total_bond_order[j]-bo_ij->BO));
	    exphuov = exp(gp4 * (workspace->Delta[i] + workspace->Delta[j]));
	    hulpov = 1.0 / (1.0 + 25.0 * exphuov);
	    
	    estriph = gp10 * exphu * hulpov * (exphua1 + exphub1);
	    data->my_en.e_bond += estriph;
	    
	    decobdbo = gp10 * exphu * hulpov * (exphua1 + exphub1) *
	      ( gp3 - 2.0 * gp7 * (bo_ij->BO-2.50) );
	    decobdboua = -gp10 * exphu * hulpov *
	      (gp3*exphua1 + 25.0*gp4*exphuov*hulpov*(exphua1+exphub1));
	    decobdboub = -gp10 * exphu * hulpov *
	      (gp3*exphub1 + 25.0*gp4*exphuov*hulpov*(exphua1+exphub1));
	    
	    /* tally into per-atom energy */
	    if( system->evflag)
	      system->pair_ptr->ev_tally(i,j,natoms,1,estriph,0.0,0.0,0.0,0.0,0.0);
	    
	    bo_ij->Cdbo += decobdbo;
	    workspace->CdDelta[i] += decobdboua;
	    workspace->CdDelta[j] += decobdboub;
#ifdef TEST_ENERGY
	    //fprintf( out_control->ebond, 
	    //  "%6d%6d%24.15e%24.15e%24.15e%24.15e\n",
	    //  system->my_atoms[i].orig_id, system->my_atoms[j].orig_id,
	    //  estriph, decobdbo, decobdboua, decobdboub );
#endif
#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 );
#endif
	  }
	}
      }
    }
  }
}