sandbox/huet/src/lagrangian_caps/bending-ft.h

    Bending force for front-tracking membranes

    #define _BENDING_FT 1
    #ifndef E_B
      #define E_B 1.
    #endif
    #ifndef REF_CURV
      #define REF_CURV 1
    #endif
    #ifndef GLOBAL_REF_CURV
      #if REF_CURV
        #define GLOBAL_REF_CURV 1
      #else
        #define GLOBAL_REF_CURV 0
      #endif
    #endif
    #if GLOBAL_REF_CURV
      #ifndef C0

    c_0/a = -2.09 is the typical reference curvature of a red blood cell.

        #define C0 (-2.09/RADIUS)
      #endif
    #endif
    #ifndef LINEAR_BENDING
      #define LINEAR_BENDING 0
    #endif
    
    #define cot(x) (cos(x)/sin(x))
    
    #include "curvature-ft.h"

    The function below computes the nodal area of node i.

    double compute_node_area(lagMesh* mesh, int i) {
      double area = 0.;
      for(int j=0; j<mesh->nodes[i].nb_triangles; j++) {
        int tid = mesh->nodes[i].triangle_ids[j];
        if (is_obtuse_triangle(mesh, tid)) {
          area += (is_obtuse_node(mesh, tid, i)) ? mesh->triangles[tid].area/2 :
            mesh->triangles[tid].area/4;
        }
        else {
          double voronoi_area = 0.;
          for(int k=0; k<3; k++) {
            int nid = mesh->triangles[tid].node_ids[k];
            if (nid != i) {
              int eid = -1; // eid for "edge id", connecting i and nid
              for (int l=0; l<3; l++) {
                int teid = mesh->triangles[tid].edge_ids[l]; // temporary edge id
                if ((mesh->edges[teid].node_ids[0] == i ||
                  mesh->edges[teid].node_ids[1] == i) &&
                  (mesh->edges[teid].node_ids[0] == nid ||
                  mesh->edges[teid].node_ids[1] == nid)) eid = teid;
              }
              int onid[2]; // onid for "opposite node ids"
              // find onid[0], onid[1]
              for(int l=0; l<2; l++) {
                // tneid for "triangle neighboring eid"
                int tneid = mesh->edges[eid].triangle_ids[l];
                for(int m=0; m<3; m++)
                  if (mesh->triangles[tneid].node_ids[m] != i &&
                    mesh->triangles[tneid].node_ids[m] != nid)
                    onid[l] = mesh->triangles[tneid].node_ids[m];
              }
              // compute their angle facing the relevant triangle
              double theta[2];
              for(int l=0; l<2; l++) {
                theta[l] = comp_angle(&(mesh->nodes[onid[l]]), &(mesh->nodes[i]),
                  &(mesh->nodes[nid]));
              }
              // compute the squared length of [i:nid]
              double edge_length = 0.;
              foreach_dimension()
                edge_length += sq(GENERAL_1DIST(mesh->nodes[i].pos.x,
                  mesh->nodes[nid].pos.x));
              voronoi_area += (cot(theta[0]) + cot(theta[1]))*edge_length;
            }
          }
          area += voronoi_area/16.;
        }
      }
      return area;
    }
    
    event acceleration (i++) {
      for(int i=0; i<NCAPS; i++) {
        if (CAPS(i).isactive) {
          lagMesh* mesh = &(CAPS(i));
          comp_curvature(mesh);
          for(int j=0; j<mesh->nln; j++) {
            #if (!LINEAR_BENDING)
              double curv = mesh->nodes[j].curv;
              double rcurv = mesh->nodes[i].ref_curv;
              double gcurv = mesh->nodes[j].gcurv;
            #endif
            double lbcurv = laplace_beltrami(mesh, j, true);
            double bending_surface_force = 2*E_B*(lbcurv
              #if (!LINEAR_BENDING)
                + 2*(curv - rcurv)*(sq(curv) - gcurv + rcurv*curv)
              #endif
              );

    We now have to compute the area associated with each node

            double area = compute_node_area(mesh, j);

    The bending force is ready to be added to the Lagrangian force of the considered node.

            foreach_dimension()
              mesh->nodes[j].lagForce.x +=
                mesh->nodes[j].normal.x*bending_surface_force*area;
          }
        }
      }
    }