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); }
// 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])); } }