void Reset_Neighbor_Lists( reax_system *system, control_params *control,
                           storage *workspace, reax_list **lists,
                           MPI_Comm comm )
{
  int i, total_bonds, Hindex, total_hbonds;
  reax_list *bonds, *hbonds;

  /* bonds list */
  if (system->N > 0) {
    bonds = (*lists) + BONDS;
    total_bonds = 0;

    /* reset start-end indexes */
    for( i = 0; i < system->N; ++i ) {
      Set_Start_Index( i, total_bonds, bonds );
      Set_End_Index( i, total_bonds, bonds );
      total_bonds += system->my_atoms[i].num_bonds;
    }

    /* is reallocation needed? */
    if (total_bonds >= bonds->num_intrs * DANGER_ZONE) {
      workspace->realloc.bonds = 1;
      if (total_bonds >= bonds->num_intrs) {
        fprintf(stderr,
                "p%d: not enough space for bonds! total=%d allocated=%d\n",
                system->my_rank, total_bonds, bonds->num_intrs );
        MPI_Abort( comm, INSUFFICIENT_MEMORY );
      }
    }
  }

  if (control->hbond_cut > 0 && system->numH > 0) {
    hbonds = (*lists) + HBONDS;
    total_hbonds = 0;

    /* reset start-end indexes */
    for( i = 0; i < system->n; ++i ) {
      Hindex = system->my_atoms[i].Hindex;
      if (Hindex > -1) {
        Set_Start_Index( Hindex, total_hbonds, hbonds );
        Set_End_Index( Hindex, total_hbonds, hbonds );
        total_hbonds += system->my_atoms[i].num_hbonds;
      }
    }

    /* is reallocation needed? */
    if (total_hbonds >= hbonds->num_intrs * 0.90/*DANGER_ZONE*/) {
      workspace->realloc.hbonds = 1;
      if (total_hbonds >= hbonds->num_intrs) {
        fprintf(stderr,
                "p%d: not enough space for hbonds! total=%d allocated=%d\n",
                system->my_rank, total_hbonds, hbonds->num_intrs );
        MPI_Abort( comm, INSUFFICIENT_MEMORY );
      }
    }
  }
}
Exemple #2
0
// copy bond list into old bond list
void Copy_Bond_List( reax_system *system, control_params *control,
		     list **lists )
{
  int i, j, top_old;
  list *new_bonds = (*lists) + BONDS;
  list *old_bonds = (*lists) + OLD_BONDS;

  for( top_old = 0, i = 0; i < system->N; ++i ) {
    Set_Start_Index( i, top_old, old_bonds );

    // fprintf( stdout, "%d: ", i );
    for( j = Start_Index( i, new_bonds ); j < End_Index( i, new_bonds ); ++j )
      if( new_bonds->select.bond_list[j].bo_data.BO >= control->bg_cut ) {
	// fprintf( stderr, "%d ", new_bonds->select.bond_list[j].nbr );
	old_bonds->select.bond_list[ top_old ].nbr =
	  new_bonds->select.bond_list[j].nbr;
	old_bonds->select.bond_list[ top_old ].bo_data.BO =
	  new_bonds->select.bond_list[j].bo_data.BO;
	top_old++;
      }

    Set_End_Index( i, top_old, old_bonds);
    // fprintf( stderr, "--- s: %d, e: %d\n",
    // Start_Index( i, old_bonds ),  End_Index( i, old_bonds ) );
  }
}
Exemple #3
0
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
}
Exemple #4
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 Init_Forces_noQEq( reax_system *system, control_params *control,
                        simulation_data *data, storage *workspace,
                        reax_list **lists, output_controls *out_control,
                        MPI_Comm comm ) {
  int i, j, pj;
  int start_i, end_i;
  int type_i, type_j;
  int btop_i, btop_j, num_bonds, num_hbonds;
  int ihb, jhb, ihb_top, jhb_top;
  int local, flag, renbr;
  double cutoff;
  reax_list *far_nbrs, *bonds, *hbonds;
  single_body_parameters *sbp_i, *sbp_j;
  two_body_parameters *twbp;
  far_neighbor_data *nbr_pj;
  reax_atom *atom_i, *atom_j;

  far_nbrs = *lists + FAR_NBRS;
  bonds = *lists + BONDS;
  hbonds = *lists + HBONDS;

  for( i = 0; i < system->n; ++i )
    workspace->bond_mark[i] = 0;
  for( i = system->n; i < system->N; ++i ) {
    workspace->bond_mark[i] = 1000; // put ghost atoms to an infinite distance
  }

  num_bonds = 0;
  num_hbonds = 0;
  btop_i = btop_j = 0;
  renbr = (data->step-data->prev_steps) % control->reneighbor == 0;

  for( i = 0; i < system->N; ++i ) {
    atom_i = &(system->my_atoms[i]);
    type_i  = atom_i->type;
    if (type_i < 0) continue;
    start_i = Start_Index(i, far_nbrs);
    end_i   = End_Index(i, far_nbrs);
    btop_i = End_Index( i, bonds );
    sbp_i = &(system->reax_param.sbp[type_i]);

    if( i < system->n ) {
      local = 1;
      cutoff = MAX( control->hbond_cut, control->bond_cut );
    }
    else {
      local = 0;
      cutoff = control->bond_cut;
    }

    ihb = -1;
    ihb_top = -1;
    if( local && control->hbond_cut > 0 ) {
      ihb = sbp_i->p_hbond;
      if( ihb == 1 )
        ihb_top = End_Index( atom_i->Hindex, hbonds );
      else ihb_top = -1;
    }

    /* update i-j distance - check if j is within cutoff */
    for( pj = start_i; pj < end_i; ++pj ) {
      nbr_pj = &( far_nbrs->select.far_nbr_list[pj] );
      j = nbr_pj->nbr;
      atom_j = &(system->my_atoms[j]);

      if( renbr ) {
        if( nbr_pj->d <= cutoff )
          flag = 1;
        else flag = 0;
      }
      else{
        nbr_pj->dvec[0] = atom_j->x[0] - atom_i->x[0];
        nbr_pj->dvec[1] = atom_j->x[1] - atom_i->x[1];
        nbr_pj->dvec[2] = atom_j->x[2] - atom_i->x[2];
        nbr_pj->d = rvec_Norm_Sqr( nbr_pj->dvec );
        if( nbr_pj->d <= SQR(cutoff) ) {
          nbr_pj->d = sqrt(nbr_pj->d);
          flag = 1;
        }
        else {
          flag = 0;
        }
      }

      if( flag ) {
        type_j = atom_j->type;
	if (type_j < 0) continue;
        sbp_j = &(system->reax_param.sbp[type_j]);
        twbp = &(system->reax_param.tbp[type_i][type_j]);

        if( local ) {
          /* hydrogen bond lists */
          if( control->hbond_cut > 0 && (ihb==1 || ihb==2) &&
              nbr_pj->d <= control->hbond_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( j < system->n && ihb == 2 && jhb == 1 ) {
              jhb_top = End_Index( atom_j->Hindex, 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( atom_j->Hindex, jhb_top+1, hbonds );
              ++num_hbonds;
            }
          }
        }

        if( //(workspace->bond_mark[i] < 3 || workspace->bond_mark[j] < 3) &&
            nbr_pj->d <= control->bond_cut &&
            BOp( workspace, bonds, control->bo_cut,
                 i , btop_i, nbr_pj, sbp_i, sbp_j, twbp ) ) {
          num_bonds += 2;
          ++btop_i;

          if( workspace->bond_mark[j] > workspace->bond_mark[i] + 1 )
            workspace->bond_mark[j] = workspace->bond_mark[i] + 1;
          else if( workspace->bond_mark[i] > workspace->bond_mark[j] + 1 ) {
            workspace->bond_mark[i] = workspace->bond_mark[j] + 1;
          }
        }
      }
    }

    Set_End_Index( i, btop_i, bonds );
    if( local && ihb == 1 )
      Set_End_Index( atom_i->Hindex, ihb_top, hbonds );
  }


  workspace->realloc.num_bonds = num_bonds;
  workspace->realloc.num_hbonds = num_hbonds;

  Validate_Lists( system, workspace, lists, data->step,
                  system->n, system->N, system->numH, comm );
}
Exemple #6
0
void Init_Forces( reax_system *system, control_params *control,
                  simulation_data *data, storage *workspace, reax_list **lists,
                  output_controls *out_control, MPI_Comm comm ) {
  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 local, flag, renbr;
  real r_ij, cutoff;
  sparse_matrix *H;
  reax_list *far_nbrs, *bonds, *hbonds;
  single_body_parameters *sbp_i, *sbp_j;
  two_body_parameters *twbp;
  far_neighbor_data *nbr_pj;
  reax_atom *atom_i, *atom_j;

  far_nbrs = *lists + FAR_NBRS;
  bonds = *lists + BONDS;
  hbonds = *lists + HBONDS;

  for( i = 0; i < system->n; ++i )
    workspace->bond_mark[i] = 0;
  for( i = system->n; i < system->N; ++i ) {
    workspace->bond_mark[i] = 1000; // put ghost atoms to an infinite distance
    //workspace->done_after[i] = Start_Index( i, far_nbrs );
  }

  H = workspace->H;
  H->n = system->n;
  Htop = 0;
  num_bonds = 0;
  num_hbonds = 0;
  btop_i = btop_j = 0;
  renbr = (data->step-data->prev_steps) % control->reneighbor == 0;

  for( i = 0; i < system->N; ++i ) {
    atom_i = &(system->my_atoms[i]);
    type_i  = atom_i->type;
    start_i = Start_Index(i, far_nbrs);
    end_i   = End_Index(i, far_nbrs);
    btop_i = End_Index( i, bonds );
    sbp_i = &(system->reax_param.sbp[type_i]);

    if( i < system->n ) {
      local = 1;
      cutoff = control->nonb_cut;
    }
    else {
      local = 0;
      cutoff = control->bond_cut;
    }

    ihb = -1;
    ihb_top = -1;
    if( local ) {
      H->start[i] = Htop;
      H->entries[Htop].j = i;
      H->entries[Htop].val = sbp_i->eta;
      ++Htop;

      if( control->hbond_cut > 0 ) {
        ihb = sbp_i->p_hbond;
        if( ihb == 1 )
          ihb_top = End_Index( atom_i->Hindex, hbonds );
        else ihb_top = -1;
      }
    }

    /* update i-j distance - check if j is within cutoff */
    for( pj = start_i; pj < end_i; ++pj ) {
      nbr_pj = &( far_nbrs->select.far_nbr_list[pj] );
      j = nbr_pj->nbr;
      atom_j = &(system->my_atoms[j]);
      //fprintf( stderr, "%d%d i=%d x_i: %f %f %f,j=%d x_j: %f %f %f, d=%f\n",
      //         MIN(atom_i->orig_id, atom_j->orig_id),
      //         MAX(atom_i->orig_id, atom_j->orig_id),
      //         i, atom_i->x[0], atom_i->x[1], atom_i->x[2],
      //         j, atom_j->x[0], atom_j->x[1], atom_j->x[2], nbr_pj->d );
      if( renbr ) {
        if(nbr_pj->d <= cutoff)
          flag = 1;
        else flag = 0;
      }
      else{
        nbr_pj->dvec[0] = atom_j->x[0] - atom_i->x[0];
        nbr_pj->dvec[1] = atom_j->x[1] - atom_i->x[1];
        nbr_pj->dvec[2] = atom_j->x[2] - atom_i->x[2];
        nbr_pj->d = rvec_Norm_Sqr( nbr_pj->dvec );
        if( nbr_pj->d <= SQR(cutoff) ) {
          nbr_pj->d = sqrt(nbr_pj->d);
          flag = 1;
        }
        else {
          flag = 0;
        }
      }

      if( flag ){
        type_j = atom_j->type;
        r_ij = nbr_pj->d;
        sbp_j = &(system->reax_param.sbp[type_j]);
        twbp = &(system->reax_param.tbp[type_i][type_j]);

        if( local ) {
          /* H matrix entry */
          if( j < system->n || atom_i->orig_id < atom_j->orig_id ) {//tryQEq||1
            H->entries[Htop].j = j;
            //fprintf( stdout, "%d%d %d %d\n",
            //     MIN(atom_i->orig_id, atom_j->orig_id),
            //     MAX(atom_i->orig_id, atom_j->orig_id),
            //     MIN(atom_i->orig_id, atom_j->orig_id),
            //     MAX(atom_i->orig_id, atom_j->orig_id) );
            if( control->tabulate == 0 )
              H->entries[Htop].val = Compute_H(r_ij,twbp->gamma,workspace->Tap);
            else H->entries[Htop].val = Compute_tabH(r_ij, type_i, type_j);
            ++Htop;
          }

          /* hydrogen bond lists */
          if( control->hbond_cut > 0 && (ihb==1 || ihb==2) &&
              nbr_pj->d <= control->hbond_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( j < system->n && ihb == 2 && jhb == 1 ) {
              jhb_top = End_Index( atom_j->Hindex, 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( atom_j->Hindex, jhb_top+1, hbonds );
              ++num_hbonds;
            }
          }
        }

        /* uncorrected bond orders */
        if( //(workspace->bond_mark[i] < 3 || workspace->bond_mark[j] < 3) &&
            nbr_pj->d <= control->bond_cut &&
            BOp( workspace, bonds, control->bo_cut,
                 i , btop_i, nbr_pj, sbp_i, sbp_j, twbp ) ) {
          num_bonds += 2;
          ++btop_i;

          if( workspace->bond_mark[j] > workspace->bond_mark[i] + 1 )
            workspace->bond_mark[j] = workspace->bond_mark[i] + 1;
          else if( workspace->bond_mark[i] > workspace->bond_mark[j] + 1 ) {
            workspace->bond_mark[i] = workspace->bond_mark[j] + 1;
            //if( workspace->bond_mark[i] == 1000 )
            //  workspace->done_after[i] = pj;
          }
          //fprintf( stdout, "%d%d - %d(%d) %d(%d)\n",
          //   i , j, i, workspace->bond_mark[i], j, workspace->bond_mark[j] );
        }
      }
    }

    Set_End_Index( i, btop_i, bonds );
    if( local ) {
      H->end[i] = Htop;
      if( ihb == 1 )
        Set_End_Index( atom_i->Hindex, ihb_top, hbonds );
    }
  }

  //fprintf( stderr, "after the first init loop\n" );
  /*for( i = system->n; i < system->N; ++i )
    if( workspace->bond_mark[i] > 3 ) {
      start_i = Start_Index(i, bonds);
      end_i = End_Index(i, bonds);
      num_bonds -= (end_i - start_i);
      Set_End_Index(i, start_i, bonds );
      }*/

  /*for( i = system->n; i < system->N; ++i ) {
    start_i = Start_Index(i, far_nbrs);
    end_i = workspace->done_after[i];

    if( workspace->bond_mark[i] >= 2 && start_i < end_i ) {
      atom_i = &(system->my_atoms[i]);
      type_i = atom_i->type;
      btop_i = End_Index( i, bonds );
      sbp_i = &(system->reax_param.sbp[type_i]);

      for( pj = start_i; pj < end_i; ++pj ) {
        nbr_pj = &( far_nbrs->select.far_nbr_list[pj] );
        j = nbr_pj->nbr;

        if( workspace->bond_mark[j] >= 2 && nbr_pj->d <= control->bond_cut ) {
          atom_j = &(system->my_atoms[j]);
          type_j = atom_j->type;
          sbp_j = &(system->reax_param.sbp[type_j]);
          twbp = &(system->reax_param.tbp[type_i][type_j]);

          if( BOp( workspace, bonds, control->bo_cut,
                   i , btop_i, nbr_pj, sbp_i, sbp_j, twbp ) ) {
            num_bonds += 2;
            ++btop_i;

            if( workspace->bond_mark[j] > workspace->bond_mark[i] + 1 )
              workspace->bond_mark[j] = workspace->bond_mark[i] + 1;
            else if( workspace->bond_mark[i] > workspace->bond_mark[j] + 1 )
              workspace->bond_mark[i] = workspace->bond_mark[j] + 1;

            //fprintf( stdout, "%d%d - %d(%d) %d(%d) new\n",
            // i , j, i, workspace->bond_mark[i], j, workspace->bond_mark[j] );
          }
        }
      }
      Set_End_Index( i, btop_i, bonds );
    }
    }*/

  workspace->realloc.Htop = Htop;
  workspace->realloc.num_bonds = num_bonds;
  workspace->realloc.num_hbonds = num_hbonds;

#if defined(DEBUG_FOCUS)
  fprintf( stderr, "p%d @ step%d: Htop = %d num_bonds = %d num_hbonds = %d\n",
           system->my_rank, data->step, Htop, num_bonds, num_hbonds );
  MPI_Barrier( comm );
#endif
#if defined( DEBUG )
  Print_Bonds( system, bonds, "debugbonds.out" );
  Print_Bond_List2( system, bonds, "pbonds.out" );
  Print_Sparse_Matrix( system, H );
  for( i = 0; i < H->n; ++i )
    for( j = H->start[i]; j < H->end[i]; ++j )
      fprintf( stderr, "%d %d %.15e\n",
               MIN(system->my_atoms[i].orig_id,
                   system->my_atoms[H->entries[j].j].orig_id),
               MAX(system->my_atoms[i].orig_id,
                   system->my_atoms[H->entries[j].j].orig_id),
               H->entries[j].val );
#endif

  Validate_Lists( system, workspace, lists, data->step,
                  system->n, system->N, system->numH, comm );
}
void Valence_Angles( reax_system *system, control_params *control,
                     simulation_data *data, storage *workspace,
                     reax_list **lists, output_controls *out_control )
{
  int i, j, pi, k, pk, t;
  int type_i, type_j, type_k;
  int start_j, end_j, start_pk, end_pk;
  int cnt, num_thb_intrs;

  double temp, temp_bo_jt, pBOjt7;
  double p_val1, p_val2, p_val3, p_val4, p_val5;
  double p_val6, p_val7, p_val8, p_val9, p_val10;
  double p_pen1, p_pen2, p_pen3, p_pen4;
  double p_coa1, p_coa2, p_coa3, p_coa4;
  double trm8, expval6, expval7, expval2theta, expval12theta, exp3ij, exp3jk;
  double exp_pen2ij, exp_pen2jk, exp_pen3, exp_pen4, trm_pen34, exp_coa2;
  double dSBO1, dSBO2, SBO, SBO2, CSBO2, SBOp, prod_SBO, vlpadj;
  double CEval1, CEval2, CEval3, CEval4, CEval5, CEval6, CEval7, CEval8;
  double CEpen1, CEpen2, CEpen3;
  double e_ang, e_coa, e_pen;
  double CEcoa1, CEcoa2, CEcoa3, CEcoa4, CEcoa5;
  double Cf7ij, Cf7jk, Cf8j, Cf9j;
  double f7_ij, f7_jk, f8_Dj, f9_Dj;
  double Ctheta_0, theta_0, theta_00, theta, cos_theta, sin_theta;
  double BOA_ij, BOA_jk;
  rvec force, ext_press;

  // Tallying variables
  double eng_tmp, fi_tmp[3], fj_tmp[3], fk_tmp[3];
  double delij[3], delkj[3];

  three_body_header *thbh;
  three_body_parameters *thbp;
  three_body_interaction_data *p_ijk, *p_kji;
  bond_data *pbond_ij, *pbond_jk, *pbond_jt;
  bond_order_data *bo_ij, *bo_jk, *bo_jt;
  reax_list *bonds = (*lists) + BONDS;
  reax_list *thb_intrs =  (*lists) + THREE_BODIES;

  /* global parameters used in these calculations */
  p_val6 = system->reax_param.gp.l[14];
  p_val8 = system->reax_param.gp.l[33];
  p_val9 = system->reax_param.gp.l[16];
  p_val10 = system->reax_param.gp.l[17];
  num_thb_intrs = 0;


  for( j = 0; j < system->N; ++j ) {         // Ray: the first one with system->N
    type_j = system->my_atoms[j].type;
    if (type_j < 0) continue;
    start_j = Start_Index(j, bonds);
    end_j = End_Index(j, bonds);

    p_val3 = system->reax_param.sbp[ type_j ].p_val3;
    p_val5 = system->reax_param.sbp[ type_j ].p_val5;

    SBOp = 0, prod_SBO = 1;
    for( t = start_j; t < end_j; ++t ) {
      bo_jt = &(bonds->select.bond_list[t].bo_data);
      SBOp += (bo_jt->BO_pi + bo_jt->BO_pi2);
      temp = SQR( bo_jt->BO );
      temp *= temp;
      temp *= temp;
      prod_SBO *= exp( -temp );
    }

    if( workspace->vlpex[j] >= 0 ){
      vlpadj = 0;
      dSBO2 = prod_SBO - 1;
    }
    else{
      vlpadj = workspace->nlp[j];
      dSBO2 = (prod_SBO - 1) * (1 - p_val8 * workspace->dDelta_lp[j]);
    }

    SBO = SBOp + (1 - prod_SBO) * (-workspace->Delta_boc[j] - p_val8 * vlpadj);
    dSBO1 = -8 * prod_SBO * ( workspace->Delta_boc[j] + p_val8 * vlpadj );

    if( SBO <= 0 )
      SBO2 = 0, CSBO2 = 0;
    else if( SBO > 0 && SBO <= 1 ) {
        SBO2 = pow( SBO, p_val9 );
        CSBO2 = p_val9 * pow( SBO, p_val9 - 1 );
    }
    else if( SBO > 1 && SBO < 2 ) {
      SBO2 = 2 - pow( 2-SBO, p_val9 );
      CSBO2 = p_val9 * pow( 2 - SBO, p_val9 - 1 );
    }
    else
      SBO2 = 2, CSBO2 = 0;

    expval6 = exp( p_val6 * workspace->Delta_boc[j] );

    for( pi = start_j; pi < end_j; ++pi ) {
      Set_Start_Index( pi, num_thb_intrs, thb_intrs );
      pbond_ij = &(bonds->select.bond_list[pi]);
      bo_ij = &(pbond_ij->bo_data);
      BOA_ij = bo_ij->BO - control->thb_cut;


      if( BOA_ij/*bo_ij->BO*/ > 0.0 &&
          ( j < system->n || pbond_ij->nbr < system->n ) ) {
        i = pbond_ij->nbr;
        type_i = system->my_atoms[i].type;

        for( pk = start_j; pk < pi; ++pk ) {
          start_pk = Start_Index( pk, thb_intrs );
          end_pk = End_Index( pk, thb_intrs );

          for( t = start_pk; t < end_pk; ++t )
            if( thb_intrs->select.three_body_list[t].thb == i ) {
              p_ijk = &(thb_intrs->select.three_body_list[num_thb_intrs] );
              p_kji = &(thb_intrs->select.three_body_list[t]);

              p_ijk->thb = bonds->select.bond_list[pk].nbr;
              p_ijk->pthb  = pk;
              p_ijk->theta = p_kji->theta;
              rvec_Copy( p_ijk->dcos_di, p_kji->dcos_dk );
              rvec_Copy( p_ijk->dcos_dj, p_kji->dcos_dj );
              rvec_Copy( p_ijk->dcos_dk, p_kji->dcos_di );

              ++num_thb_intrs;
              break;
            }
        }

        for( pk = pi+1; pk < end_j; ++pk ) {
          pbond_jk = &(bonds->select.bond_list[pk]);
          bo_jk    = &(pbond_jk->bo_data);
          BOA_jk   = bo_jk->BO - control->thb_cut;
          k        = pbond_jk->nbr;
          type_k   = system->my_atoms[k].type;
          p_ijk    = &( thb_intrs->select.three_body_list[num_thb_intrs] );

          Calculate_Theta( pbond_ij->dvec, pbond_ij->d,
                           pbond_jk->dvec, pbond_jk->d,
                           &theta, &cos_theta );

          Calculate_dCos_Theta( pbond_ij->dvec, pbond_ij->d,
                                pbond_jk->dvec, pbond_jk->d,
                                &(p_ijk->dcos_di), &(p_ijk->dcos_dj),
                                &(p_ijk->dcos_dk) );
          p_ijk->thb = k;
          p_ijk->pthb = pk;
          p_ijk->theta = theta;

          sin_theta = sin( theta );
          if( sin_theta < 1.0e-5 )
            sin_theta = 1.0e-5;

          ++num_thb_intrs;


          if( (j < system->n) && (BOA_jk > 0.0) &&
              (bo_ij->BO > control->thb_cut) &&
              (bo_jk->BO > control->thb_cut) &&
              (bo_ij->BO * bo_jk->BO > control->thb_cutsq) ) {
            thbh = &( system->reax_param.thbp[ type_i ][ type_j ][ type_k ] );

            for( cnt = 0; cnt < thbh->cnt; ++cnt ) {
              if( fabs(thbh->prm[cnt].p_val1) > 0.001 ) {
                thbp = &( thbh->prm[cnt] );

                /* ANGLE ENERGY */
                p_val1 = thbp->p_val1;
                p_val2 = thbp->p_val2;
                p_val4 = thbp->p_val4;
                p_val7 = thbp->p_val7;
                theta_00 = thbp->theta_00;

                exp3ij = exp( -p_val3 * pow( BOA_ij, p_val4 ) );
                f7_ij = 1.0 - exp3ij;
                Cf7ij = p_val3 * p_val4 * pow( BOA_ij, p_val4 - 1.0 ) * exp3ij;

                exp3jk = exp( -p_val3 * pow( BOA_jk, p_val4 ) );
                f7_jk = 1.0 - exp3jk;
                Cf7jk = p_val3 * p_val4 * pow( BOA_jk, p_val4 - 1.0 ) * exp3jk;

                expval7 = exp( -p_val7 * workspace->Delta_boc[j] );
                trm8 = 1.0 + expval6 + expval7;
                f8_Dj = p_val5 - ( (p_val5 - 1.0) * (2.0 + expval6) / trm8 );
                Cf8j = ( (1.0 - p_val5) / SQR(trm8) ) *
                  ( p_val6 * expval6 * trm8 -
                    (2.0 + expval6) * ( p_val6*expval6 - p_val7*expval7 ) );

                theta_0 = 180.0 - theta_00 * (1.0 -
                                              exp(-p_val10 * (2.0 - SBO2)));
                theta_0 = DEG2RAD( theta_0 );

                expval2theta  = exp( -p_val2 * SQR(theta_0 - theta) );
                if( p_val1 >= 0 )
                  expval12theta = p_val1 * (1.0 - expval2theta);
                else // To avoid linear Me-H-Me angles (6/6/06)
                  expval12theta = p_val1 * -expval2theta;

                CEval1 = Cf7ij * f7_jk * f8_Dj * expval12theta;
                CEval2 = Cf7jk * f7_ij * f8_Dj * expval12theta;
                CEval3 = Cf8j  * f7_ij * f7_jk * expval12theta;
                CEval4 = -2.0 * p_val1 * p_val2 * f7_ij * f7_jk * f8_Dj *
                  expval2theta * (theta_0 - theta);

                Ctheta_0 = p_val10 * DEG2RAD(theta_00) *
                  exp( -p_val10 * (2.0 - SBO2) );

                CEval5 = -CEval4 * Ctheta_0 * CSBO2;
                CEval6 = CEval5 * dSBO1;
                CEval7 = CEval5 * dSBO2;
                CEval8 = -CEval4 / sin_theta;

                data->my_en.e_ang += e_ang =
                  f7_ij * f7_jk * f8_Dj * expval12theta;
                /* END ANGLE ENERGY*/

                /* PENALTY ENERGY */
                p_pen1 = thbp->p_pen1;
                p_pen2 = system->reax_param.gp.l[19];
                p_pen3 = system->reax_param.gp.l[20];
                p_pen4 = system->reax_param.gp.l[21];

                exp_pen2ij = exp( -p_pen2 * SQR( BOA_ij - 2.0 ) );
                exp_pen2jk = exp( -p_pen2 * SQR( BOA_jk - 2.0 ) );
                exp_pen3 = exp( -p_pen3 * workspace->Delta[j] );
                exp_pen4 = exp(  p_pen4 * workspace->Delta[j] );
                trm_pen34 = 1.0 + exp_pen3 + exp_pen4;
                f9_Dj = ( 2.0 + exp_pen3 ) / trm_pen34;
                Cf9j = ( -p_pen3 * exp_pen3 * trm_pen34 -
                         (2.0 + exp_pen3) * ( -p_pen3 * exp_pen3 +
                                              p_pen4 * exp_pen4 ) ) /
                  SQR( trm_pen34 );

                data->my_en.e_pen += e_pen =
                  p_pen1 * f9_Dj * exp_pen2ij * exp_pen2jk;

                CEpen1 = e_pen * Cf9j / f9_Dj;
                temp   = -2.0 * p_pen2 * e_pen;
                CEpen2 = temp * (BOA_ij - 2.0);
                CEpen3 = temp * (BOA_jk - 2.0);
                /* END PENALTY ENERGY */

                /* COALITION ENERGY */
                p_coa1 = thbp->p_coa1;
                p_coa2 = system->reax_param.gp.l[2];
                p_coa3 = system->reax_param.gp.l[38];
                p_coa4 = system->reax_param.gp.l[30];

                exp_coa2 = exp( p_coa2 * workspace->Delta_val[j] );
                data->my_en.e_coa += e_coa =
                  p_coa1 / (1. + exp_coa2) *
                  exp( -p_coa3 * SQR(workspace->total_bond_order[i]-BOA_ij) ) *
                  exp( -p_coa3 * SQR(workspace->total_bond_order[k]-BOA_jk) ) *
                  exp( -p_coa4 * SQR(BOA_ij - 1.5) ) *
                  exp( -p_coa4 * SQR(BOA_jk - 1.5) );

                CEcoa1 = -2 * p_coa4 * (BOA_ij - 1.5) * e_coa;
                CEcoa2 = -2 * p_coa4 * (BOA_jk - 1.5) * e_coa;
                CEcoa3 = -p_coa2 * exp_coa2 * e_coa / (1 + exp_coa2);
                CEcoa4 = -2 * p_coa3 *
                  (workspace->total_bond_order[i]-BOA_ij) * e_coa;
                CEcoa5 = -2 * p_coa3 *
                  (workspace->total_bond_order[k]-BOA_jk) * e_coa;
                /* END COALITION ENERGY */

                /* FORCES */
                bo_ij->Cdbo += (CEval1 + CEpen2 + (CEcoa1 - CEcoa4));
                bo_jk->Cdbo += (CEval2 + CEpen3 + (CEcoa2 - CEcoa5));
                workspace->CdDelta[j] += ((CEval3 + CEval7) + CEpen1 + CEcoa3);
                workspace->CdDelta[i] += CEcoa4;
                workspace->CdDelta[k] += CEcoa5;

                for( t = start_j; t < end_j; ++t ) {
                    pbond_jt = &( bonds->select.bond_list[t] );
                    bo_jt = &(pbond_jt->bo_data);
                    temp_bo_jt = bo_jt->BO;
                    temp = CUBE( temp_bo_jt );
                    pBOjt7 = temp * temp * temp_bo_jt;

                    bo_jt->Cdbo += (CEval6 * pBOjt7);
                    bo_jt->Cdbopi += CEval5;
                    bo_jt->Cdbopi2 += CEval5;
                }

                if( control->virial == 0 ) {
                  rvec_ScaledAdd( workspace->f[i], CEval8, p_ijk->dcos_di );
                  rvec_ScaledAdd( workspace->f[j], CEval8, p_ijk->dcos_dj );
                  rvec_ScaledAdd( workspace->f[k], CEval8, p_ijk->dcos_dk );
                }
                else {
                  rvec_Scale( force, CEval8, p_ijk->dcos_di );
                  rvec_Add( workspace->f[i], force );
                  rvec_iMultiply( ext_press, pbond_ij->rel_box, force );
                  rvec_Add( data->my_ext_press, ext_press );

                  rvec_ScaledAdd( workspace->f[j], CEval8, p_ijk->dcos_dj );

                  rvec_Scale( force, CEval8, p_ijk->dcos_dk );
                  rvec_Add( workspace->f[k], force );
                  rvec_iMultiply( ext_press, pbond_jk->rel_box, force );
                  rvec_Add( data->my_ext_press, ext_press );
                }

                /* tally into per-atom virials */
                if( system->pair_ptr->vflag_atom || system->pair_ptr->evflag) {

                  /* Acquire vectors */
                  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, -CEval8, p_ijk->dcos_di );
                  rvec_Scale( fj_tmp, -CEval8, p_ijk->dcos_dj );
                  rvec_Scale( fk_tmp, -CEval8, p_ijk->dcos_dk );

                  eng_tmp = e_ang + e_pen + e_coa;

                  if( system->pair_ptr->evflag)
                          system->pair_ptr->ev_tally(j,j,system->N,1,eng_tmp,0.0,0.0,0.0,0.0,0.0);
                  if( system->pair_ptr->vflag_atom)
                          system->pair_ptr->v_tally3(i,j,k,fi_tmp,fk_tmp,delij,delkj);
                }
              }
            }
          }
        }
      }

      Set_End_Index(pi, num_thb_intrs, thb_intrs );
    }
  }

  if( num_thb_intrs >= thb_intrs->num_intrs * DANGER_ZONE ) {
    workspace->realloc.num_3body = num_thb_intrs;
    if( num_thb_intrs > thb_intrs->num_intrs ) {
      fprintf( stderr, "step%d-ran out of space on angle_list: top=%d, max=%d",
               data->step, num_thb_intrs, thb_intrs->num_intrs );
      MPI_Abort( MPI_COMM_WORLD, INSUFFICIENT_MEMORY );
    }
  }

}
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;
}