Program Listing for File potentialConstantAreaTriangle.cpp#

Return to documentation for file (pymembrane/cppmodule/src/potentials/potentialConstantAreaTriangle.cpp)

#include "potentialConstantAreaTriangle.hpp"

real ComputeVertexConstantAreaTriangleEnergy_lambda(const real *__restrict__ g_now,
                                                    const real sigma,
                                                    const real target_area)
{
    real triangle_area = pymemb::compute_area_triangle_from_metric(g_now);
    real energy = 0.5 * sigma * (triangle_area - target_area) * (triangle_area - target_area);
    return energy;
}

void ComputeVertexConstantAreaTriangleEnergy_fn(const int Numfaces,
                                                HE_FaceProp *faces,
                                                const HE_VertexProp *vertices,
                                                const real *__restrict__ _sigma,
                                                const real *__restrict__ _target_area,
                                                const BoxType _box)
{
    for (int face_index = 0; face_index < Numfaces; face_index++)
    {
        int type = faces[face_index].type;
        int v1 = faces[face_index].v1;
        int v2 = faces[face_index].v2;
        int v3 = faces[face_index].v3;

        real g_now[3];
        pymemb::compute_form_factor_triangle(g_now, vertices[v1].r, vertices[v2].r, vertices[v3].r, _box);
        real energy = ComputeVertexConstantAreaTriangleEnergy_lambda(g_now, _sigma[type], _target_area[type]);

        faces[face_index].energy += energy;
    }
}

void ComputeVertexConstantAreaTriangleEnergy::compute_energy(void)
{

    ComputeVertexConstantAreaTriangleEnergy_fn(_system.Numfaces,
                                               &_system.faces[0],
                                               &_system.vertices[0],
                                               &sigma[0],
                                               &target_area[0],
                                               _system.get_box());
}

real ComputeVertexConstantAreaTriangleEnergy::compute_edge_energy(int query_edge_index)
{
    // we need to loop the 2 faces that are connected to the edge_index
    pymemb::vector<int> face_vec{_system.edges[query_edge_index].face_k, _system.edges[query_edge_index].face_l};
    // reset energy
    real edge_energy = 0.0;
    for (auto face_index : face_vec)
    {
        int type = _system.faces[face_index].type;
        int v1 = _system.faces[face_index].v1;
        int v2 = _system.faces[face_index].v2;
        int v3 = _system.faces[face_index].v3;

        real g_now[3];
        pymemb::compute_form_factor_triangle(g_now, _system.vertices[v1].r, _system.vertices[v2].r, _system.vertices[v3].r, _system.get_box());
        edge_energy += ComputeVertexConstantAreaTriangleEnergy_lambda(g_now, sigma[type], target_area[type]);
    }
    return edge_energy;
}

real ComputeVertexConstantAreaTriangleEnergy::compute_vertex_energy(int query_vertex_index)
{

    real energy = 0.0;

    int he = _system.vertices[query_vertex_index]._hedge;
    int first = he;
    // std::cout<< "first " << first << "\n";
    int face_index, he_pair, he_pair_next;
    do
    {

        face_index = _system.halfedges[he].face;
        if (_system.faces[face_index].boundary == false) // Remember -1 is the virtual face outside of the mesh
        {
            int type = _system.faces[face_index].type;
            int v1 = _system.faces[face_index].v1;
            int v2 = _system.faces[face_index].v2;
            int v3 = _system.faces[face_index].v3;

            real g_now[3];
            pymemb::compute_form_factor_triangle(g_now, _system.vertices[v1].r, _system.vertices[v2].r, _system.vertices[v3].r, _system.get_box());
            energy += ComputeVertexConstantAreaTriangleEnergy_lambda(g_now, sigma[type], target_area[type]);
        }

        int he_prev = _system.halfedges[he].prev;
        he = _system.halfedges[he_prev].pair;
    } while ((he != first));
    return energy;
}

