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 }
void Init_Forces(reax_system *system, control_params *control, simulation_data *data, static_storage *workspace, list **lists, output_controls *out_control) { int i, j, pj; int start_i, end_i; int type_i, type_j; int Htop, btop_i, btop_j, num_bonds, num_hbonds; int ihb, jhb, ihb_top, jhb_top; int flag; real r_ij, r2, self_coef; real dr3gamij_1, dr3gamij_3, Tap; //real val, dif, base; real C12, C34, C56; real Cln_BOp_s, Cln_BOp_pi, Cln_BOp_pi2; real BO, BO_s, BO_pi, BO_pi2; real p_boc1, p_boc2; sparse_matrix *H; list *far_nbrs, *bonds, *hbonds; single_body_parameters *sbp_i, *sbp_j; two_body_parameters *twbp; far_neighbor_data *nbr_pj; //LR_lookup_table *t; reax_atom *atom_i, *atom_j; bond_data *ibond, *jbond; bond_order_data *bo_ij, *bo_ji; far_nbrs = *lists + FAR_NBRS; bonds = *lists + BONDS; hbonds = *lists + HBONDS; H = workspace->H; Htop = 0; num_bonds = 0; num_hbonds = 0; btop_i = btop_j = 0; p_boc1 = system->reaxprm.gp.l[0]; p_boc2 = system->reaxprm.gp.l[1]; for (i = 0; i < system->N; ++i) { atom_i = &(system->atoms[i]); type_i = atom_i->type; start_i = Start_Index(i, far_nbrs); end_i = End_Index(i, far_nbrs); H->start[i] = Htop; btop_i = End_Index(i, bonds); sbp_i = &(system->reaxprm.sbp[type_i]); ihb = ihb_top = -1; if (control->hb_cut > 0 && (ihb = sbp_i->p_hbond) == 1) ihb_top = End_Index(workspace->hbond_index[i], hbonds); for (pj = start_i; pj < end_i; ++pj) { nbr_pj = &(far_nbrs->select.far_nbr_list[pj]); j = nbr_pj->nbr; atom_j = &(system->atoms[j]); flag = 0; if ((data->step - data->prev_steps) % control->reneighbor == 0) { if (nbr_pj->d <= control->r_cut) flag = 1; else flag = 0; } else if ((nbr_pj->d = Sq_Distance_on_T3(atom_i->x, atom_j->x, &(system->box), nbr_pj->dvec)) <= SQR(control->r_cut)) { nbr_pj->d = sqrt(nbr_pj->d); flag = 1; } if (flag) { type_j = system->atoms[j].type; r_ij = nbr_pj->d; sbp_j = &(system->reaxprm.sbp[type_j]); twbp = &(system->reaxprm.tbp[type_i][type_j]); self_coef = (i == j) ? 0.5 : 1.0; /* H matrix entry */ Tap = control->Tap7 * r_ij + control->Tap6; Tap = Tap * r_ij + control->Tap5; Tap = Tap * r_ij + control->Tap4; Tap = Tap * r_ij + control->Tap3; Tap = Tap * r_ij + control->Tap2; Tap = Tap * r_ij + control->Tap1; Tap = Tap * r_ij + control->Tap0; dr3gamij_1 = (r_ij * r_ij * r_ij + twbp->gamma); dr3gamij_3 = POW(dr3gamij_1, 0.33333333333333); H->entries[Htop].j = j; H->entries[Htop].val = self_coef * Tap * EV_to_KCALpMOL / dr3gamij_3; ++Htop; /* hydrogen bond lists */ if (control->hb_cut > 0 && (ihb == 1 || ihb == 2) && nbr_pj->d <= control->hb_cut) { // fprintf( stderr, "%d %d\n", atom1, atom2 ); jhb = sbp_j->p_hbond; if (ihb == 1 && jhb == 2) { hbonds->select.hbond_list[ihb_top].nbr = j; hbonds->select.hbond_list[ihb_top].scl = 1; hbonds->select.hbond_list[ihb_top].ptr = nbr_pj; ++ihb_top; ++num_hbonds; } else if (ihb == 2 && jhb == 1) { jhb_top = End_Index(workspace->hbond_index[j], hbonds); hbonds->select.hbond_list[jhb_top].nbr = i; hbonds->select.hbond_list[jhb_top].scl = -1; hbonds->select.hbond_list[jhb_top].ptr = nbr_pj; Set_End_Index(workspace->hbond_index[j], jhb_top + 1, hbonds); ++num_hbonds; } } /* uncorrected bond orders */ if (far_nbrs->select.far_nbr_list[pj].d <= control->nbr_cut) { r2 = SQR(r_ij); if (sbp_i->r_s > 0.0 && sbp_j->r_s > 0.0) { C12 = twbp->p_bo1 * POW(r_ij / twbp->r_s, twbp->p_bo2); BO_s = (1.0 + control->bo_cut) * EXP(C12); } else BO_s = C12 = 0.0; if (sbp_i->r_pi > 0.0 && sbp_j->r_pi > 0.0) { C34 = twbp->p_bo3 * POW(r_ij / twbp->r_p, twbp->p_bo4); BO_pi = EXP(C34); } else BO_pi = C34 = 0.0; if (sbp_i->r_pi_pi > 0.0 && sbp_j->r_pi_pi > 0.0) { C56 = twbp->p_bo5 * POW(r_ij / twbp->r_pp, twbp->p_bo6); BO_pi2 = EXP(C56); } else BO_pi2 = C56 = 0.0; /* Initially BO values are the uncorrected ones, page 1 */ BO = BO_s + BO_pi + BO_pi2; if (BO >= control->bo_cut) { num_bonds += 2; /****** bonds i-j and j-i ******/ ibond = &(bonds->select.bond_list[btop_i]); btop_j = End_Index(j, bonds); jbond = &(bonds->select.bond_list[btop_j]); ibond->nbr = j; jbond->nbr = i; ibond->d = r_ij; jbond->d = r_ij; rvec_Copy(ibond->dvec, nbr_pj->dvec); rvec_Scale(jbond->dvec, -1, nbr_pj->dvec); ivec_Copy(ibond->rel_box, nbr_pj->rel_box); ivec_Scale(jbond->rel_box, -1, nbr_pj->rel_box); ibond->dbond_index = btop_i; jbond->dbond_index = btop_i; ibond->sym_index = btop_j; jbond->sym_index = btop_i; ++btop_i; Set_End_Index(j, btop_j + 1, bonds); bo_ij = &(ibond->bo_data); bo_ji = &(jbond->bo_data); bo_ji->BO = bo_ij->BO = BO; bo_ji->BO_s = bo_ij->BO_s = BO_s; bo_ji->BO_pi = bo_ij->BO_pi = BO_pi; bo_ji->BO_pi2 = bo_ij->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, -bo_ij->BO_s * Cln_BOp_s, ibond->dvec); rvec_Scale(bo_ij->dln_BOp_pi, -bo_ij->BO_pi * Cln_BOp_pi, ibond->dvec); rvec_Scale(bo_ij->dln_BOp_pi2, -bo_ij->BO_pi2 * Cln_BOp_pi2, ibond->dvec); rvec_Scale(bo_ji->dln_BOp_s, -1., bo_ij->dln_BOp_s); rvec_Scale(bo_ji->dln_BOp_pi, -1., bo_ij->dln_BOp_pi); rvec_Scale(bo_ji->dln_BOp_pi2, -1., 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, -(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., bo_ij->dBOp); rvec_Add(workspace->dDeltap_self[i], bo_ij->dBOp); rvec_Add(workspace->dDeltap_self[j], bo_ji->dBOp); bo_ij->BO_s -= control->bo_cut; bo_ij->BO -= control->bo_cut; bo_ji->BO_s -= control->bo_cut; bo_ji->BO -= control->bo_cut; workspace->total_bond_order[i] += bo_ij->BO; //currently total_BOp workspace->total_bond_order[j] += bo_ji->BO; //currently total_BOp bo_ij->Cdbo = bo_ij->Cdbopi = bo_ij->Cdbopi2 = 0.0; bo_ji->Cdbo = bo_ji->Cdbopi = bo_ji->Cdbopi2 = 0.0; /*fprintf( stderr, "%d %d %g %g %g\n", i+1, j+1, bo_ij->BO, bo_ij->BO_pi, bo_ij->BO_pi2 );*/ /*fprintf( stderr, "Cln_BOp_s: %f, pbo2: %f, C12:%f\n", Cln_BOp_s, twbp->p_bo2, C12 ); fprintf( stderr, "Cln_BOp_pi: %f, pbo4: %f, C34:%f\n", Cln_BOp_pi, twbp->p_bo4, C34 ); fprintf( stderr, "Cln_BOp_pi2: %f, pbo6: %f, C56:%f\n", Cln_BOp_pi2, twbp->p_bo6, C56 );*/ /*fprintf(stderr, "pbo1: %f, pbo2:%f\n", twbp->p_bo1, twbp->p_bo2); fprintf(stderr, "pbo3: %f, pbo4:%f\n", twbp->p_bo3, twbp->p_bo4); fprintf(stderr, "pbo5: %f, pbo6:%f\n", twbp->p_bo5, twbp->p_bo6); fprintf( stderr, "r_s: %f, r_p: %f, r_pp: %f\n", twbp->r_s, twbp->r_p, twbp->r_pp ); fprintf( stderr, "C12: %g, C34:%g, C56:%g\n", C12, C34, C56 );*/ /*fprintf( stderr, "\tfactors: %g %g %g\n", -(bo_ij->BO_s * Cln_BOp_s + bo_ij->BO_pi * Cln_BOp_pi + bo_ij->BO_pi2 * Cln_BOp_pp), -bo_ij->BO_pi * Cln_BOp_pi, -bo_ij->BO_pi2 * Cln_BOp_pi2 );*/ /*fprintf( stderr, "dBOpi:\t[%g, %g, %g]\n", bo_ij->dBOp[0], bo_ij->dBOp[1], bo_ij->dBOp[2] ); fprintf( stderr, "dBOpi:\t[%g, %g, %g]\n", bo_ij->dln_BOp_pi[0], bo_ij->dln_BOp_pi[1], bo_ij->dln_BOp_pi[2] ); fprintf( stderr, "dBOpi2:\t[%g, %g, %g]\n\n", bo_ij->dln_BOp_pi2[0], bo_ij->dln_BOp_pi2[1], bo_ij->dln_BOp_pi2[2] );*/ Set_End_Index(j, btop_j + 1, bonds); } } } } H->entries[Htop].j = i; H->entries[Htop].val = system->reaxprm.sbp[type_i].eta; ++Htop; Set_End_Index(i, btop_i, bonds); if (ihb == 1) Set_End_Index(workspace->hbond_index[i], ihb_top, hbonds); //fprintf( stderr, "%d bonds start: %d, end: %d\n", // i, Start_Index( i, bonds ), End_Index( i, bonds ) ); } // mark the end of j list H->start[i] = Htop; /* validate lists - decide if reallocation is required! */ Validate_Lists(workspace, lists, data->step, system->N, H->m, Htop, num_bonds, num_hbonds); #if defined(DEBUG_FOCUS) fprintf( stderr, "step%d: Htop = %d, num_bonds = %d, num_hbonds = %d\n", data->step, Htop, num_bonds, num_hbonds ); #endif }
int BOp( storage *workspace, reax_list *bonds, double bo_cut, int i, int btop_i, far_neighbor_data *nbr_pj, single_body_parameters *sbp_i, single_body_parameters *sbp_j, two_body_parameters *twbp ) { int j, btop_j; double r2, C12, C34, C56; double Cln_BOp_s, Cln_BOp_pi, Cln_BOp_pi2; double BO, BO_s, BO_pi, BO_pi2; bond_data *ibond, *jbond; bond_order_data *bo_ij, *bo_ji; j = nbr_pj->nbr; r2 = SQR(nbr_pj->d); if( sbp_i->r_s > 0.0 && sbp_j->r_s > 0.0 ) { C12 = twbp->p_bo1 * pow( nbr_pj->d / twbp->r_s, twbp->p_bo2 ); BO_s = (1.0 + bo_cut) * exp( C12 ); } else BO_s = C12 = 0.0; if( sbp_i->r_pi > 0.0 && sbp_j->r_pi > 0.0 ) { C34 = twbp->p_bo3 * pow( nbr_pj->d / twbp->r_p, twbp->p_bo4 ); BO_pi = exp( C34 ); } else BO_pi = C34 = 0.0; if( sbp_i->r_pi_pi > 0.0 && sbp_j->r_pi_pi > 0.0 ) { C56 = twbp->p_bo5 * pow( nbr_pj->d / twbp->r_pp, twbp->p_bo6 ); BO_pi2= exp( C56 ); } else BO_pi2 = C56 = 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->select.bond_list[btop_i] ); btop_j = End_Index( j, bonds ); jbond = &(bonds->select.bond_list[btop_j]); ibond->nbr = j; jbond->nbr = i; ibond->d = nbr_pj->d; jbond->d = nbr_pj->d; rvec_Copy( ibond->dvec, nbr_pj->dvec ); rvec_Scale( jbond->dvec, -1, nbr_pj->dvec ); ivec_Copy( ibond->rel_box, nbr_pj->rel_box ); ivec_Scale( jbond->rel_box, -1, nbr_pj->rel_box ); ibond->dbond_index = btop_i; jbond->dbond_index = btop_i; ibond->sym_index = btop_j; jbond->sym_index = btop_i; Set_End_Index( j, btop_j+1, bonds ); bo_ij = &( ibond->bo_data ); bo_ji = &( jbond->bo_data ); bo_ji->BO = bo_ij->BO = BO; bo_ji->BO_s = bo_ij->BO_s = BO_s; bo_ji->BO_pi = bo_ij->BO_pi = BO_pi; bo_ji->BO_pi2 = bo_ij->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,-bo_ij->BO_s*Cln_BOp_s,ibond->dvec); rvec_Scale(bo_ij->dln_BOp_pi,-bo_ij->BO_pi*Cln_BOp_pi,ibond->dvec); rvec_Scale(bo_ij->dln_BOp_pi2, -bo_ij->BO_pi2*Cln_BOp_pi2,ibond->dvec); rvec_Scale(bo_ji->dln_BOp_s, -1., bo_ij->dln_BOp_s); rvec_Scale(bo_ji->dln_BOp_pi, -1., bo_ij->dln_BOp_pi ); rvec_Scale(bo_ji->dln_BOp_pi2, -1., bo_ij->dln_BOp_pi2 ); rvec_Scale( bo_ij->dBOp, -(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., bo_ij->dBOp ); 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; bo_ji->BO_s -= bo_cut; bo_ji->BO -= bo_cut; workspace->total_bond_order[i] += bo_ij->BO; //currently total_BOp workspace->total_bond_order[j] += bo_ji->BO; //currently total_BOp bo_ij->Cdbo = bo_ij->Cdbopi = bo_ij->Cdbopi2 = 0.0; bo_ji->Cdbo = bo_ji->Cdbopi = bo_ji->Cdbopi2 = 0.0; return 1; } return 0; }
void Init_Forces_Tab(reax_system *system, control_params *control, simulation_data *data, static_storage *workspace, list **lists, output_controls *out_control) { int i, j, pj; int start_i, end_i; int type_i, type_j; int Htop, btop_i, btop_j, num_bonds, num_hbonds; int tmin, tmax, r; int ihb, jhb, ihb_top, jhb_top; int flag; real r_ij, r2, self_coef; real val, dif, base; real C12, C34, C56; real Cln_BOp_s, Cln_BOp_pi, Cln_BOp_pi2; real BO, BO_s, BO_pi, BO_pi2; real p_boc1, p_boc2; sparse_matrix *H; list *far_nbrs, *bonds, *hbonds; single_body_parameters *sbp_i, *sbp_j; two_body_parameters *twbp; far_neighbor_data *nbr_pj; LR_lookup_table *t; reax_atom *atom_i, *atom_j; bond_data *ibond, *jbond; bond_order_data *bo_ij, *bo_ji; far_nbrs = *lists + FAR_NBRS; bonds = *lists + BONDS; hbonds = *lists + HBONDS; H = workspace->H; Htop = 0; num_bonds = 0; num_hbonds = 0; btop_i = btop_j = 0; p_boc1 = system->reaxprm.gp.l[0]; p_boc2 = system->reaxprm.gp.l[1]; for (i = 0; i < system->N; ++i) { atom_i = &(system->atoms[i]); type_i = atom_i->type; start_i = Start_Index(i, far_nbrs); end_i = End_Index(i, far_nbrs); H->start[i] = Htop; btop_i = End_Index(i, bonds); sbp_i = &(system->reaxprm.sbp[type_i]); ihb = ihb_top = -1; if (control->hb_cut > 0 && (ihb = sbp_i->p_hbond) == 1) ihb_top = End_Index(workspace->hbond_index[i], hbonds); for (pj = start_i; pj < end_i; ++pj) { nbr_pj = &(far_nbrs->select.far_nbr_list[pj]); j = nbr_pj->nbr; atom_j = &(system->atoms[j]); flag = 0; if ((data->step - data->prev_steps) % control->reneighbor == 0) { if (nbr_pj->d <= control->r_cut) flag = 1; else flag = 0; } else if ((nbr_pj->d = Sq_Distance_on_T3(atom_i->x, atom_j->x, &(system->box), nbr_pj->dvec)) <= SQR(control->r_cut)) { nbr_pj->d = sqrt(nbr_pj->d); flag = 1; } if (flag) { type_j = system->atoms[j].type; r_ij = nbr_pj->d; sbp_j = &(system->reaxprm.sbp[type_j]); twbp = &(system->reaxprm.tbp[type_i][type_j]); self_coef = (i == j) ? 0.5 : 1.0; tmin = MIN( type_i, type_j ); tmax = MAX( type_i, type_j ); t = &(LR[tmin][tmax]); /* cubic spline interpolation */ r = (int) (r_ij * t->inv_dx); if (r == 0) ++r; base = (real) (r + 1) * t->dx; dif = r_ij - base; val = ((t->ele[r].d * dif + t->ele[r].c) * dif + t->ele[r].b) * dif + t->ele[r].a; val *= EV_to_KCALpMOL / C_ele; H->entries[Htop].j = j; H->entries[Htop].val = self_coef * val; ++Htop; /* hydrogen bond lists */ if (control->hb_cut > 0 && (ihb == 1 || ihb == 2) && nbr_pj->d <= control->hb_cut) { // fprintf( stderr, "%d %d\n", atom1, atom2 ); jhb = sbp_j->p_hbond; if (ihb == 1 && jhb == 2) { hbonds->select.hbond_list[ihb_top].nbr = j; hbonds->select.hbond_list[ihb_top].scl = 1; hbonds->select.hbond_list[ihb_top].ptr = nbr_pj; ++ihb_top; ++num_hbonds; } else if (ihb == 2 && jhb == 1) { jhb_top = End_Index(workspace->hbond_index[j], hbonds); hbonds->select.hbond_list[jhb_top].nbr = i; hbonds->select.hbond_list[jhb_top].scl = -1; hbonds->select.hbond_list[jhb_top].ptr = nbr_pj; Set_End_Index(workspace->hbond_index[j], jhb_top + 1, hbonds); ++num_hbonds; } } /* uncorrected bond orders */ if (far_nbrs->select.far_nbr_list[pj].d <= control->nbr_cut) { r2 = SQR(r_ij); if (sbp_i->r_s > 0.0 && sbp_j->r_s > 0.0) { C12 = twbp->p_bo1 * POW(r_ij / twbp->r_s, twbp->p_bo2); BO_s = (1.0 + control->bo_cut) * EXP(C12); } else BO_s = C12 = 0.0; if (sbp_i->r_pi > 0.0 && sbp_j->r_pi > 0.0) { C34 = twbp->p_bo3 * POW(r_ij / twbp->r_p, twbp->p_bo4); BO_pi = EXP(C34); } else BO_pi = C34 = 0.0; if (sbp_i->r_pi_pi > 0.0 && sbp_j->r_pi_pi > 0.0) { C56 = twbp->p_bo5 * POW(r_ij / twbp->r_pp, twbp->p_bo6); BO_pi2 = EXP(C56); } else BO_pi2 = C56 = 0.0; /* Initially BO values are the uncorrected ones, page 1 */ BO = BO_s + BO_pi + BO_pi2; if (BO >= control->bo_cut) { num_bonds += 2; /****** bonds i-j and j-i ******/ ibond = &(bonds->select.bond_list[btop_i]); btop_j = End_Index(j, bonds); jbond = &(bonds->select.bond_list[btop_j]); ibond->nbr = j; jbond->nbr = i; ibond->d = r_ij; jbond->d = r_ij; rvec_Copy(ibond->dvec, nbr_pj->dvec); rvec_Scale(jbond->dvec, -1, nbr_pj->dvec); ivec_Copy(ibond->rel_box, nbr_pj->rel_box); ivec_Scale(jbond->rel_box, -1, nbr_pj->rel_box); ibond->dbond_index = btop_i; jbond->dbond_index = btop_i; ibond->sym_index = btop_j; jbond->sym_index = btop_i; ++btop_i; Set_End_Index(j, btop_j + 1, bonds); bo_ij = &(ibond->bo_data); bo_ji = &(jbond->bo_data); bo_ji->BO = bo_ij->BO = BO; bo_ji->BO_s = bo_ij->BO_s = BO_s; bo_ji->BO_pi = bo_ij->BO_pi = BO_pi; bo_ji->BO_pi2 = bo_ij->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, -bo_ij->BO_s * Cln_BOp_s, ibond->dvec); rvec_Scale(bo_ij->dln_BOp_pi, -bo_ij->BO_pi * Cln_BOp_pi, ibond->dvec); rvec_Scale(bo_ij->dln_BOp_pi2, -bo_ij->BO_pi2 * Cln_BOp_pi2, ibond->dvec); rvec_Scale(bo_ji->dln_BOp_s, -1., bo_ij->dln_BOp_s); rvec_Scale(bo_ji->dln_BOp_pi, -1., bo_ij->dln_BOp_pi); rvec_Scale(bo_ji->dln_BOp_pi2, -1., 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, -(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., bo_ij->dBOp); rvec_Add(workspace->dDeltap_self[i], bo_ij->dBOp); rvec_Add(workspace->dDeltap_self[j], bo_ji->dBOp); bo_ij->BO_s -= control->bo_cut; bo_ij->BO -= control->bo_cut; bo_ji->BO_s -= control->bo_cut; bo_ji->BO -= control->bo_cut; workspace->total_bond_order[i] += bo_ij->BO; //currently total_BOp workspace->total_bond_order[j] += bo_ji->BO; //currently total_BOp bo_ij->Cdbo = bo_ij->Cdbopi = bo_ij->Cdbopi2 = 0.0; bo_ji->Cdbo = bo_ji->Cdbopi = bo_ji->Cdbopi2 = 0.0; Set_End_Index(j, btop_j + 1, bonds); } } } } H->entries[Htop].j = i; H->entries[Htop].val = system->reaxprm.sbp[type_i].eta; ++Htop; Set_End_Index(i, btop_i, bonds); if (ihb == 1) Set_End_Index(workspace->hbond_index[i], ihb_top, hbonds); } // mark the end of j list H->start[i] = Htop; /* validate lists - decide if reallocation is required! */ Validate_Lists(workspace, lists, data->step, system->N, H->m, Htop, num_bonds, num_hbonds); #if defined(DEBUG_FOCUS) fprintf( stderr, "step%d: Htop = %d, num_bonds = %d, num_hbonds = %d\n", data->step, Htop, num_bonds, num_hbonds ); //Print_Bonds( system, bonds, "sbonds.out" ); //Print_Bond_List2( system, bonds, "sbonds.out" ); //Print_Sparse_Matrix2( H, "H.out" ); #endif }
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_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; 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; for( j = 0; j < system->n; ++j ) if( system->reax_param.sbp[system->my_atoms[j].type].p_hbond == 1 ) { 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 ); if (type_j < 0) continue; top = 0; for( pi = start_j; pi < end_j; ++pi ) { pbond_ij = &( bond_list[pi] ); i = pbond_ij->nbr; type_i = system->my_atoms[i].type; if (type_i < 0) continue; bo_ij = &(pbond_ij->bo_data); if( system->reax_param.sbp[type_i].p_hbond == 2 && bo_ij->BO >= HB_THRESHOLD ) hblist[top++] = pi; } 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; if (type_k < 0) continue; 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; if (type_i < 0) continue; 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; /* 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 { 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[j].x, -1., system->my_atoms[i].x ); rvec_ScaledSum( delkj, 1., system->my_atoms[j].x, -1., system->my_atoms[k].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); } } } } } }