Program Listing for File potentialBendingGompperKroll.cpp#
↰ Return to documentation for file (pymembrane/cppmodule/src/potentials/potentialBendingGompperKroll.cpp
)
#include "potentialBendingGompperKroll.hpp"
//update face global index, normal vector, area and cotangent
void update_face(const std::vector<int> local_index,
const std::vector<real3> local_vertices,
std::vector<double> &local_cot,
std::vector<double> &local_area,
std::vector<real3> &local_sigma,
double &At, real3 &nf)
{
nf = pymemb::compute_normal_triangle(local_vertices[0], local_vertices[1], local_vertices[2]);
At = 0.5*sqrt(vdot(nf,nf));
for (int i = 0; i < 3; ++i)
{
int k=(i+1)%3, l=(i+2)%3;
int vi = local_index[i];
int vk = local_index[k];
int vl = local_index[l];
real3 ri = local_vertices[i];
real3 rk = local_vertices[k];
real3 rl = local_vertices[l];
real3 ril,rik,rkl;
vsub(ril, ri, rl);
vsub(rik, ri, rk);
vsub(rkl, rk, rl);
local_cot[k] = -vdot(rik,rkl)/2./At;
local_cot[l] = vdot(ril,rkl)/2./At;
Xvec2(local_sigma[i], 0.5 * local_cot[k], ril,
0.5 * local_cot[l], rik);
local_area[i] = 0.125 * local_cot[k] * vdot(ril,ril)
+ 0.125 * local_cot[l] * vdot(rik,rik);
}
}
void compute_mean_curvature_operature(
int Numvertices,
int Numfaces,
const HE_VertexProp *vertices,
const HE_FaceProp *faces,
std::vector<real3> &meanH_operator,
std::vector<double> &meanH)
{
std::vector<int> local_index (3);
std::vector<real3> local_vertices (3);
std::vector<double> local_cot (3);
std::vector<double> local_area (3);
std::vector<real3> local_sigma (3);
std::vector<double> global_area (Numvertices);
std::vector<real3> global_sigma (Numvertices);
std::vector<real3> global_normal (Numvertices);
double At;
real3 nf;
for (int face_index = 0;
face_index < Numfaces;
face_index ++)
{
local_index[0]=faces[face_index].v1;
local_index[1]=faces[face_index].v2;
local_index[2]=faces[face_index].v3;
local_vertices[0]=vertices[local_index[0]].r;
local_vertices[1]=vertices[local_index[1]].r;
local_vertices[2]=vertices[local_index[2]].r;
update_face(local_index,
local_vertices,
local_cot,
local_area,
local_sigma,
At,nf);
for (int i = 0; i < 3; ++i)
{
int vi = local_index[i];
global_area[vi] += local_area[i];
vsum(global_sigma[vi],global_sigma[vi],local_sigma[i]);
vsum(global_normal[vi],global_normal[vi],nf);
}
}
for (int vertex_index = 0; vertex_index < Numvertices; vertex_index++)
{
double vertex_area = global_area[vertex_index];
real3 nv = global_normal[vertex_index];
real3 sigma = global_sigma[vertex_index];
double sign = (vdot(nv, sigma) > 0.) ? 1. : -1.;
Xvec1(meanH_operator[vertex_index], 1./vertex_area, sigma);
meanH[vertex_index] = sign * sqrt(vdot(sigma, sigma)) / vertex_area;
}
}
void ComputeVertexBendingGKEnergy::compute(void)
{
std::vector<int> local_index (3);
std::vector<real3> local_vertices (3);
std::vector<double> local_cot (3);
std::vector<double> local_area (3);
std::vector<real3> local_sigma (3);
std::vector<real3> force (3);
std::vector<real3> meanH_operator (_system.Numvertices);
std::vector<double> meanH (_system.Numvertices);
std::vector<real3> forces (_system.Numvertices);
int vi,vj,vk,vl;
double a,At,H,H_0,k_b,k_g,cot_i,cot_j,cot_k,cot_l;
real3 ri,rj,rk,rl,rij,rjk,ril,rik,rkl;
real3 Hop,sigmai,sigmaj,dA,nf,force1,force2,forceg;
compute_mean_curvature_operature(_system.Numvertices,
_system.Numfaces,
&_system.vertices[0],
&_system.faces[0],
meanH_operator,
meanH);
for (int face_index = 0;
face_index < _system.Numfaces;
face_index ++)
{
local_index[0]=_system.faces[face_index].v1;
local_index[1]=_system.faces[face_index].v2;
local_index[2]=_system.faces[face_index].v3;
local_vertices[0]=_system.vertices[local_index[0]].r;
local_vertices[1]=_system.vertices[local_index[1]].r;
local_vertices[2]=_system.vertices[local_index[2]].r;
update_face(local_index,
local_vertices,
local_cot,
local_area,
local_sigma,
At,nf);
for (int i = 0; i < 3; ++i)
{
//force on i:
vi = local_index[i];
ri = _system.vertices[vi].r;
sigmai = local_sigma[i];
for (int j = 0; j < 3; ++j)
{
a = local_area[j];
sigmaj = local_sigma[j];
Hop = meanH_operator[local_index[j]];
H = meanH[local_index[j]];
int type = _system.vertices[local_index[j]].type;
H_0 = H0[type];
k_b = kappaH[type];
k_g = kappaG[type];
vj = local_index[j];
cot_j = local_cot[j];
if (i==j)
{
vk = local_index[(i+1)%3];
vl = local_index[(i+2)%3];
rk = _system.vertices[vk].r;
rl = _system.vertices[vl].r;
vsub(ril, ri, rl);
vsub(rik, ri, rk);
vsub(rkl, rk, rl);
cot_k = local_cot[(i+1)%3];
cot_l = local_cot[(i+2)%3];
Xvec3(dA,
(1. - a/At), sigmai,
- 0.125 * (cot_k+cot_l), rik,
- 0.125 * (cot_k+cot_l), ril);
Xvec1(force1,
0.5 * (H - 2.*H_0) * (H + 2.*H_0), dA);
Xvec3(force2,
- 1.0 * vdot(Hop,sigmai), sigmai,
+ 0.25 * vdot(rkl,rkl), Hop,
- 0.25 * vdot(rkl,Hop), rkl);
if (vdot(force2,force2)>0.)
aXvec(-(H - 2.*H_0)/(H * At), force2);
// forceg.x=forceg.y=forceg.z=0.;
Xvec2(forceg,
-1.0*cot_k/vdot(rik,rik), rik,
-1.0*cot_l/vdot(ril,ril), ril);
}
else
{
vj = local_index[j];
vk = local_index[3-i-j];
rj = _system.vertices[vj].r;
rk = _system.vertices[vk].r;
vsub(rij, ri, rj);
vsub(rik, ri, rk);
vsub(rjk, rj, rk);
cot_i = local_cot[i];
cot_k = local_cot[3-i-j];
Xvec3(dA,
(0.5 - a/At), sigmai,
+ 0.125 * (2*cot_k), rik,
+ 0.125 * (cot_i-cot_k), rjk);
Xvec1(force1,
0.5 * (H - 2.*H_0) * (H + 2.*H_0), dA);
Xvec4(force2,
+ 1.0 * vdot(Hop, sigmaj), sigmai,
- 0.5 * vdot(Hop, rjk), rik,
+ 0.25 * vdot(Hop, rik), rjk,
+ 0.25 * vdot(rjk, rik), Hop);
if (vdot(force2,force2)>0.)
aXvec((H - 2.*H_0)/(H * At), force2);
// forceg.x=forceg.y=forceg.z=0.;
Xvec2(forceg,
0.5/At, rjk,
cot_j/vdot(rij,rij), rij);
}
_system.vertices[vi].forceC.x += k_b * (force1.x + force2.x) + k_g * forceg.x;
_system.vertices[vi].forceC.y += k_b * (force1.y + force2.y) + k_g * forceg.y;
_system.vertices[vi].forceC.z += k_b * (force1.z + force2.z) + k_g * forceg.z;
}
}
}
}
double compute_vertex_energy_fn(int query_vertex_index,
const HE_VertexProp *vertices,
const HE_HalfEdgeProp *halfedges,
const double *_kappaH,
const double *_kappaG,
const double *_H0)
{
real3 sigma, nv, nf;
nv.x = nv.y = nv.z = 0.0;
sigma.x = sigma.y = sigma.z = 0.0;
double gaussian_curv = 2.0*defPI;
double vertex_area = 0.0;
int v0=query_vertex_index,v1,v2;
int he = vertices[query_vertex_index]._hedge;
int first = he;
do
{
int edge_index = halfedges[he].edge;
if (halfedges[he].boundary == false)
{
v1 = halfedges[he].vert_to;
int he_next = halfedges[he].next;
v2 = halfedges[he_next].vert_to;
nf = pymemb::compute_normal_triangle(vertices[v0].r, vertices[v1].r, vertices[v2].r);
nv.x += nf.x;
nv.y += nf.y;
nv.z += nf.z;
real3 r0 = vertices[v0].r;
real3 r1 = vertices[v1].r;
real3 r2 = vertices[v2].r;
real3 r01, r02, r10, r12, r20, r21;
vsub(r01, r0, r1);
vsub(r02, r0, r2);
vsub(r10, r1, r0);
vsub(r12, r1, r2);
vsub(r20, r2, r0);
vsub(r21, r2, r1);
double r01_dot_r02 = vdot(r01, r02);
double r10_dot_r12 = vdot(r10, r12);
double r20_dot_r21 = vdot(r20, r21);
real3 r01_cross_r02, r10_cross_r12, r20_cross_r21;
vcross(r01_cross_r02, r01, r02);
vcross(r10_cross_r12, r10, r12);
vcross(r20_cross_r21, r21, r20);
double r01_cross_r02n = sqrt(vdot(r01_cross_r02, r01_cross_r02));
double r10_cross_r12n = sqrt(vdot(r10_cross_r12, r10_cross_r12));
double r20_cross_r21n = sqrt(vdot(r20_cross_r21, r20_cross_r21));
double cot_alpha = r10_dot_r12 / r10_cross_r12n;
double cot_beta = r20_dot_r21 / r20_cross_r21n;
double cot_weight = 0.5 * (cot_alpha + cot_beta);
sigma.x += 0.5 * cot_alpha * r02.x + 0.5 * cot_beta * r01.x;
sigma.y += 0.5 * cot_alpha * r02.y + 0.5 * cot_beta * r01.y;
sigma.z += 0.5 * cot_alpha * r02.z + 0.5 * cot_beta * r01.z;
// vertex_area += 0.125 * vdot(r02, r02) * cot_alpha + 0.125 * vdot(r01, r01) * cot_beta;
if (r01_dot_r02<0 || r10_dot_r12<0 || r20_dot_r21<0)
{
if (r01_dot_r02<0)
vertex_area += 0.5 * r01_cross_r02n;
else
vertex_area += 0.25 * r01_cross_r02n;
}
else
vertex_area += 0.125 * vdot(r02, r02) * cot_alpha + 0.125 * vdot(r01, r01) * cot_beta;
gaussian_curv-=acos(r01_dot_r02/sqrt(vdot(r01,r01)*vdot(r02,r02)));
}
int he_pair = halfedges[he].pair;
he = halfedges[he_pair].next;
} while ((he != first));
int type = vertices[query_vertex_index].type;
double sign = (vdot(nv, sigma) > 0.) ? 1. : -1.;
double H = sign * sqrt(vdot(sigma, sigma)) / vertex_area;
double delH = H - 2.0 * _H0[type];
return (0.5 * _kappaH[type] * delH * delH * vertex_area + _kappaG[type]*gaussian_curv);
}
void ComputeVertexBendingGKEnergy::compute_energy(void)
{
for (int vertex_index = 0; vertex_index < _system.Numvertices; vertex_index++)
{
double energy=compute_vertex_energy_fn(vertex_index,
&_system.vertices[0],
&_system.halfedges[0],
&kappaH[0],
&kappaG[0],
&H0[0]);
_system.vertices[vertex_index].energy += energy;
}
}
double ComputeVertexBendingGKEnergy::compute_edge_energy(int query_edge_index)
{
pymemb::vector<int> v_index_vec(4);
v_index_vec[0] = _system.edges[query_edge_index].v0;
v_index_vec[1] = _system.edges[query_edge_index].v1;
v_index_vec[2] = _system.edges[query_edge_index].v2;
v_index_vec[3] = _system.edges[query_edge_index].v3;
double edge_energy = 0.0;
for (auto v_index : v_index_vec)
{
edge_energy+=compute_vertex_energy_fn(v_index,
&_system.vertices[0],
&_system.halfedges[0],
&kappaH[0],
&kappaG[0],
&H0[0]);
}
return(edge_energy);
}
//energy of query vertex and its neighbor vertices
double ComputeVertexBendingGKEnergy::compute_vertex_energy(int query_vertex_index)
{
double energy = compute_vertex_energy_fn(query_vertex_index,
&_system.vertices[0],
&_system.halfedges[0],
&kappaH[0],
&kappaG[0],
&H0[0]);
int he = _system.vertices[query_vertex_index]._hedge;
int first = he;
do
{
energy += compute_vertex_energy_fn(_system.halfedges[he].vert_to,
&_system.vertices[0],
&_system.halfedges[0],
&kappaH[0],
&kappaG[0],
&H0[0]);
int he_pair = _system.halfedges[he].pair;
he = _system.halfedges[he_pair].next;
} while ((he != first));
return energy;
}