forceMatrix ComputeVertexConstantAreaTriangleForce_lambda(const real3 r1,
                                                          const real3 r2,
                                                          const real3 r3,
                                                          const real *__restrict__ g_now,
                                                          const real sigma,
                                                          const real target_area,
                                                          const BoxType _box)
{

    real triangle_area = pymemb::compute_area_triangle_from_metric(g_now);

    /*----------------------------------------------------------------------------------------------------------------*/
    /*-----------------------------------           FORCE MATRIX        ----------------------------------------------*/
    /*----------------------------------------------------------------------------------------------------------------*/
    real force_factor = sigma * (triangle_area - target_area);

    auto r12 = pymemb::vector_subtract(r2, r1, _box);
    auto r13 = pymemb::vector_subtract(r3, r1, _box);

    real3 forceM11, forceM12;
    forceM11.x = forceM11.y = forceM11.z = 0.0;
    forceM12.x = forceM12.y = forceM12.z = 0.0;

    // T5
    forceM11.x += (0.25 * force_factor / triangle_area) * (g_now[2] * r12.x - g_now[1] * r13.x);
    forceM12.x += (0.25 * force_factor / triangle_area) * (g_now[0] * r13.x - g_now[1] * r12.x);
    forceM11.y += (0.25 * force_factor / triangle_area) * (g_now[2] * r12.y - g_now[1] * r13.y);
    forceM12.y += (0.25 * force_factor / triangle_area) * (g_now[0] * r13.y - g_now[1] * r12.y);
    forceM11.z += (0.25 * force_factor / triangle_area) * (g_now[2] * r12.z - g_now[1] * r13.z);
    forceM12.z += (0.25 * force_factor / triangle_area) * (g_now[0] * r13.z - g_now[1] * r12.z);

    forceM11.x *= -1.0;
    forceM12.x *= -1.0;
    forceM11.y *= -1.0;
    forceM12.y *= -1.0;
    forceM11.z *= -1.0;
    forceM12.z *= -1.0;

    forceMatrix result;

    result.forceM11 = forceM11;
    result.forceM12 = forceM12;

    return result;
}

void ComputeVertexConstantAreaTriangleForce_fn(const int Numfaces,
                                               HE_VertexProp *vertices,
                                               const HE_FaceProp *faces,
                                               const real *__restrict__ _sigma,
                                               const real *__restrict__ _target_area,
                                               const BoxType _box)
{
    for (int face_index = 0; face_index < Numfaces; face_index++)
    {
        int type = faces[face_index].type;
        int v1 = faces[face_index].v1;
        int v2 = faces[face_index].v2;
        int v3 = faces[face_index].v3;

        real g_now[3];
        pymemb::compute_form_factor_triangle(g_now, vertices[v1].r, vertices[v2].r, vertices[v3].r, _box);

        forceMatrix fval = ComputeVertexConstantAreaTriangleForce_lambda(vertices[v1].r,
                                                                         vertices[v2].r,
                                                                         vertices[v3].r,
                                                                         g_now,
                                                                         _sigma[type],
                                                                         _target_area[type],
                                                                         _box);

        /*----------------------------------------------------------------------------------------------------------------*/
        /*-----------------------------------           ACTUAL CALCULATION        ----------------------------------------*/
        /*----------------------------------------------------------------------------------------------------------------*/
        // v1
        vertices[v1].forceC.x += -1.0 * (fval.forceM11.x + fval.forceM12.x);
        vertices[v1].forceC.y += -1.0 * (fval.forceM11.y + fval.forceM12.y);
        vertices[v1].forceC.z += -1.0 * (fval.forceM11.z + fval.forceM12.z);

        // v2
        vertices[v2].forceC.x += fval.forceM11.x;
        vertices[v2].forceC.y += fval.forceM11.y;
        vertices[v2].forceC.z += fval.forceM11.z;

        // v3
        vertices[v3].forceC.x += fval.forceM12.x;
        vertices[v3].forceC.y += fval.forceM12.y;
        vertices[v3].forceC.z += fval.forceM12.z;
    }
}

void ComputeVertexConstantAreaTriangleEnergy::compute(void)
{

    ComputeVertexConstantAreaTriangleForce_fn(_system.Numfaces,
                                              &_system.vertices[0],
                                              &_system.faces[0],
                                              &sigma[0],
                                              &target_area[0],
                                              _system.get_box());
}

