From 5a23342934b350bd88de7d335b40c1bb3c7427d2 Mon Sep 17 00:00:00 2001 From: Trung Nguyen <ndactrung@gmail.com> Date: Sat, 26 May 2018 00:39:55 -0500 Subject: [PATCH] Refactored pair body rounded/polyhedron so that other kernel force models can be implemented in the future --- src/BODY/pair_body_rounded_polyhedron.cpp | 545 ++++++++++++---------- src/BODY/pair_body_rounded_polyhedron.h | 39 +- 2 files changed, 318 insertions(+), 266 deletions(-) diff --git a/src/BODY/pair_body_rounded_polyhedron.cpp b/src/BODY/pair_body_rounded_polyhedron.cpp index 02c2abe1e3..42c107d68e 100644 --- a/src/BODY/pair_body_rounded_polyhedron.cpp +++ b/src/BODY/pair_body_rounded_polyhedron.cpp @@ -610,10 +610,10 @@ void PairBodyRoundedPolyhedron::sphere_against_sphere(int ibody, int jbody, rij = sqrt(rsq); R = rij - contact_dist; - shift = k_na * cut_inner; energy = 0; - + kernel_force(R, k_n, k_na, energy, fpair); +/* if (R <= 0) { // deformation occurs fpair = -k_n * R - shift; energy = (0.5 * k_n * R + shift) * R; @@ -621,6 +621,7 @@ void PairBodyRoundedPolyhedron::sphere_against_sphere(int ibody, int jbody, fpair = k_na * R - shift; energy = (-0.5 * k_na * R + shift) * R; } else fpair = 0.0; +*/ fx = delx*fpair/rij; fy = dely*fpair/rij; @@ -681,17 +682,17 @@ void PairBodyRoundedPolyhedron::sphere_against_sphere(int ibody, int jbody, } /* ---------------------------------------------------------------------- - Interaction bt the faces of a polyhedron (ibody) and a sphere (jbody) + Interaction bt the edges of a polyhedron (ibody) and a sphere (jbody) ---------------------------------------------------------------------- */ -void PairBodyRoundedPolyhedron::sphere_against_face(int ibody, int jbody, +void PairBodyRoundedPolyhedron::sphere_against_edge(int ibody, int jbody, double k_n, double k_na, double** x, double** v, double** f, double** torque, double** angmom, int evflag) { - int ni,nfi,inside,ifirst,iffirst,npi1,npi2,npi3,ibonus,tmp; - double xi1[3],xi2[3],xi3[3],ui[3],vi[3],vti[3],n[3],h[3],fn[3],ft[3],d; - double delx,dely,delz,rsq,rij,rsqinv,R,fx,fy,fz,fpair,shift,energy; + int ni,nei,ifirst,iefirst,npi1,npi2,ibonus; + double xi1[3],xi2[3],vti[3],h[3],fn[3],ft[3],d,t; + double delx,dely,delz,rij,rsqinv,R,fx,fy,fz,fpair,shift,energy; double rradi,rradj,contact_dist; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; double *quat, *inertia; @@ -701,18 +702,17 @@ void PairBodyRoundedPolyhedron::sphere_against_face(int ibody, int jbody, int newton_pair = force->newton_pair; ifirst = dfirst[ibody]; - iffirst = facfirst[ibody]; - nfi = facnum[ibody]; + iefirst = edfirst[ibody]; + nei = ednum[ibody]; rradi = rounded_radius[ibody]; rradj = rounded_radius[jbody]; contact_dist = rradi + rradj; - for (ni = 0; ni < nfi; ni++) { + for (ni = 0; ni < nei; ni++) { - npi1 = static_cast<int>(face[iffirst+ni][0]); - npi2 = static_cast<int>(face[iffirst+ni][1]); - npi3 = static_cast<int>(face[iffirst+ni][2]); + npi1 = static_cast<int>(edge[iefirst+ni][0]); + npi2 = static_cast<int>(edge[iefirst+ni][1]); // compute the space-fixed coordinates for the vertices of the face @@ -724,45 +724,53 @@ void PairBodyRoundedPolyhedron::sphere_against_face(int ibody, int jbody, xi2[1] = x[ibody][1] + discrete[ifirst+npi2][1]; xi2[2] = x[ibody][2] + discrete[ifirst+npi2][2]; - xi3[0] = x[ibody][0] + discrete[ifirst+npi3][0]; - xi3[1] = x[ibody][1] + discrete[ifirst+npi3][1]; - xi3[2] = x[ibody][2] + discrete[ifirst+npi3][2]; - - // find the normal unit vector of the face - - MathExtra::sub3(xi2, xi1, ui); - MathExtra::sub3(xi3, xi1, vi); - MathExtra::cross3(ui, vi, n); - MathExtra::norm3(n); - - // skip if the COM of the two bodies are in the same side of the face + // find the projection of the jbody's COM on the edge - if (opposite_sides(n, xi1, x[ibody], x[jbody]) == 0) continue; + project_pt_line(x[jbody], xi1, xi2, h, d, t); - // find the projection of the sphere on the face + if (d > contact_dist + cut_inner) continue; + if (t < 0 || t > 1) continue; - project_pt_plane(x[jbody], xi1, xi2, xi3, h, d, inside); + if (fabs(t) < EPSILON) { + if (static_cast<int>(discrete[ifirst+npi1][6]) == 1) + continue; + else { + h[0] = xi1[0]; + h[1] = xi1[1]; + h[2] = xi1[2]; + discrete[ifirst+npi1][6] = 1; + } + } - inside_polygon(ibody, ni, x[ibody], h, NULL, inside, tmp); - if (inside == 0) continue; + if (fabs(t-1) < EPSILON) { + if (static_cast<int>(discrete[ifirst+npi2][6]) == 1) + continue; + else { + h[0] = xi2[0]; + h[1] = xi2[1]; + h[2] = xi2[2]; + discrete[ifirst+npi2][6] = 1; + } + } delx = h[0] - x[jbody][0]; dely = h[1] - x[jbody][1]; delz = h[2] - x[jbody][2]; - rsq = delx*delx + dely*dely + delz*delz; - rij = sqrt(rsq); + rij = sqrt(delx*delx + dely*dely + delz*delz); R = rij - contact_dist; - shift = k_na * cut_inner; energy = 0; - - if (R <= 0) { // deformation occurs + kernel_force(R, k_n, k_na, energy, fpair); +/* + if (R <= 0) { // deformation occurs fpair = -k_n * R - shift; energy = (0.5 * k_n * R + shift) * R; - } else if (R <= cut_inner) { // not deforming but cohesive ranges overlap + } else if (R <= cut_inner) { // not deforming but cohesive ranges overlap fpair = k_na * R - shift; energy = (-0.5 * k_na * R + shift) * R; } else fpair = 0.0; +*/ + fx = delx*fpair/rij; fy = dely*fpair/rij; @@ -787,7 +795,6 @@ void PairBodyRoundedPolyhedron::sphere_against_face(int ibody, int jbody, // normal component - rsqinv = 1.0/rsq; vnnr = vr1*delx + vr2*dely + vr3*delz; vn1 = delx*vnnr * rsqinv; vn2 = dely*vnnr * rsqinv; @@ -805,8 +812,7 @@ void PairBodyRoundedPolyhedron::sphere_against_face(int ibody, int jbody, fn[1] = -c_n * vn2; fn[2] = -c_n * vn3; - // tangential friction term at contact, - // excluding the tangential deformation term for now + // tangential friction term at contact, excluding the tangential deformation term ft[0] = -c_t * vt1; ft[1] = -c_t * vt2; @@ -834,17 +840,17 @@ void PairBodyRoundedPolyhedron::sphere_against_face(int ibody, int jbody, } /* ---------------------------------------------------------------------- - Interaction bt the edges of a polyhedron (ibody) and a sphere (jbody) + Interaction bt the faces of a polyhedron (ibody) and a sphere (jbody) ---------------------------------------------------------------------- */ -void PairBodyRoundedPolyhedron::sphere_against_edge(int ibody, int jbody, +void PairBodyRoundedPolyhedron::sphere_against_face(int ibody, int jbody, double k_n, double k_na, double** x, double** v, double** f, double** torque, double** angmom, int evflag) { - int ni,nei,ifirst,iefirst,npi1,npi2,ibonus; - double xi1[3],xi2[3],vti[3],h[3],fn[3],ft[3],d,t; - double delx,dely,delz,rij,rsqinv,R,fx,fy,fz,fpair,shift,energy; + int ni,nfi,inside,ifirst,iffirst,npi1,npi2,npi3,ibonus,tmp; + double xi1[3],xi2[3],xi3[3],ui[3],vi[3],vti[3],n[3],h[3],fn[3],ft[3],d; + double delx,dely,delz,rsq,rij,rsqinv,R,fx,fy,fz,fpair,shift,energy; double rradi,rradj,contact_dist; double vr1,vr2,vr3,vnnr,vn1,vn2,vn3,vt1,vt2,vt3; double *quat, *inertia; @@ -854,17 +860,18 @@ void PairBodyRoundedPolyhedron::sphere_against_edge(int ibody, int jbody, int newton_pair = force->newton_pair; ifirst = dfirst[ibody]; - iefirst = edfirst[ibody]; - nei = ednum[ibody]; + iffirst = facfirst[ibody]; + nfi = facnum[ibody]; rradi = rounded_radius[ibody]; rradj = rounded_radius[jbody]; contact_dist = rradi + rradj; - for (ni = 0; ni < nei; ni++) { + for (ni = 0; ni < nfi; ni++) { - npi1 = static_cast<int>(edge[iefirst+ni][0]); - npi2 = static_cast<int>(edge[iefirst+ni][1]); + npi1 = static_cast<int>(face[iffirst+ni][0]); + npi2 = static_cast<int>(face[iffirst+ni][1]); + npi3 = static_cast<int>(face[iffirst+ni][2]); // compute the space-fixed coordinates for the vertices of the face @@ -876,51 +883,46 @@ void PairBodyRoundedPolyhedron::sphere_against_edge(int ibody, int jbody, xi2[1] = x[ibody][1] + discrete[ifirst+npi2][1]; xi2[2] = x[ibody][2] + discrete[ifirst+npi2][2]; - // find the projection of the jbody's COM on the edge + xi3[0] = x[ibody][0] + discrete[ifirst+npi3][0]; + xi3[1] = x[ibody][1] + discrete[ifirst+npi3][1]; + xi3[2] = x[ibody][2] + discrete[ifirst+npi3][2]; - project_pt_line(x[jbody], xi1, xi2, h, d, t); + // find the normal unit vector of the face + + MathExtra::sub3(xi2, xi1, ui); + MathExtra::sub3(xi3, xi1, vi); + MathExtra::cross3(ui, vi, n); + MathExtra::norm3(n); - if (d > contact_dist + cut_inner) continue; - if (t < 0 || t > 1) continue; + // skip if the COM of the two bodies are in the same side of the face - if (fabs(t) < EPSILON) { - if (static_cast<int>(discrete[ifirst+npi1][6]) == 1) - continue; - else { - h[0] = xi1[0]; - h[1] = xi1[1]; - h[2] = xi1[2]; - discrete[ifirst+npi1][6] = 1; - } - } + if (opposite_sides(n, xi1, x[ibody], x[jbody]) == 0) continue; - if (fabs(t-1) < EPSILON) { - if (static_cast<int>(discrete[ifirst+npi2][6]) == 1) - continue; - else { - h[0] = xi2[0]; - h[1] = xi2[1]; - h[2] = xi2[2]; - discrete[ifirst+npi2][6] = 1; - } - } + // find the projection of the sphere on the face + + project_pt_plane(x[jbody], xi1, xi2, xi3, h, d, inside); + + inside_polygon(ibody, ni, x[ibody], h, NULL, inside, tmp); + if (inside == 0) continue; delx = h[0] - x[jbody][0]; dely = h[1] - x[jbody][1]; delz = h[2] - x[jbody][2]; - rij = sqrt(delx*delx + dely*dely + delz*delz); + rsq = delx*delx + dely*dely + delz*delz; + rij = sqrt(rsq); R = rij - contact_dist; - shift = k_na * cut_inner; energy = 0; - - if (R <= 0) { // deformation occurs + kernel_force(R, k_n, k_na, energy, fpair); +/* + if (R <= 0) { // deformation occurs fpair = -k_n * R - shift; energy = (0.5 * k_n * R + shift) * R; - } else if (R <= cut_inner) { // not deforming but cohesive ranges overlap + } else if (R <= cut_inner) { // not deforming but cohesive ranges overlap fpair = k_na * R - shift; energy = (-0.5 * k_na * R + shift) * R; } else fpair = 0.0; +*/ fx = delx*fpair/rij; fy = dely*fpair/rij; @@ -945,6 +947,7 @@ void PairBodyRoundedPolyhedron::sphere_against_edge(int ibody, int jbody, // normal component + rsqinv = 1.0/rsq; vnnr = vr1*delx + vr2*dely + vr3*delz; vn1 = delx*vnnr * rsqinv; vn2 = dely*vnnr * rsqinv; @@ -962,7 +965,8 @@ void PairBodyRoundedPolyhedron::sphere_against_edge(int ibody, int jbody, fn[1] = -c_n * vn2; fn[2] = -c_n * vn3; - // tangential friction term at contact, excluding the tangential deformation term + // tangential friction term at contact, + // excluding the tangential deformation term for now ft[0] = -c_t * vt1; ft[1] = -c_t * vt2; @@ -987,11 +991,10 @@ void PairBodyRoundedPolyhedron::sphere_against_edge(int ibody, int jbody, if (evflag) ev_tally_xyz(ibody,jbody,nlocal,newton_pair, energy,0.0,fx,fy,fz,delx,dely,delz); } - } /* ---------------------------------------------------------------------- - Determine the interaction mode between i's edges against j's faces + Determine the interaction mode between i's edges against j's edges i = atom i (body i) j = atom j (body j) @@ -1000,46 +1003,44 @@ void PairBodyRoundedPolyhedron::sphere_against_edge(int ibody, int jbody, torque = atoms' torques tag = atoms' tags contact_list = list of contacts - num_contacts = number of contacts between i's edges and j's faces + num_contacts = number of contacts between i's edges and j's edges Return: ---------------------------------------------------------------------- */ -int PairBodyRoundedPolyhedron::edge_against_face(int ibody, int jbody, +int PairBodyRoundedPolyhedron::edge_against_edge(int ibody, int jbody, double k_n, double k_na, double** x, Contact* contact_list, int &num_contacts, double &evdwl, double* facc) { - int ni,nei,nj,nfj,contact,interact; + int ni,nei,nj,nej,contact,interact; double rradi,rradj,energy; nei = ednum[ibody]; rradi = rounded_radius[ibody]; - nfj = facnum[jbody]; + nej = ednum[jbody]; rradj = rounded_radius[jbody]; energy = 0; - interact = EF_NONE; + interact = EE_NONE; // loop through body i's edges for (ni = 0; ni < nei; ni++) { - // loop through body j's faces - - for (nj = 0; nj < nfj; nj++) { + for (nj = 0; nj < nej; nj++) { - // compute the distance between the face nj to the edge ni + // compute the distance between the edge nj to the edge ni #ifdef _POLYHEDRON_DEBUG - printf("Compute interaction between face %d of body %d with edge %d of body %d:\n", + printf("Compute interaction between edge %d of body %d with edge %d of body %d:\n", nj, jbody, ni, ibody); #endif - interact = interaction_face_to_edge(jbody, nj, x[jbody], rradj, - ibody, ni, x[ibody], rradi, + interact = interaction_edge_to_edge(ibody, ni, x[ibody], rradi, + jbody, nj, x[jbody], rradj, k_n, k_na, cut_inner, contact_list, num_contacts, energy, facc); - } + } } // end for looping through the edges of body i @@ -1049,7 +1050,7 @@ int PairBodyRoundedPolyhedron::edge_against_face(int ibody, int jbody, } /* ---------------------------------------------------------------------- - Determine the interaction mode between i's edges against j's edges + Determine the interaction mode between i's edges against j's faces i = atom i (body i) j = atom j (body j) @@ -1058,44 +1059,46 @@ int PairBodyRoundedPolyhedron::edge_against_face(int ibody, int jbody, torque = atoms' torques tag = atoms' tags contact_list = list of contacts - num_contacts = number of contacts between i's edges and j's edges + num_contacts = number of contacts between i's edges and j's faces Return: ---------------------------------------------------------------------- */ -int PairBodyRoundedPolyhedron::edge_against_edge(int ibody, int jbody, +int PairBodyRoundedPolyhedron::edge_against_face(int ibody, int jbody, double k_n, double k_na, double** x, Contact* contact_list, int &num_contacts, double &evdwl, double* facc) { - int ni,nei,nj,nej,contact,interact; + int ni,nei,nj,nfj,contact,interact; double rradi,rradj,energy; nei = ednum[ibody]; rradi = rounded_radius[ibody]; - nej = ednum[jbody]; + nfj = facnum[jbody]; rradj = rounded_radius[jbody]; energy = 0; - interact = EE_NONE; + interact = EF_NONE; // loop through body i's edges for (ni = 0; ni < nei; ni++) { - for (nj = 0; nj < nej; nj++) { + // loop through body j's faces - // compute the distance between the edge nj to the edge ni + for (nj = 0; nj < nfj; nj++) { + + // compute the distance between the face nj to the edge ni #ifdef _POLYHEDRON_DEBUG - printf("Compute interaction between edge %d of body %d with edge %d of body %d:\n", + printf("Compute interaction between face %d of body %d with edge %d of body %d:\n", nj, jbody, ni, ibody); #endif - interact = interaction_edge_to_edge(ibody, ni, x[ibody], rradi, - jbody, nj, x[jbody], rradj, + interact = interaction_face_to_edge(jbody, nj, x[jbody], rradj, + ibody, ni, x[ibody], rradi, k_n, k_na, cut_inner, contact_list, num_contacts, energy, facc); - } + } } // end for looping through the edges of body i @@ -1104,6 +1107,144 @@ int PairBodyRoundedPolyhedron::edge_against_edge(int ibody, int jbody, return interact; } +/* ------------------------------------------------------------------------- + Compute the distance between an edge of body i and an edge from + another body + Input: + ibody = body i (i.e. atom i) + face_index = face index of body i + xmi = atom i's coordinates (body i's center of mass) + rounded_radius_i = rounded radius of the body i + jbody = body i (i.e. atom j) + edge_index = coordinate of the tested edge from another body + xmj = atom j's coordinates (body j's center of mass) + rounded_radius_j = rounded radius of the body j + cut_inner = cutoff for vertex-vertex and vertex-edge interaction + Output: + d = Distance from a point x0 to an edge + hi = coordinates of the projection of x0 on the edge + + contact = 0 no contact between the queried edge and the face + 1 contact detected + return + INVALID if the face index is invalid + NONE if there is no interaction +------------------------------------------------------------------------- */ + +int PairBodyRoundedPolyhedron::interaction_edge_to_edge(int ibody, + int edge_index_i, + double *xmi, + double rounded_radius_i, + int jbody, + int edge_index_j, + double *xmj, + double rounded_radius_j, + double k_n, + double k_na, + double cut_inner, + Contact* contact_list, + int &num_contacts, + double &energy, + double* facc) +{ + int ifirst,iefirst,jfirst,jefirst,npi1,npi2,npj1,npj2,interact; + double xi1[3],xi2[3],xpj1[3],xpj2[3]; + double r,t1,t2,h1[3],h2[3]; + double contact_dist, shift; + + double** x = atom->x; + double** v = atom->v; + double** f = atom->f; + double** torque = atom->torque; + double** angmom = atom->angmom; + + ifirst = dfirst[ibody]; + iefirst = edfirst[ibody]; + npi1 = static_cast<int>(edge[iefirst+edge_index_i][0]); + npi2 = static_cast<int>(edge[iefirst+edge_index_i][1]); + + // compute the space-fixed coordinates for the edge ends + + xi1[0] = xmi[0] + discrete[ifirst+npi1][0]; + xi1[1] = xmi[1] + discrete[ifirst+npi1][1]; + xi1[2] = xmi[2] + discrete[ifirst+npi1][2]; + + xi2[0] = xmi[0] + discrete[ifirst+npi2][0]; + xi2[1] = xmi[1] + discrete[ifirst+npi2][1]; + xi2[2] = xmi[2] + discrete[ifirst+npi2][2]; + + // two ends of the edge from body j + + jfirst = dfirst[jbody]; + jefirst = edfirst[jbody]; + npj1 = static_cast<int>(edge[jefirst+edge_index_j][0]); + npj2 = static_cast<int>(edge[jefirst+edge_index_j][1]); + + xpj1[0] = xmj[0] + discrete[jfirst+npj1][0]; + xpj1[1] = xmj[1] + discrete[jfirst+npj1][1]; + xpj1[2] = xmj[2] + discrete[jfirst+npj1][2]; + + xpj2[0] = xmj[0] + discrete[jfirst+npj2][0]; + xpj2[1] = xmj[1] + discrete[jfirst+npj2][1]; + xpj2[2] = xmj[2] + discrete[jfirst+npj2][2]; + + contact_dist = rounded_radius_i + rounded_radius_j; + + int jflag = 1; + distance_bt_edges(xpj1, xpj2, xi1, xi2, h1, h2, t1, t2, r); + + #ifdef _POLYHEDRON_DEBUG + double ui[3],uj[3]; + MathExtra::sub3(xi1,xi2,ui); + MathExtra::norm3(ui); + MathExtra::sub3(xpj1,xpj2,uj); + MathExtra::norm3(uj); + double dot = MathExtra::dot3(ui, uj); + printf(" edge npi1 = %d (%f %f %f); npi2 = %d (%f %f %f) vs." + " edge npj1 = %d (%f %f %f); npj2 = %d (%f %f %f): " + "t1 = %f; t2 = %f; r = %f; dot = %f\n", + npi1, xi1[0], xi1[1], xi1[2], npi2, xi2[0], xi2[1], xi2[2], + npj1, xpj1[0], xpj1[1], xpj1[2], npj2, xpj2[0], xpj2[1], xpj2[2], + t1, t2, r, dot); + #endif + + interact = EE_NONE; + + // singularity case, ignore interactions + + if (r < EPSILON) return interact; + + // include the vertices for interactions + + if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1 && + r < contact_dist + cut_inner) { + pair_force_and_torque(jbody, ibody, h1, h2, r, contact_dist, + k_n, k_na, x, v, f, torque, angmom, + jflag, energy, facc); + + interact = EE_INTERACT; + if (r <= contact_dist) { + // store the contact info + contact_list[num_contacts].ibody = ibody; + contact_list[num_contacts].jbody = jbody; + contact_list[num_contacts].xi[0] = h2[0]; + contact_list[num_contacts].xi[1] = h2[1]; + contact_list[num_contacts].xi[2] = h2[2]; + contact_list[num_contacts].xj[0] = h1[0]; + contact_list[num_contacts].xj[1] = h1[1]; + contact_list[num_contacts].xj[2] = h1[2]; + contact_list[num_contacts].type = 1; + contact_list[num_contacts].separation = r - contact_dist; + contact_list[num_contacts].unique = 1; + num_contacts++; + } + } else { + + } + + return interact; +} + /* ------------------------------------------------------------------------- Compute the interaction between a face of body i and an edge from another body @@ -1225,7 +1366,6 @@ int PairBodyRoundedPolyhedron::interaction_face_to_edge(int ibody, inside_polygon(ibody, face_index, xmi, hi1, hi2, inside1, inside2); contact_dist = rounded_radius_i + rounded_radius_j; - shift = k_na * cut_inner; // both endpoints are on the same side of, or parallel to, the face // and both are out of the interaction zone @@ -1257,7 +1397,7 @@ int PairBodyRoundedPolyhedron::interaction_face_to_edge(int ibody, if (inside1) { if (static_cast<int>(discrete[jfirst+npj1][6]) == 0) { pair_force_and_torque(jbody, ibody, xpj1, hi1, d1, contact_dist, - k_n, k_na, shift, x, v, f, torque, angmom, + k_n, k_na, x, v, f, torque, angmom, jflag, energy, facc); #ifdef _POLYHEDRON_DEBUG printf(" - compute pair force between vertex %d from edge %d of body %d " @@ -1277,6 +1417,7 @@ int PairBodyRoundedPolyhedron::interaction_face_to_edge(int ibody, contact_list[num_contacts].xj[2] = xpj1[2]; contact_list[num_contacts].type = 0; contact_list[num_contacts].separation = d1 - contact_dist; + contact_list[num_contacts].unique = 1; num_contacts++; } @@ -1295,7 +1436,7 @@ int PairBodyRoundedPolyhedron::interaction_face_to_edge(int ibody, if (inside2) { if (static_cast<int>(discrete[jfirst+npj2][6]) == 0) { pair_force_and_torque(jbody, ibody, xpj2, hi2, d2, contact_dist, - k_n, k_na, shift, x, v, f, torque, angmom, + k_n, k_na, x, v, f, torque, angmom, jflag, energy, facc); #ifdef _POLYHEDRON_DEBUG printf(" - compute pair force between vertex %d from edge %d of body %d " @@ -1315,6 +1456,7 @@ int PairBodyRoundedPolyhedron::interaction_face_to_edge(int ibody, contact_list[num_contacts].xj[2] = xpj2[2]; contact_list[num_contacts].type = 0; contact_list[num_contacts].separation = d2 - contact_dist; + contact_list[num_contacts].unique = 1; num_contacts++; } discrete[jfirst+npj2][6] = 1; @@ -1360,155 +1502,17 @@ int PairBodyRoundedPolyhedron::interaction_face_to_edge(int ibody, int jflag = 1; if (d1 < d2) pair_force_and_torque(jbody, ibody, xpj1, hi1, d1, contact_dist, - k_n, k_na, shift, x, v, f, torque, angmom, + k_n, k_na, x, v, f, torque, angmom, jflag, energy, facc); else pair_force_and_torque(jbody, ibody, xpj2, hi2, d2, contact_dist, - k_n, k_na, shift, x, v, f, torque, angmom, + k_n, k_na, x, v, f, torque, angmom, jflag, energy, facc); } return interact; } -/* ------------------------------------------------------------------------- - Compute the distance between an edge of body i and an edge from - another body - Input: - ibody = body i (i.e. atom i) - face_index = face index of body i - xmi = atom i's coordinates (body i's center of mass) - rounded_radius_i = rounded radius of the body i - jbody = body i (i.e. atom j) - edge_index = coordinate of the tested edge from another body - xmj = atom j's coordinates (body j's center of mass) - rounded_radius_j = rounded radius of the body j - cut_inner = cutoff for vertex-vertex and vertex-edge interaction - Output: - d = Distance from a point x0 to an edge - hi = coordinates of the projection of x0 on the edge - - contact = 0 no contact between the queried edge and the face - 1 contact detected - return - INVALID if the face index is invalid - NONE if there is no interaction -------------------------------------------------------------------------- */ - -int PairBodyRoundedPolyhedron::interaction_edge_to_edge(int ibody, - int edge_index_i, - double *xmi, - double rounded_radius_i, - int jbody, - int edge_index_j, - double *xmj, - double rounded_radius_j, - double k_n, - double k_na, - double cut_inner, - Contact* contact_list, - int &num_contacts, - double &energy, - double* facc) -{ - int ifirst,iefirst,jfirst,jefirst,npi1,npi2,npj1,npj2,interact; - double xi1[3],xi2[3],xpj1[3],xpj2[3]; - double r,t1,t2,h1[3],h2[3]; - double contact_dist, shift; - - double** x = atom->x; - double** v = atom->v; - double** f = atom->f; - double** torque = atom->torque; - double** angmom = atom->angmom; - - ifirst = dfirst[ibody]; - iefirst = edfirst[ibody]; - npi1 = static_cast<int>(edge[iefirst+edge_index_i][0]); - npi2 = static_cast<int>(edge[iefirst+edge_index_i][1]); - - // compute the space-fixed coordinates for the edge ends - - xi1[0] = xmi[0] + discrete[ifirst+npi1][0]; - xi1[1] = xmi[1] + discrete[ifirst+npi1][1]; - xi1[2] = xmi[2] + discrete[ifirst+npi1][2]; - - xi2[0] = xmi[0] + discrete[ifirst+npi2][0]; - xi2[1] = xmi[1] + discrete[ifirst+npi2][1]; - xi2[2] = xmi[2] + discrete[ifirst+npi2][2]; - - // two ends of the edge from body j - - jfirst = dfirst[jbody]; - jefirst = edfirst[jbody]; - npj1 = static_cast<int>(edge[jefirst+edge_index_j][0]); - npj2 = static_cast<int>(edge[jefirst+edge_index_j][1]); - - xpj1[0] = xmj[0] + discrete[jfirst+npj1][0]; - xpj1[1] = xmj[1] + discrete[jfirst+npj1][1]; - xpj1[2] = xmj[2] + discrete[jfirst+npj1][2]; - - xpj2[0] = xmj[0] + discrete[jfirst+npj2][0]; - xpj2[1] = xmj[1] + discrete[jfirst+npj2][1]; - xpj2[2] = xmj[2] + discrete[jfirst+npj2][2]; - - contact_dist = rounded_radius_i + rounded_radius_j; - shift = k_na * cut_inner; - - int jflag = 1; - distance_bt_edges(xpj1, xpj2, xi1, xi2, h1, h2, t1, t2, r); - - #ifdef _POLYHEDRON_DEBUG - double ui[3],uj[3]; - MathExtra::sub3(xi1,xi2,ui); - MathExtra::norm3(ui); - MathExtra::sub3(xpj1,xpj2,uj); - MathExtra::norm3(uj); - double dot = MathExtra::dot3(ui, uj); - printf(" edge npi1 = %d (%f %f %f); npi2 = %d (%f %f %f) vs." - " edge npj1 = %d (%f %f %f); npj2 = %d (%f %f %f): " - "t1 = %f; t2 = %f; r = %f; dot = %f\n", - npi1, xi1[0], xi1[1], xi1[2], npi2, xi2[0], xi2[1], xi2[2], - npj1, xpj1[0], xpj1[1], xpj1[2], npj2, xpj2[0], xpj2[1], xpj2[2], - t1, t2, r, dot); - #endif - - interact = EE_NONE; - - // singularity case, ignore interactions - - if (r < EPSILON) return interact; - - // include the vertices for interactions - - if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1 && - r < contact_dist + cut_inner) { - pair_force_and_torque(jbody, ibody, h1, h2, r, contact_dist, - k_n, k_na, shift, x, v, f, torque, angmom, - jflag, energy, facc); - - interact = EE_INTERACT; - if (r <= contact_dist) { - // store the contact info - contact_list[num_contacts].ibody = ibody; - contact_list[num_contacts].jbody = jbody; - contact_list[num_contacts].xi[0] = h2[0]; - contact_list[num_contacts].xi[1] = h2[1]; - contact_list[num_contacts].xi[2] = h2[2]; - contact_list[num_contacts].xj[0] = h1[0]; - contact_list[num_contacts].xj[1] = h1[1]; - contact_list[num_contacts].xj[2] = h1[2]; - contact_list[num_contacts].type = 1; - contact_list[num_contacts].separation = r - contact_dist; - num_contacts++; - } - } else { - - } - - return interact; -} - /* ---------------------------------------------------------------------- Compute forces and torques between two bodies caused by the interaction between a pair of points on either bodies (similar to sphere-sphere) @@ -1516,7 +1520,7 @@ int PairBodyRoundedPolyhedron::interaction_edge_to_edge(int ibody, void PairBodyRoundedPolyhedron::pair_force_and_torque(int ibody, int jbody, double* pi, double* pj, double r, double contact_dist, - double k_n, double k_na, double shift, double** x, + double k_n, double k_na, double** x, double** v, double** f, double** torque, double** angmom, int jflag, double& energy, double* facc) { @@ -1525,7 +1529,10 @@ void PairBodyRoundedPolyhedron::pair_force_and_torque(int ibody, int jbody, delx = pi[0] - pj[0]; dely = pi[1] - pj[1]; delz = pi[2] - pj[2]; - R = r - contact_dist; + R = r - contact_dist; + + kernel_force(R, k_n, k_na, energy, fpair); +/* if (R <= 0) { // deformation occurs fpair = -k_n * R - shift; energy += (0.5 * k_n * R + shift) * R; @@ -1533,6 +1540,7 @@ void PairBodyRoundedPolyhedron::pair_force_and_torque(int ibody, int jbody, fpair = k_na * R - shift; energy += (-0.5 * k_na * R + shift) * R; } else fpair = 0.0; +*/ fx = delx*fpair/r; fy = dely*fpair/r; @@ -1570,6 +1578,26 @@ void PairBodyRoundedPolyhedron::pair_force_and_torque(int ibody, int jbody, } } +/* ---------------------------------------------------------------------- + Kernel force is model-dependent and can be derived for other styles + here is the harmonic potential (linear piece-wise forces) in Wang et al. +------------------------------------------------------------------------- */ + +void PairBodyRoundedPolyhedron::kernel_force(double R, double k_n, double k_na, + double& energy, double& fpair) +{ + double shift = k_na * cut_inner; + double e = 0; + if (R <= 0) { // deformation occurs + fpair = -k_n * R - shift; + e = (0.5 * k_n * R + shift) * R; + } else if (R <= cut_inner) { // not deforming but cohesive ranges overlap + fpair = k_na * R - shift; + e = (-0.5 * k_na * R + shift) * R; + } else fpair = 0.0; + energy += e; +} + /* ---------------------------------------------------------------------- Compute contact forces between two bodies modify the force stored at the vertex and edge in contact by j_a @@ -1685,7 +1713,7 @@ void PairBodyRoundedPolyhedron::rescale_cohesive_forces(double** x, double k_n, double k_na, double* facc) { int m,ibody,jbody; - double delx,dely,delz,fx,fy,fz,R,fpair,r,shift,contact_area; + double delx,dely,delz,fx,fy,fz,R,fpair,r,contact_area; int num_unique_contacts = 0; if (num_contacts == 1) { @@ -1723,11 +1751,11 @@ void PairBodyRoundedPolyhedron::rescale_cohesive_forces(double** x, contact_area *= (MY_PI/(double)num_unique_contacts); } - double j_a = contact_area / (num_contacts * A_ua); + double j_a = contact_area / (num_unique_contacts * A_ua); if (j_a < 1.0) j_a = 1.0; - shift = k_na * cut_inner; - for (m = 0; m < num_contacts; m++) { + if (contact_list[m].unique == 0) continue; + ibody = contact_list[m].ibody; jbody = contact_list[m].jbody; @@ -1735,12 +1763,17 @@ void PairBodyRoundedPolyhedron::rescale_cohesive_forces(double** x, dely = contact_list[m].xi[1] - contact_list[m].xj[1]; delz = contact_list[m].xi[2] - contact_list[m].xj[2]; r = sqrt(delx*delx + dely*dely + delz*delz); - R = contact_list[m].separation; + R = contact_list[m].separation; + + double energy = 0; + kernel_force(R, k_n, k_na, energy, fpair); +/* if (R <= 0) { // deformation occurs fpair = -k_n * R - shift; } else if (R <= cut_inner) { // not deforming but cohesive ranges overlap fpair = k_na * R - shift; } else fpair = 0.0; +*/ fpair *= j_a; fx = delx*fpair/r; diff --git a/src/BODY/pair_body_rounded_polyhedron.h b/src/BODY/pair_body_rounded_polyhedron.h index 05985ef813..f59faf9ba6 100644 --- a/src/BODY/pair_body_rounded_polyhedron.h +++ b/src/BODY/pair_body_rounded_polyhedron.h @@ -34,6 +34,9 @@ class PairBodyRoundedPolyhedron : public Pair { void init_style(); double init_one(int, int); + virtual void kernel_force(double R, double k_n, double k_na, + double& energy, double& fpair); + struct Contact { int ibody, jbody; // body (i.e. atom) indices (not tags) int type; // 0 = VERTEX-FACE; 1 = EDGE-EDGE @@ -84,28 +87,35 @@ class PairBodyRoundedPolyhedron : public Pair { void allocate(); void body2space(int); - int edge_against_face(int ibody, int jbody, double k_n, double k_na, - double** x, Contact* contact_list, int &num_contacts, - double &evdwl, double* facc); - int edge_against_edge(int ibody, int jbody, double k_n, double k_na, - double** x,Contact* contact_list, int &num_contacts, - double &evdwl, double* facc); + // sphere-sphere interaction void sphere_against_sphere(int ibody, int jbody, double delx, double dely, double delz, double rsq, double k_n, double k_na, double** v, double** f, int evflag); - void sphere_against_face(int ibody, int jbody, + // sphere-edge interaction + void sphere_against_edge(int ibody, int jbody, double k_n, double k_na, double** x, double** v, double** f, double** torque, double** angmom, int evflag); - void sphere_against_edge(int ibody, int jbody, + // sphere-face interaction + void sphere_against_face(int ibody, int jbody, double k_n, double k_na, double** x, double** v, double** f, double** torque, double** angmom, int evflag); + // edge-edge interactions + int edge_against_edge(int ibody, int jbody, double k_n, double k_na, + double** x,Contact* contact_list, int &num_contacts, + double &evdwl, double* facc); + // edge-face interactions + int edge_against_face(int ibody, int jbody, double k_n, double k_na, + double** x, Contact* contact_list, int &num_contacts, + double &evdwl, double* facc); + // a face vs. a single edge int interaction_face_to_edge(int ibody, int face_index, double* xmi, double rounded_radius_i, int jbody, int edge_index, double* xmj, double rounded_radius_j, double k_n, double k_na, double cut_inner, Contact* contact_list, int &num_contacts, double& energy, double* facc); + // an edge vs. an edge from another body int interaction_edge_to_edge(int ibody, int edge_index_i, double* xmi, double rounded_radius_i, int jbody, int edge_index_j, double* xmj, double rounded_radius_j, @@ -113,29 +123,38 @@ class PairBodyRoundedPolyhedron : public Pair { Contact* contact_list, int &num_contacts, double& energy, double* facc); + // compute contact forces if contact points are detected void contact_forces(int ibody, int jbody, double *xi, double *xj, double delx, double dely, double delz, double fx, double fy, double fz, double** x, double** v, double** angmom, double** f, double** torque, double* facc); + // compute force and torque between two bodies given a pair of interacting points void pair_force_and_torque(int ibody, int jbody, double* pi, double* pj, double r, double contact_dist, double k_n, - double k_na, double shift, double** x, double** v, + double k_na, double** x, double** v, double** f, double** torque, double** angmom, int jflag, double& energy, double* facc); + // rescale the cohesive forces if a contact area is detected void rescale_cohesive_forces(double** x, double** f, double** torque, Contact* contact_list, int &num_contacts, double k_n, double k_na, double* facc); + // compute the separation between two contacts double contact_separation(const Contact& c1, const Contact& c2); + // detect the unique contact points (as there may be double counts) void find_unique_contacts(Contact* contact_list, int& num_contacts); + // accumulate torque to a body given a force at a given point void sum_torque(double* xm, double *x, double fx, double fy, double fz, double* torque); - int opposite_sides(double* n, double* x0, double* a, double* b); + + // find the intersection point (if any) between an edge and a face int edge_face_intersect(double* x1, double* x2, double* x3, double* a, double* b, double* hi1, double* hi2, double& d1, double& d2, int& inside_a, int& inside_b); + // helper functions + int opposite_sides(double* n, double* x0, double* a, double* b); void project_pt_plane(const double* q, const double* p, const double* n, double* q_proj, double &d); void project_pt_plane(const double* q, const double* x1, const double* x2, -- GitLab