Foam::scalarField Foam::LiquidEvaporation<CloudType>::calcXc
(
    const label cellI
) const
{
    scalarField Xc(this->owner().mcCarrierThermo().Y().size());

    forAll(Xc, i)
    {
        Xc[i] =
            this->owner().mcCarrierThermo().Y()[i][cellI]
           /this->owner().mcCarrierThermo().speciesData()[i].W();
    }

    return Xc/sum(Xc);
}
Beispiel #2
0
// Retriangulate a cavity formed when a constraint edge is inserted, following Shewchuck and Brown.
// The cavity is defined by a counterclockwise list of vertices v[0] to v[m-1] as in Shewchuck and Brown, Figure 5.
static void cavity_delaunay(MutableTriangleTopology& parent_mesh, RawField<const EV,VertexId> X,
                            RawArray<const VertexId> cavity, Random& random) {
  // Since the algorithm generates meshes which may be inconsistent with the outer mesh, and the cavity
  // array may have duplicate vertices, we use a temporary mesh and then copy the triangles over when done.
  // In the temporary, vertices are indexed consecutively from 0 to m-1.
  const int m = cavity.size();
  assert(m >= 3);
  const auto mesh = new_<MutableTriangleTopology>();
  Field<Perturbed2,VertexId> Xc(m,uninit);
  for (const int i : range(m))
    Xc.flat[i] = Perturbed2(cavity[i].id,X[cavity[i]]);
  mesh->add_vertices(m);
  const auto xs = Xc.flat[0],
             xe = Xc.flat[m-1];

  // Set up data structures for prev, next, pi in the paper
  const Field<VertexId,VertexId> prev(m,uninit),
                                 next(m,uninit);
  for (int i=0;i<m-1;i++) {
    next.flat[i] = VertexId(i+1);
    prev.flat[i+1] = VertexId(i);
  }
  const Array<VertexId> pi_(m-2,uninit);
  for (int i=1;i<=m-2;i++)
    pi_[i-1] = VertexId(i);
  #define PI(i) pi_[(i)-1]

  // Randomly shuffle [1,m-2], subject to vertices closer to xs-xe than both their neighbors occurring later
  for (int i=m-2;i>=2;i--) {
    int j;
    for (;;) {
      j = random.uniform<int>(0,i)+1;
      const auto pj = PI(j);
      if (!(   segment_directions_oriented(xe,xs,Xc[pj],Xc[prev[pj]])
            && segment_directions_oriented(xe,xs,Xc[pj],Xc[next[pj]])))
        break;
    }
    swap(PI(i),PI(j));
    // Remove PI(i) from the list
    const auto pi = PI(i);
    next[prev[pi]] = next[pi];
    prev[next[pi]] = prev[pi];
  }

  // Add the first triangle
  mesh->add_face(vec(VertexId(0),PI(1),VertexId(m-1)));

  // Add remaining triangles, flipping to ensure Delaunay
  const Field<bool,VertexId> marked(m);
  Array<HalfedgeId> fan;
  bool used_chew = false;
  for (int i=2;i<m-1;i++) {
    const auto pi = PI(i);
    insert_cavity_vertex(mesh,Xc,marked,pi,next[pi],prev[pi]);
    if (marked[pi]) {
      used_chew = true;
      marked[pi] = false;
      // Retriangulate the fans of triangles that have all three vertices marked
      auto e = mesh->reverse(mesh->halfedge(pi));
      auto v = mesh->src(e);
      bool mv = marked[v];
      marked[v] = false;
      fan.clear();
      do {
        const auto h = mesh->prev(e);
        e = mesh->reverse(mesh->next(e));
        v = mesh->src(e);
        const bool mv2 = marked[v];
        marked[v] = false;
        if (mv) {
          if (mv2)
            fan.append(h);
          if (!mv2 || mesh->is_boundary(e)) {
            chew_fan(mesh,Xc,pi,fan,random);
            fan.clear();
          }
        }
        mv = mv2;
      } while (!mesh->is_boundary(e));
    }
  }
  #undef PI

  // If we ran Chew's algorithm, validate the output.  I haven't tested this
  // case enough to be confident of its correctness.
  if (used_chew)
    assert_delaunay("Failure in extreme special case.  If this triggers, please email [email protected]: ",
                    mesh,Xc,Tuple<>(),false,false);

  // Copy triangles from temporary mesh to real mesh
  for (const auto f : mesh->faces()) {
    const auto v = mesh->vertices(f);
    parent_mesh.add_face(vec(cavity[v.x.id],cavity[v.y.id],cavity[v.z.id]));
  }
}