Program Listing for File potentialCauchyGreen.cpp#

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

#include "potentialCauchyGreen.hpp"

real ComputeVertexCauchyGreenEnergy_lambda(const real *__restrict__ g_now,
                                           const real *__restrict__ g_reference,
                                           const real *__restrict__ g_reference_inv,
                                           const real Y,
                                           const real nu,
                                           const real h)
{
    real triangle_reference_area = pymemb::compute_area_triangle_from_metric(g_reference);
    //     _                                         _     _                     _     _      _
    //    |   g_reference_inv[0]  g_reference_inv[1]  |   |   g_now[0]  g_now[1]  |   |  1  0  |
    // F = |                                           | x |                       | - |        |
    //    |_  g_reference_inv[1]  g_reference_inv[2] _|   |_  g_now[1]  g_now[2] _|   |_ 0  1 _|
    real F11 = g_reference_inv[0] * g_now[0] + g_reference_inv[1] * g_now[1] - 1.0;
    real F12 = g_reference_inv[0] * g_now[1] + g_reference_inv[1] * g_now[2];
    real F21 = g_reference_inv[1] * g_now[0] + g_reference_inv[2] * g_now[1];
    real F22 = g_reference_inv[1] * g_now[1] + g_reference_inv[2] * g_now[2] - 1.0;

    real coeff_1 = Y * h * triangle_reference_area / (8.0 * (1.0 + nu));
    real coeff_2 = coeff_1 * (nu / (1.0 - nu));
    real energy = coeff_1 * (F11 * F11 + F12 * F21 + F12 * F21 + F22 * F22) + coeff_2 * (F11 + F22) * (F11 + F22);

    return energy;
}

void ComputeVertexCauchyGreenEnergy_fn(const int Numfaces,
                                       HE_FaceProp *faces,
                                       const HE_VertexProp *vertices,
                                       const real *__restrict__ _Y,
                                       const real *__restrict__ _nu,
                                       const real *__restrict__ _h,
                                       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 Ydev = _Y[type];
        real nudev = _nu[type];
        real hdev = _h[type];

        real g_now[3];
        pymemb::compute_form_factor_triangle(g_now, vertices[v1].r, vertices[v2].r, vertices[v3].r, _box);
        real energy = ComputeVertexCauchyGreenEnergy_lambda(g_now, faces[face_index].g_reference, faces[face_index].g_reference_inv, Ydev, nudev, hdev);

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

void ComputeVertexCauchyGreenEnergy::compute_energy(void)
{

    ComputeVertexCauchyGreenEnergy_fn(_system.Numfaces,
                                      &_system.faces[0],
                                      &_system.vertices[0],
                                      &Y[0],
                                      &nu[0],
                                      &h[0],
                                      _system.get_box());
}

real ComputeVertexCauchyGreenEnergy::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 Ydev = Y[type];
        real nudev = nu[type];
        real hdev = h[type];

        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 += ComputeVertexCauchyGreenEnergy_lambda(g_now, _system.faces[face_index].g_reference, _system.faces[face_index].g_reference_inv, Ydev, nudev, hdev);
    }
    return edge_energy;
}

real ComputeVertexCauchyGreenEnergy::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 Ydev = Y[type];
            real nudev = nu[type];
            real hdev = h[type];

            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 += ComputeVertexCauchyGreenEnergy_lambda(g_now, _system.faces[face_index].g_reference, _system.faces[face_index].g_reference_inv, Ydev, nudev, hdev);
        }

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