void ComputeVertexConstantAreaTriangleEnergyStress_fn(const int Numfaces,
                                                      HE_VertexProp *vertices,
                                                      const HE_FaceProp *faces,
                                                      const real *__restrict__ _sigma,
                                                      const real *__restrict__ _target_area,
                                                      realTensor *stress_group_faces,
                                                      const BoxType _box)
{

    for (int face_index = 0; face_index < Numfaces; face_index++)
    {
        int type = faces[face_index].type;
        int v1 = faces[face_index].v1;
        int v2 = faces[face_index].v2;
        int v3 = faces[face_index].v3;

        real g_now[3];
        pymemb::compute_form_factor_triangle(g_now, vertices[v1].r, vertices[v2].r, vertices[v3].r, _box);

        forceMatrix fval = ComputeVertexConstantAreaTriangleForce_lambda(vertices[v1].r,
                                                                         vertices[v2].r,
                                                                         vertices[v3].r,
                                                                         g_now,
                                                                         _sigma[type],
                                                                         _target_area[type],
                                                                         _box);
        // J. Chem. Phys. 131, 154107 (2009) page 4 Eq. 21
        // Assume that v1 is in the local replica then construct the r2, r3 based on it

        real3 r1 = vertices[v1].r;
        real3 r2 = vertices[v2].r;
        real3 r3 = vertices[v3].r;

        real3 r12, r13;
        r12 = pymemb::vector_subtract(r2, r1, _box);
        r13 = pymemb::vector_subtract(r3, r1, _box);
        real3 uw_r3, uw_r2 /*,uw_r1*/;
        // uw_r1 = r1;
        uw_r2 = pymemb::vector_sum(r1, r12);
        uw_r3 = pymemb::vector_sum(r1, r13);

        real3 F3, F2, F1;

        F1.x = -1.0 * (fval.forceM11.x + fval.forceM12.x);
        F1.y = -1.0 * (fval.forceM11.y + fval.forceM12.y);
        F1.z = -1.0 * (fval.forceM11.z + fval.forceM12.z);

        F2.x = fval.forceM11.x;
        F2.y = fval.forceM11.y;
        F2.z = fval.forceM11.z;

        F3.x = fval.forceM12.x;
        F3.y = fval.forceM12.y;
        F3.z = fval.forceM12.z;

        stress_group_faces[face_index].xx += r1.x * F1.x + uw_r2.x * F2.x + uw_r3.x * F3.x;
        stress_group_faces[face_index].xy += r1.x * F1.y + uw_r2.x * F2.y + uw_r3.x * F3.y;
        stress_group_faces[face_index].xz += r1.x * F1.z + uw_r2.x * F2.z + uw_r3.x * F3.z;

        stress_group_faces[face_index].yx += r1.y * F1.x + uw_r2.y * F2.x + uw_r3.y * F3.x;
        stress_group_faces[face_index].yy += r1.y * F1.y + uw_r2.y * F2.y + uw_r3.y * F3.y;
        stress_group_faces[face_index].yz += r1.y * F1.z + uw_r2.y * F2.z + uw_r3.y * F3.z;

        stress_group_faces[face_index].zx += r1.z * F1.x + uw_r2.z * F2.x + uw_r3.z * F3.x;
        stress_group_faces[face_index].zy += r1.z * F1.y + uw_r2.z * F2.y + uw_r3.z * F3.y;
        stress_group_faces[face_index].zz += r1.z * F1.z + uw_r2.z * F2.z + uw_r3.z * F3.z;
    }
}

void ComputeVertexConstantAreaTriangleEnergy::compute_stress(void)
{

    ComputeVertexConstantAreaTriangleEnergyStress_fn(_system.Numfaces,
                                                     &_system.vertices[0],
                                                     &_system.faces[0],
                                                     &sigma[0],
                                                     &target_area[0],
                                                     &_system.stress_group_faces[0],
                                                     _system.get_box());
}

void ComputeVertexConstantAreaTriangleEnergyStressAtom_fn(const int Numfaces,
                                                          HE_VertexProp *vertices,
                                                          const HE_FaceProp *faces,
                                                          const real *__restrict__ _sigma,
                                                          const real *__restrict__ _target_area,
                                                          realTensor *stress_virial_atom,
                                                          const BoxType _box)
{

    for (int face_index = 0; face_index < Numfaces; face_index++)
    {
        int type = faces[face_index].type;
        int v1 = faces[face_index].v1;
        int v2 = faces[face_index].v2;
        int v3 = faces[face_index].v3;

        real g_now[3];
        pymemb::compute_form_factor_triangle(g_now, vertices[v1].r, vertices[v2].r, vertices[v3].r, _box);

        forceMatrix fval = ComputeVertexConstantAreaTriangleForce_lambda(vertices[v1].r,
                                                                         vertices[v2].r,
                                                                         vertices[v3].r,
                                                                         g_now,
                                                                         _sigma[type],
                                                                         _target_area[type],
                                                                         _box);
        // J. Chem. Phys. 131, 154107 (2009) page 4 Eq. 21
        // Assume that v1 is in the local replica then construct the r2, r3 based on it

        real3 r1 = vertices[v1].r;
        real3 r2 = vertices[v2].r;
        real3 r3 = vertices[v3].r;

        real3 r12, r13;
        r12 = pymemb::vector_subtract(r2, r1, _box);
        r13 = pymemb::vector_subtract(r3, r1, _box);
        real3 uw_r3, uw_r2 /*,uw_r1*/;
        // uw_r1 = r1;
        uw_r2 = pymemb::vector_sum(r1, r12);
        uw_r3 = pymemb::vector_sum(r1, r13);

        real3 F3, F2, F1;

        F1.x = -1.0 * (fval.forceM11.x + fval.forceM12.x);
        F1.y = -1.0 * (fval.forceM11.y + fval.forceM12.y);
        F1.z = -1.0 * (fval.forceM11.z + fval.forceM12.z);

        F2.x = fval.forceM11.x;
        F2.y = fval.forceM11.y;
        F2.z = fval.forceM11.z;

        F3.x = fval.forceM12.x;
        F3.y = fval.forceM12.y;
        F3.z = fval.forceM12.z;

        realTensor stress_group_face;
        stress_group_face.xx = r1.x * F1.x + uw_r2.x * F2.x + uw_r3.x * F3.x;
        stress_group_face.xy = r1.x * F1.y + uw_r2.x * F2.y + uw_r3.x * F3.y;
        stress_group_face.xz = r1.x * F1.z + uw_r2.x * F2.z + uw_r3.x * F3.z;

        stress_group_face.yx = r1.y * F1.x + uw_r2.y * F2.x + uw_r3.y * F3.x;
        stress_group_face.yy = r1.y * F1.y + uw_r2.y * F2.y + uw_r3.y * F3.y;
        stress_group_face.yz = r1.y * F1.z + uw_r2.y * F2.z + uw_r3.y * F3.z;

        stress_group_face.zx = r1.z * F1.x + uw_r2.z * F2.x + uw_r3.z * F3.x;
        stress_group_face.zy = r1.z * F1.y + uw_r2.z * F2.y + uw_r3.z * F3.y;
        stress_group_face.zz = r1.z * F1.z + uw_r2.z * F2.z + uw_r3.z * F3.z;

        int vvec[3] = {v1, v2, v3};

        for (auto v : vvec)
        {
            stress_virial_atom[v].xx += stress_group_face.xx / 3.0;
            stress_virial_atom[v].xy += stress_group_face.xy / 3.0;
            stress_virial_atom[v].xz += stress_group_face.xz / 3.0;
            stress_virial_atom[v].yx += stress_group_face.yx / 3.0;
            stress_virial_atom[v].yy += stress_group_face.yy / 3.0;
            stress_virial_atom[v].yz += stress_group_face.yz / 3.0;
            stress_virial_atom[v].zx += stress_group_face.zx / 3.0;
            stress_virial_atom[v].zy += stress_group_face.zy / 3.0;
            stress_virial_atom[v].zz += stress_group_face.zz / 3.0;
        }
    }
}

void ComputeVertexConstantAreaTriangleEnergy::compute_atomic_stress(void)
{

    ComputeVertexConstantAreaTriangleEnergyStressAtom_fn(_system.Numfaces,
                                                         &_system.vertices[0],
                                                         &_system.faces[0],
                                                         &sigma[0],
                                                         &target_area[0],
                                                         &_system.stress_virial_atom[0],
                                                         _system.get_box());
}