forceMatrix ComputeVertexCauchyGreenForce_lambda(const real3 &r1,
                                                 const real3 &r2,
                                                 const real3 &r3,
                                                 const real *__restrict__ g_now,
                                                 const real *__restrict__ g_reference,
                                                 const real *__restrict__ g_reference_inv,
                                                 const real &Y,
                                                 const real &nu,
                                                 const real &h,
                                                 const BoxType &_box)
{

    real triangle_reference_area = pymemb::compute_area_triangle_from_metric(g_reference);
    //     _                                         _     _                     _     _      _
    //    |   g_reference_inv[0]  g_reference_inv[1]  |   |   g_now[0]  g_now[1]  |   |  1  0  |
    // F = |                                           | x |                       | - |        |
    //    |_  g_reference_inv[1]  g_reference_inv[2] _|   |_  g_now[1]  g_now[2] _|   |_ 0  1 _|
    real F11 = g_reference_inv[0] * g_now[0] + g_reference_inv[1] * g_now[1] - 1.0;
    real F12 = g_reference_inv[0] * g_now[1] + g_reference_inv[1] * g_now[2];
    real F21 = g_reference_inv[1] * g_now[0] + g_reference_inv[2] * g_now[1];
    real F22 = g_reference_inv[1] * g_now[1] + g_reference_inv[2] * g_now[2] - 1.0;

    /*----------------------------------------------------------------------------------------------------------------*/
    /*-----------------------------------           FORCE MATRIX        ----------------------------------------------*/
    /*----------------------------------------------------------------------------------------------------------------*/
    real c1 = 0.25 * Y * h * triangle_reference_area / (1.0 - nu * nu);
    real c2 = F11 + nu * F22;
    real c3 = F22 + nu * F11;
    real c4 = (1.0 - nu);
    real c5 = F21;
    real c6 = F12;

    real alpha11 = g_reference_inv[0];
    real alpha12 = g_reference_inv[1];
    real alpha22 = g_reference_inv[2];

    real3 r12 = pymemb::vector_subtract(r2, r1, _box);
    real3 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;

    // T1
    forceM11.x += c2 * (2.0 * alpha11 * r12.x + alpha12 * r13.x);
    forceM12.x += c2 * (alpha12 * r12.x);
    forceM11.y += c2 * (2.0 * alpha11 * r12.y + alpha12 * r13.y);
    forceM12.y += c2 * (alpha12 * r12.y);
    forceM11.z += c2 * (2.0 * alpha11 * r12.z + alpha12 * r13.z);
    forceM12.z += c2 * (alpha12 * r12.z);

    // T2
    forceM11.x += c3 * (alpha12 * r13.x);
    forceM12.x += c3 * (2.0 * alpha22 * r13.x + alpha12 * r12.x);
    forceM11.y += c3 * (alpha12 * r13.y);
    forceM12.y += c3 * (2.0 * alpha22 * r13.y + alpha12 * r12.y);
    forceM11.z += c3 * (alpha12 * r13.z);
    forceM12.z += c3 * (2.0 * alpha22 * r13.z + alpha12 * r12.z);

    // T3
    forceM11.x += c4 * (c5 * alpha11 * r13.x + c6 * 2.0 * alpha12 * r12.x + c6 * alpha22 * r13.x);
    forceM12.x += c4 * (c5 * 2.0 * alpha12 * r13.x + c5 * alpha11 * r12.x + c6 * alpha22 * r12.x);
    forceM11.y += c4 * (c5 * alpha11 * r13.y + c6 * 2.0 * alpha12 * r12.y + c6 * alpha22 * r13.y);
    forceM12.y += c4 * (c5 * 2.0 * alpha12 * r13.y + c5 * alpha11 * r12.y + c6 * alpha22 * r12.y);
    forceM11.z += c4 * (c5 * alpha11 * r13.z + c6 * 2.0 * alpha12 * r12.z + c6 * alpha22 * r13.z);
    forceM12.z += c4 * (c5 * 2.0 * alpha12 * r13.z + c5 * alpha11 * r12.z + c6 * alpha22 * r12.z);

    // T4
    forceM11.x *= c1;
    forceM12.x *= c1;
    forceM11.y *= c1;
    forceM12.y *= c1;
    forceM11.z *= c1;
    forceM12.z *= c1;

    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 ComputeVertexCauchyGreenForce_fn(const int Numfaces,
                                      HE_VertexProp *vertices,
                                      HE_FaceProp *faces,
                                      const real *__restrict__ _Y,
                                      const real *__restrict__ _nu,
                                      const real *__restrict__ _h,
                                      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 Ydev = _Y[type];
        real nudev = _nu[type];
        real hdev = _h[type];

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

        forceMatrix fval = ComputeVertexCauchyGreenForce_lambda(vertices[v1].r, vertices[v2].r, vertices[v3].r, g_now, faces[face_index].g_reference, faces[face_index].g_reference_inv, Ydev, nudev, hdev, _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 ComputeVertexCauchyGreenEnergy::compute(void)
{

    ComputeVertexCauchyGreenForce_fn(_system.Numfaces,
                                     &_system.vertices[0],
                                     &_system.faces[0],
                                     &Y[0],
                                     &nu[0],
                                     &h[0],
                                     _system.get_box());
}

void ComputeVertexCauchyGreenStress_fn(const int Numfaces,
                                       HE_VertexProp *vertices,
                                       HE_FaceProp *faces,
                                       const real *__restrict__ _Y,
                                       const real *__restrict__ _nu,
                                       const real *__restrict__ _h,
                                       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 Ydev = _Y[type];
        real nudev = _nu[type];
        real hdev = _h[type];

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

        forceMatrix fval = ComputeVertexCauchyGreenForce_lambda(vertices[v1].r, vertices[v2].r, vertices[v3].r, g_now, faces[face_index].g_reference, faces[face_index].g_reference_inv, Ydev, nudev, hdev, _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 ComputeVertexCauchyGreenEnergy::compute_stress(void)
{

    ComputeVertexCauchyGreenStress_fn(_system.Numfaces,
                                      &_system.vertices[0],
                                      &_system.faces[0],
                                      &Y[0],
                                      &nu[0],
                                      &h[0],
                                      &_system.stress_group_faces[0],
                                      _system.get_box());
}

void ComputeVertexCauchyGreenStressAtom_fn(const int Numfaces,
                                           HE_VertexProp *vertices,
                                           HE_FaceProp *faces,
                                           const real *__restrict__ _Y,
                                           const real *__restrict__ _nu,
                                           const real *__restrict__ _h,
                                           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 Ydev = _Y[type];
        real nudev = _nu[type];
        real hdev = _h[type];

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

        forceMatrix fval = ComputeVertexCauchyGreenForce_lambda(vertices[v1].r, vertices[v2].r, vertices[v3].r, g_now, faces[face_index].g_reference, faces[face_index].g_reference_inv, Ydev, nudev, hdev, _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 ComputeVertexCauchyGreenEnergy::compute_atomic_stress(void)
{

    ComputeVertexCauchyGreenStressAtom_fn(_system.Numfaces,
                                          &_system.vertices[0],
                                          &_system.faces[0],
                                          &Y[0],
                                          &nu[0],
                                          &h[0],
                                          &_system.stress_virial_atom[0],
                                          _system.get_box());
}