void EdgeMesh::update_edge(const dim3 &cube, const edge &e, int edgeid, bool cb, bool ce, int patchid) { int dir = edgeid >> 2; int ab = edgeid & 3; int ccb = cb ? 1 : 0; int cce = ce ? 1 : 0; int sig = (ccb << 3) | (cce << 2) | patchid; if (dir == 0) xedge(cube + e.beg)[ab] = sig; else if (dir == 1) yedge(cube + e.beg)[ab] = sig; else zedge(cube + e.beg)[ab] = sig; }
MyVertex::Index GetRepVertex_TRI(MyEdge::Index edgeId, Triangle* polygon) { MyEdge& edge = xedge(edgeId); int edgeIndexInFace = -1; for (size_t i = 0; i < polygon->degree(); i++) { if (polygon->edgeId(i) == edgeId) { edgeIndexInFace = i; break; } } assert(edgeIndexInFace != -1); return polygon->vertexId(edgeIndexInFace); }
void calcEdgeIndicatorByExtremity(MyVertex::Index seedId, SSeed& seed, FullIndicatorVector& inds, size_t nMesh) { FullIndicatorVector vInds(nMesh); MyVertex& seedV = xvertex(seedId); for (int i = 0; i < nMesh; i++) vInds[i] = REL_OUTSIDE; // 找到那些on boundary的mesh,通过遍历所有的边上的面,查看它们的meshId for (auto &edgeId : seedV.edges) { MyEdge& eRef = xedge(edgeId); MyVertex& theOther = eRef.theOtherVertex(seedId); if (theOther.isPlaneRep()) continue; // 过滤掉非原始边 auto fItr = MyEdge::ConstFaceIterator(eRef); for (; fItr; ++fItr) { if (fItr.face()->getType() == IPolygon::SUBPOLYGON) continue; // 过滤掉非原始面 vInds[fItr.face()->meshId()] = REL_ON_BOUNDARY; } } // 找到一个包含有效面,且周围面的不共面的边,赋值edgeId // 这里会有隐含的假设:这个极点必须是原始点(应该是对的) bool flag = false; for (auto &edgeId : seedV.edges) { MyEdge& eRef = xedge(edgeId); MyVertex& theOther = eRef.theOtherVertex(seedId); auto fItr = MyEdge::FaceIterator(eRef); if (fItr.face()->getType() == IPolygon::TRIANGLE) { reinterpret_cast<Triangle*>(fItr.face())->calcSupportingPlane(); } XPlane basePlane = fItr.face()->supportingPlane(); flag = false; // 是否有不共面的相邻面 for (; fItr; ++fItr) { if (!fItr.face()->isValid()) continue; if (fItr.face()->getType() == IPolygon::TRIANGLE) { Triangle* pTri = (Triangle*)fItr.face(); pTri->calcSupportingPlane(); } if (!basePlane.coplanar(fItr.face()->supportingPlane())) { seed.edgeId = edgeId; flag = true; break; } } if (flag) break; } assert(flag); assert(xedge(seed.edgeId).ends[0] == seedId || xedge(seed.edgeId).ends[1] == seedId); // 赋值pFace MyEdge& eRef = xedge(seed.edgeId); auto fItr = MyEdge::FaceIterator(eRef); flag = false; for (; fItr; ++fItr) { if (fItr.face()->isValid()) { flag = true; seed.pFace = fItr.face(); break; } } assert(flag); calcEdgeIndicator(seedId, seed.edgeId, vInds, inds); }
void doClassification(Octree* pOctree, CSGTree<RegularMesh>* pCSG, std::vector<RegularMesh*>& meshList, RegularMesh* result, MyVertex::Index seedId) { uint32_t nMesh = meshList.size(); CSGTreeOld* tree = pCSG->auxiliary(); CSGTreeNode** curTreeLeaves = new CSGTreeNode*[nMesh]; SSeed tmpSeed; MyVertex& seedV = xvertex(seedId); tmpSeed.edgeId = *seedV.edges.begin(); MyEdge& seedE = xedge(tmpSeed.edgeId); tmpSeed.eIndicators.reset(new FullIndicatorVector(nMesh)); calcEdgeIndicatorByExtremity(seedId, tmpSeed, *reinterpret_cast<FullIndicatorVector*>(tmpSeed.eIndicators.get()), nMesh); MeshId curMeshId; std::queue<IPolygon*> faceQueue; std::queue<SSeed> intraQueue, interQueue; bool added, inverse; std::pair<uint32_t, uint32_t> inversePair; Relation relation; TestTree dummyForest; std::vector<Relation> relTab(nMesh); std::vector<MyEdge::Index> edges; interQueue.push(tmpSeed); tmpSeed.pFace->mark = SEEDED0; assert(tmpSeed.pFace->isValid()); while (!interQueue.empty()) { SSeed curSeed = interQueue.front(); interQueue.pop(); if (curSeed.pFace->mark == VISITED) continue; assert(intraQueue.empty()); curSeed.pFace->mark = SEEDED1; intraQueue.push(curSeed); curMeshId = curSeed.pFace->meshId(); inverse = meshList[curMeshId]->inverse(); if (inverse) inversePair.first = result->faces().size(); bool seedFlag = true; while (!intraQueue.empty()) { curSeed = intraQueue.front(); intraQueue.pop(); if (curSeed.pFace->mark == VISITED) continue; CSGTreeNode* tree0 = copy2(tree->pRoot, curTreeLeaves); calcFaceIndicator(curSeed, relTab, seedFlag?false:true); if (seedFlag) seedFlag = false; // only for debug use relation = ParsingCSGTree(meshList[curMeshId], relTab.data(), nMesh, tree0, curTreeLeaves, dummyForest); assert(relation != REL_NOT_AVAILABLE || relation != REL_UNKNOWN); added = (relation == REL_SAME); faceQueue.push(curSeed.pFace); while (!faceQueue.empty()) { IPolygon* curFace = faceQueue.front(); faceQueue.pop(); if (curFace->mark == VISITED) continue; curFace->mark = VISITED; if (added) result->faces().push_back(curFace); edges.clear(); curFace->getEdges(edges); assert(edges.size() == curFace->degree()); // flood filling, bfs for (int i = 0; i < curFace->degree(); i++) { MyEdge& curEdge = xedge(edges[i]); MyEdge::FaceIterator fItr(curEdge); if (curEdge.neighbor) { // 但因为共面的存在,有些neigh可能记录的相邻,但不在相邻面当中,这没关系! //assert(curEdge.faceCount() >= 4); // 如果这是一个相交而成的边,那么一定会有超过4个polygon在周围 for (; fItr; ++fItr) { if (!fItr.face()) { XLOG_ERROR << "Edge with less than two neighboring faces."; continue; } if (!fItr.face()->isValid()) continue; tmpSeed.edgeId = edges[i]; tmpSeed.pFace = fItr.face(); for (int i = 0; i < nMesh; i++) { Indicator tmpInd = REL_NOT_AVAILABLE; switch (relTab[i]) { case REL_SAME: case REL_OPPOSITE: tmpInd = REL_ON_BOUNDARY; break; default: tmpInd = relTab[i]; break; } tmpSeed.eIndicators->at(i) = tmpInd; } for (NeighborInfo& nInfo : *curEdge.neighbor) tmpSeed.eIndicators->at(nInfo.neighborMeshId) = REL_ON_BOUNDARY; if (fItr.face()->meshId() == curMeshId) { if (fItr.face()->mark < SEEDED1) { tmpSeed.pFace->mark = SEEDED1; intraQueue.push(tmpSeed); } } else { if (fItr.face()->mark < SEEDED0) { tmpSeed.pFace->mark = SEEDED0; interQueue.push(tmpSeed); } } } } else { for (; fItr; ++fItr) { if (!fItr.face()) { XLOG_ERROR << "Edge with less than two neighboring faces."; continue; } if (!fItr.face()->isValid() || fItr.face()->meshId() != curMeshId) continue; if (fItr.face()->mark < SEEDED2) { faceQueue.push(fItr.face()); fItr.face()->mark = SEEDED2; } } } } } //break; } if (inverse) { inversePair.second = result->faces().size(); result->inverseMap.push_back(inversePair); } //break; } SAFE_DELETE_ARRAY(curTreeLeaves); }
void calcFaceIndicator(SSeed& seed, std::vector<Relation>& relTab, bool hasNeighbor) { MyEdge& edge = xedge(seed.edgeId); IPolygon* polygon = seed.pFace; // copy the relation const size_t nMesh = ((FullIndicatorVector*)seed.eIndicators.get())->getNumber(); for (size_t i = 0; i < nMesh; i++) { relTab[i] = (Relation)seed.eIndicators.get()->at(i); #ifdef XR_DEBUG bool flag = true; if (i != polygon->meshId() && relTab[i] == REL_ON_BOUNDARY) { flag = false; for (auto& neigh : *edge.neighbor) { if (neigh.neighborMeshId == i) { flag = true; break; } } } assert(flag); #endif } relTab[polygon->meshId()] = REL_SAME; assert(!hasNeighbor || edge.neighbor->size()); if (!edge.neighbor || edge.neighbor->empty()) return; // remove repetitive neighborInfo, must before <find repVertex> // because subpolygon use neighborInfo to find a splitPlane if (!edge.noOverlapNeighbor) { edge.noOverlapNeighbor = true; std::set<MeshId> meshSets; std::vector<NeighborInfo> newNeighbor; for (auto &neigh : *edge.neighbor) { if (meshSets.find(neigh.neighborMeshId) == meshSets.end()) { newNeighbor.push_back(neigh); meshSets.insert(neigh.neighborMeshId); } } edge.neighbor->swap(newNeighbor); } // find the represented vertex MyVertex::Index repVertexId; if (seed.pFace->getType() == IPolygon::TRIANGLE) repVertexId = GetRepVertex_TRI(seed.edgeId, (Triangle*)seed.pFace); else repVertexId = GetRepVertex_SPOLY(seed.edgeId, (SubPolygon*)seed.pFace); MyVertex& repVertex = xvertex(repVertexId); // correct the relation for (auto &neigh: *edge.neighbor) { Oriented_side side; if (neigh.neighborMeshId == polygon->meshId()) continue; if (neigh.type == NeighborInfo::Edge) { std::vector<IPolygon*> faces; auto fItr = MyEdge::FaceIterator(xedge(neigh.neighborEdgeId), true); for (; fItr; fItr.incrementToTriangle()) { assert(fItr.face()->getType() == IPolygon::TRIANGLE); faces.push_back(fItr.face()); } BSPTree bsp; XPlane bspPlane; bsp.buildNoCross(faces); side = bsp.classify(repVertex, &bspPlane); relTab[neigh.neighborMeshId] = vRelation2fRelation(side, bspPlane, polygon->supportingPlane()); } else { assert(neigh.type == NeighborInfo::Face); Oriented_side side = orientation(neigh.pTrangle->supportingPlane(), repVertex); relTab[neigh.neighborMeshId] = vRelation2fRelation(side, neigh.pTrangle->supportingPlane(), polygon->supportingPlane()); } } }
MyVertex::Index GetRepVertex_SPOLY(MyEdge::Index edgeId, SubPolygon* polygon) { assert(orientation(polygon->supportingPlane(),(polygon->vertex(0))) == ON_ORIENTED_BOUNDARY); assert(orientation(polygon->supportingPlane(),(polygon->vertex(1))) == ON_ORIENTED_BOUNDARY); assert(orientation(polygon->supportingPlane(),(polygon->vertex(2))) == ON_ORIENTED_BOUNDARY); MyEdge& edge = xedge(edgeId); // find init point int edgeIndexInFace = -1; for (int i = 0; i < polygon->degree(); i++) { if (polygon->edgeId(i) == edgeId) { edgeIndexInFace = i; break; } } assert(edgeIndexInFace != -1); MyVertex::Index vIdInPlane; XPlane boundPlane, tmpPlane; for (int i = 2; i < polygon->degree(); i++) { vIdInPlane = polygon->vertexId((edgeIndexInFace + i) % polygon->degree()); // find a bounding plane bool flag = false; for (auto &neigh : *edge.neighbor) { if (neigh.type == NeighborInfo::Edge) { for (auto fItr = MyEdge::FaceIterator(xedge(neigh.neighborEdgeId), true); fItr; fItr.incrementToTriangle()) { assert(fItr.face()->getType() == IPolygon::TRIANGLE); tmpPlane = ((Triangle*)fItr.face())->supportingPlane(); if (orientation(tmpPlane, xvertex(vIdInPlane)) != ON_ORIENTED_BOUNDARY) { boundPlane = tmpPlane; flag = true; break; } } } else { assert(neigh.type == NeighborInfo::Face); XPlane tmpPlane = neigh.pTrangle->supportingPlane(); if (orientation(tmpPlane, xvertex(vIdInPlane)) != ON_ORIENTED_BOUNDARY) { boundPlane = tmpPlane; break; } } if (flag) break; } if (boundPlane.isValid()) break; } assert(boundPlane.isValid()); // correct the direction of bounding plane XLine edgeLine(polygon->supportingPlane(), boundPlane); assert(!polygon->supportingPlane().idEquals(boundPlane)); int tmpSide = linearOrder(edgeLine, xvertex(polygon->vertexId((edgeIndexInFace + 1) % polygon->degree())), xvertex(polygon->vertexId(edgeIndexInFace))); assert(tmpSide != 0); if (tmpSide < 0) boundPlane.inverse(); // pick a correct rep vertex MyVertex::Index repVertexId = INVALID_UINT32; for (size_t i = 0; i < polygon->degree(); i++) { if (orientation(boundPlane, xvertex(polygon->vertexId(i))) == ON_POSITIVE_SIDE) { repVertexId = polygon->vertexId(i); break; } } assert(repVertexId != INVALID_UINT32); return repVertexId; }
// Right-hand side of the Lax-Wendroff discretization: // // ( q(t+dt) - q(t) )/dt = -F_{x} - G_{y}. // // This routine constructs the 'time-integrated' flux functions F and G using the // Cauchy-Kowalewski procedure. // // First, consider time derivatives of q // // q^{n+1} = q^n + dt * (q^n_t + dt/2 * q^n_tt + dt^3/6 q^n_ttt ). // // Formally, these are given by // // q_{t} = ( -f(q) )_x + ( -g(q) )_y, // q_{tt} = ( f'(q) * ( f_x + g_y )_x + ( g'(q) * ( f_x + g_y )_y // q_{ttt} = ... // // Now, considering Taylor expansions of f and g, centered about t = t^n // // F = f^n + (t-t^n) \dot{f^n} + \cdots // G = g^n + (t-t^n) \dot{g^n} + \cdots // // We have the following form, after integrating in time // // F: = ( f - dt/2 * ( f'(q)*( f_x+g_y ) // + dt^2/6 ( \pd2{f}{q} \cdot (f_x+g_y,f_x+g_y) + // \pd{f}{q} ( f_x + g_y )_t ) + \cdots // // G: = ( g - dt/2 * ( g'(q)*( f_x+g_y ) // + dt^2/6 ( \pd2{g}{q} \cdot (f_x+g_y,f_x+g_y) + // \pd{g}{q} ( f_x + g_y )_t ) + \cdots // // where the final ingredient is // // (f_x+g_y)_t = \pd2{f}{q} \cdot (q_x, f_x+g_y ) + \pd{f}{q} ( f_xx + g_xy ) + // \pd2{g}{q} \cdot (q_y, f_x+g_y ) + \pd{g}{q} ( f_xy + g_yy ). // // At the end of the day, we set // // L(q) := -F_x - G_y. // // See also: ConstructL. void LaxWendroff(double dt, const dTensorBC4& aux, const dTensorBC4& q, // set bndy values modifies these dTensorBC4& Lstar, dTensorBC3& smax) { printf("This call hasn't been tested \n"); if ( !dogParams.get_flux_term() ) { return; } const edge_data& edgeData = Legendre2d::get_edgeData(); const int space_order = dogParams.get_space_order(); const int mx = q.getsize(1); const int my = q.getsize(2); const int meqn = q.getsize(3); const int kmax = q.getsize(4); const int mbc = q.getmbc(); const int maux = aux.getsize(3); // Flux values // // Space-order = number of quadrature points needed for 1D integration // along cell edges. // dTensorBC4 Fm(mx, my, meqn, space_order, mbc); dTensorBC4 Fp(mx, my, meqn, space_order, mbc); dTensorBC4 Gm(mx, my, meqn, space_order, mbc); dTensorBC4 Gp(mx, my, meqn, space_order, mbc); // Flux function void FluxFunc(const dTensor2& xpts, const dTensor2& Q, const dTensor2& Aux, dTensor3& flux); // Jacobian of the flux function: void DFluxFunc(const dTensor2& xpts, const dTensor2& Q, const dTensor2& Aux, dTensor4& Dflux ); // Hessian of the flux function: void D2FluxFunc(const dTensor2& xpts, const dTensor2& Q, const dTensor2& Aux, dTensor5& D2flux ); // Riemann solver that relies on the fact that we already have // f(ql) and f(qr) already computed: double RiemannSolveLxW(const dTensor1& nvec, const dTensor1& xedge, const dTensor1& Ql, const dTensor1& Qr, const dTensor1& Auxl, const dTensor1& Auxr, const dTensor1& ffl, const dTensor1& ffr, dTensor1& Fl, dTensor1& Fr); void LstarExtra(const dTensorBC4*, const dTensorBC4*, dTensorBC4*); void ArtificialViscosity(const dTensorBC4* aux, const dTensorBC4* q, dTensorBC4* Lstar); // Grid information const double xlower = dogParamsCart2.get_xlow(); const double ylower = dogParamsCart2.get_ylow(); const double dx = dogParamsCart2.get_dx(); const double dy = dogParamsCart2.get_dy(); // --------------------------------------------------------------------- // // Boundary data: // --------------------------------------------------------------------- // // TODO - call this routine before calling this function. // void SetBndValues(dTensorBC4& q, dTensorBC4& aux); // SetBndValues(q, aux); // --------------------------------------------------------- // --------------------------------------------------------------------- // // Part 0: Compute the Lax-Wendroff "flux" function: // // Here, we include the extra information about time derivatives. // --------------------------------------------------------------------- // dTensorBC4 F(mx, my, meqn, kmax, mbc); F.setall(0.); dTensorBC4 G(mx, my, meqn, kmax, mbc); G.setall(0.); void L2ProjectLxW( const int mterms, const double alpha, const double beta_dt, const double charlie_dt, const int istart, const int iend, const int jstart, const int jend, const int QuadOrder, const int BasisOrder_auxin, const int BasisOrder_fout, const dTensorBC4* qin, const dTensorBC4* auxin, dTensorBC4* F, dTensorBC4* G, void FluxFunc (const dTensor2& xpts, const dTensor2& Q, const dTensor2& Aux, dTensor3& flux), void DFluxFunc (const dTensor2& xpts, const dTensor2& Q, const dTensor2& aux, dTensor4& Dflux), void D2FluxFunc (const dTensor2& xpts, const dTensor2& Q, const dTensor2& aux, dTensor5& D2flux) ); printf("hello\n"); L2ProjectLxW( 3, 1.0, 0.5*dt, dt*dt/6.0, 1-mbc, mx+mbc, 1-mbc, my+mbc, space_order, space_order, space_order, &q, &aux, &F, &G, &FluxFunc, &DFluxFunc, D2FluxFunc ); // --------------------------------------------------------- // Part I: compute source term // --------------------------------------------------------- if( dogParams.get_source_term() > 0 ) { // eprintf("error: have not implemented source term for LxW solver."); printf("Source term has not been implemented for LxW solver. Terminating program."); exit(1); } Lstar.setall( 0. ); // --------------------------------------------------------- // Part II: compute inter-element interaction fluxes // // N = int( F(q,x,t) * phi_x, x ) / dA // // --------------------------------------------------------- // 1-direction: loop over interior edges and solve Riemann problems dTensor1 nvec(2); nvec.set(1, 1.0e0 ); nvec.set(2, 0.0e0 ); #pragma omp parallel for for (int i=(2-mbc); i<=(mx+mbc); i++) { dTensor1 Ql(meqn), Qr(meqn); dTensor1 ffl(meqn), ffr(meqn); dTensor1 Fl(meqn), Fr(meqn); dTensor1 DFl(meqn), DFr(meqn); dTensor1 Auxl(maux), Auxr(maux); dTensor1 xedge(2); for (int j=(2-mbc); j<=(my+mbc-1); j++) { // ell indexes Riemann point along the edge for (int ell=1; ell<=space_order; ell++) { // Riemann data - q and f (from basis functions/q) for (int m=1; m<=meqn; m++) { Ql.set (m, 0.0 ); Qr.set (m, 0.0 ); ffl.set(m, 0.0 ); ffr.set(m, 0.0 ); for (int k=1; k<=kmax; k++) { // phi_xl( xi=1.0, eta ), phi_xr( xi=-1.0, eta ) Ql.fetch(m) += edgeData.phi_xl->get(ell,k)*q.get(i-1, j, m, k ); Qr.fetch(m) += edgeData.phi_xr->get(ell,k)*q.get(i, j, m, k ); ffl.fetch(m) += edgeData.phi_xl->get(ell,k)*F.get(i-1, j, m, k ); ffr.fetch(m) += edgeData.phi_xr->get(ell,k)*F.get(i, j, m, k ); } } // Riemann data - aux for (int m=1; m<=maux; m++) { Auxl.set(m, 0.0 ); Auxr.set(m, 0.0 ); for (int k=1; k<=kmax; k++) { Auxl.fetch(m) += edgeData.phi_xl->get(ell,k)*aux.get(i-1, j, m, k); Auxr.fetch(m) += edgeData.phi_xr->get(ell,k)*aux.get(i, j, m, k); } } // Solve Riemann problem xedge.set(1, xlower + (double(i)-1.0)*dx ); xedge.set(2, ylower + (double(j)-0.5)*dy ); const double smax_edge = RiemannSolveLxW( nvec, xedge, Ql, Qr, Auxl, Auxr, ffl, ffr, Fl, Fr); smax.set(i-1, j, 1, Max(dy*smax_edge,smax.get(i-1, j, 1)) ); smax.set(i, j, 1, Max(dy*smax_edge,smax.get(i, j, 1)) ); // Construct fluxes for (int m=1; m<=meqn; m++) { Fm.set(i , j, m, ell, Fr.get(m) ); Fp.set(i-1, j, m, ell, Fl.get(m) ); } } } } // 2-direction: loop over interior edges and solve Riemann problems nvec.set(1, 0.0e0 ); nvec.set(2, 1.0e0 ); #pragma omp parallel for for (int i=(2-mbc); i<=(mx+mbc-1); i++) { dTensor1 Ql(meqn), Qr(meqn); dTensor1 Fl(meqn), Fr(meqn); dTensor1 ffl(meqn), ffr(meqn); dTensor1 Auxl(maux),Auxr(maux); dTensor1 xedge(2); for (int j=(2-mbc); j<=(my+mbc); j++) for (int ell=1; ell<=space_order; ell++) { // Riemann data - q for (int m=1; m<=meqn; m++) { Ql.set (m, 0.0 ); Qr.set (m, 0.0 ); ffl.set (m, 0.0 ); ffr.set (m, 0.0 ); for (int k=1; k<=kmax; k++) { Ql.fetch(m) += edgeData.phi_yl->get(ell, k)*q.get(i, j-1, m, k ); Qr.fetch(m) += edgeData.phi_yr->get(ell, k)*q.get(i, j, m, k ); ffl.fetch(m) += edgeData.phi_yl->get(ell, k)*G.get(i, j-1, m, k ); ffr.fetch(m) += edgeData.phi_yr->get(ell, k)*G.get(i, j, m, k ); } } // Riemann data - aux for (int m=1; m<=maux; m++) { Auxl.set(m, 0.0 ); Auxr.set(m, 0.0 ); for (int k=1; k<=kmax; k++) { Auxl.fetch(m) += edgeData.phi_yl->get(ell,k)*aux.get(i,j-1,m,k); Auxr.fetch(m) += edgeData.phi_yr->get(ell,k)*aux.get(i,j,m,k); } } // Solve Riemann problem xedge.set(1, xlower + (double(i)-0.5)*dx ); xedge.set(2, ylower + (double(j)-1.0)*dy ); const double smax_edge = RiemannSolveLxW( nvec, xedge, Ql, Qr, Auxl, Auxr, ffl, ffr, Fl, Fr); smax.set(i, j-1, 2, Max(dx*smax_edge, smax.get(i, j-1, 2)) ); smax.set(i, j, 2, Max(dx*smax_edge, smax.get(i, j, 2)) ); // Construct fluxes for (int m=1; m<=meqn; m++) { Gm.set(i, j, m, ell, Fr.get(m) ); Gp.set(i, j-1, m, ell, Fl.get(m) ); } } } // Compute ``flux differences'' dF and dG const double half_dx_inv = 0.5/dx; const double half_dy_inv = 0.5/dy; const int mlength = Lstar.getsize(3); assert_eq( meqn, mlength ); // Use the four values, Gm, Gp, Fm, Fp to construct the boundary integral: #pragma omp parallel for for (int i=(2-mbc); i<=(mx+mbc-1); i++) for (int j=(2-mbc); j<=(my+mbc-1); j++) for (int m=1; m<=mlength; m++) for (int k=1; k<=kmax; k++) { // 1-direction: dF double F1 = 0.0; double F2 = 0.0; for (int ell=1; ell<=space_order; ell++) { F1 = F1 + edgeData.wght_phi_xr->get(ell,k)*Fm.get(i,j,m,ell); F2 = F2 + edgeData.wght_phi_xl->get(ell,k)*Fp.get(i,j,m,ell); } // 2-direction: dG double G1 = 0.0; double G2 = 0.0; for (int ell=1; ell<=space_order; ell++) { G1 = G1 + edgeData.wght_phi_yr->get(ell,k)*Gm.get(i,j,m,ell); G2 = G2 + edgeData.wght_phi_yl->get(ell,k)*Gp.get(i,j,m,ell); } Lstar.fetch(i,j,m,k) -= (half_dx_inv*(F2-F1) + half_dy_inv*(G2-G1)); } // --------------------------------------------------------- // --------------------------------------------------------- // Part III: compute intra-element contributions // --------------------------------------------------------- // No need to call this if first-order in space if(dogParams.get_space_order()>1) { dTensorBC4 Ltmp( mx, my, meqn, kmax, mbc ); void L2ProjectGradAddLegendre(const int istart, const int iend, const int jstart, const int jend, const int QuadOrder, const dTensorBC4* F, const dTensorBC4* G, dTensorBC4* fout ); L2ProjectGradAddLegendre( 1-mbc, mx+mbc, 1-mbc, my+mbc, space_order, &F, &G, &Lstar ); } // --------------------------------------------------------- // --------------------------------------------------------- // Part IV: add extra contributions to Lstar // --------------------------------------------------------- // Call LstarExtra LstarExtra(&q,&aux,&Lstar); // --------------------------------------------------------- // --------------------------------------------------------- // Part V: artificial viscosity limiter // --------------------------------------------------------- if (dogParams.get_space_order()>1 && dogParams.using_viscosity_limiter()) { ArtificialViscosity(&aux,&q,&Lstar); } // --------------------------------------------------------- }
// Right-hand side for hyperbolic PDE in divergence form // // q_t = -( f(q,x,y,t)_x + g(q,x,y,t)_y ) + Psi(q,x,y,t) // void LaxWendroff_Unst(double dt, const mesh& Mesh, const edge_data_Unst& EdgeData, dTensor3& aux, // SetBndValues modifies ghost cells dTensor3& q, // SetBndValues modifies ghost cells dTensor3& Lstar, dTensor1& smax) { const int NumElems = Mesh.get_NumElems(); const int NumPhysElems = Mesh.get_NumPhysElems(); const int NumEdges = Mesh.get_NumEdges(); const int meqn = q.getsize(2); const int kmax = q.getsize(3); const int maux = aux.getsize(2); const int space_order = dogParams.get_space_order(); dTensor3 EdgeFluxIntegral(NumElems,meqn,kmax); dTensor3 ElemFluxIntegral(NumElems,meqn,kmax); dTensor3 Psi(NumElems,meqn,kmax); // --------------------------------------------------------- // Boundary Conditions SetBndValues_Unst(Mesh, &q, &aux); // --------------------------------------------------------- // --------------------------------------------------------------------- // // Part 0: Compute the Lax-Wendroff "flux" function: // // Here, we include the extra information about time derivatives. // --------------------------------------------------------------------- // dTensor3 F(NumElems, meqn, kmax ); F.setall(0.); dTensor3 G(NumElems, meqn, kmax ); G.setall(0.); L2ProjectLxW_Unst( dogParams.get_time_order(), 1.0, 0.5*dt, dt*dt/6.0, 1, NumElems, space_order, space_order, space_order, space_order, Mesh, &q, &aux, &F, &G, &FluxFunc, &DFluxFunc, &D2FluxFunc ); // --------------------------------------------------------- // Part I: compute source term // --------------------------------------------------------- if ( dogParams.get_source_term()>0 ) { // eprintf("error: have not implemented source term for LxW solver."); printf("Source term has not been implemented for LxW solver. Terminating program."); exit(1); } Lstar.setall(0.); // --------------------------------------------------------- // --------------------------------------------------------- // Part II: compute flux integral on element edges // --------------------------------------------------------- // Loop over all interior edges EdgeFluxIntegral.setall(0.); ElemFluxIntegral.setall(0.); #pragma omp parallel for // Loop over all interior edges for (int i=1; i<=NumEdges; i++) { // Edge coordinates double x1 = Mesh.get_edge(i,1); double y1 = Mesh.get_edge(i,2); double x2 = Mesh.get_edge(i,3); double y2 = Mesh.get_edge(i,4); // Elements on either side of edge int ileft = Mesh.get_eelem(i,1); int iright = Mesh.get_eelem(i,2); double Areal = Mesh.get_area_prim(ileft); double Arear = Mesh.get_area_prim(iright); // Scaled normal to edge dTensor1 nhat(2); nhat.set(1, (y2-y1) ); nhat.set(2, (x1-x2) ); // Variables to store flux integrals along edge dTensor2 Fr_tmp(meqn,dogParams.get_space_order()); dTensor2 Fl_tmp(meqn,dogParams.get_space_order()); // Loop over number of quadrature points along each edge for (int ell=1; ell<=dogParams.get_space_order(); ell++) { dTensor1 Ql(meqn), Qr(meqn); dTensor1 ffl(meqn), ffr(meqn); // << -- NEW PART -- >> dTensor1 Auxl(maux), Auxr(maux); // Riemann data - q for (int m=1; m<=meqn; m++) { Ql.set(m, 0.0 ); Qr.set(m, 0.0 ); // << -- NEW PART, ffl and ffr -- >> // ffl.set(m, 0.0 ); ffr.set(m, 0.0 ); for (int k=1; k<=kmax; k++) { Ql.set(m, Ql.get(m) + EdgeData.phi_left->get(i,ell,k) *q.get(ileft, m,k) ); Qr.set(m, Qr.get(m) + EdgeData.phi_right->get(i,ell,k) *q.get(iright,m,k) ); // << -- NEW PART, ffl and ffr -- >> // // Is this the correct way to use the normal vector? ffl.set(m, ffl.get(m) + EdgeData.phi_left->get (i, ell, k) * ( nhat.get(1)*F.get( ileft, m, k) + nhat.get(2)*G.get( ileft, m, k) ) ); ffr.set(m, ffr.get(m) + EdgeData.phi_right->get(i, ell, k) * ( nhat.get(1)*F.get(iright, m, k) + nhat.get(2)*G.get(iright, m, k) ) ); } } // Riemann data - aux for (int m=1; m<=maux; m++) { Auxl.set(m, 0.0 ); Auxr.set(m, 0.0 ); for (int k=1; k<=kmax; k++) { Auxl.set(m, Auxl.get(m) + EdgeData.phi_left->get(i,ell,k) * aux.get(ileft, m,k) ); Auxr.set(m, Auxr.get(m) + EdgeData.phi_right->get(i,ell,k) * aux.get(iright,m,k) ); } } // Solve Riemann problem dTensor1 xedge(2); double s = EdgeData.xpts1d->get(ell); xedge.set(1, x1 + 0.5*(s+1.0)*(x2-x1) ); xedge.set(2, y1 + 0.5*(s+1.0)*(y2-y1) ); // Solve the Riemann problem for this edge dTensor1 Fl(meqn), Fr(meqn); // Use the time-averaged fluxes to define left and right values for // the Riemann solver. const double smax_edge = RiemannSolveLxW( nhat, xedge, Ql, Qr, Auxl, Auxr, ffl, ffr, Fl, Fr); smax.set(i, Max(smax_edge,smax.get(i)) ); // Construct fluxes for (int m=1; m<=meqn; m++) { Fr_tmp.set(m,ell, Fr.get(m) ); Fl_tmp.set(m,ell, Fl.get(m) ); } } // Add edge integral to line integral around the full element for (int m=1; m<=meqn; m++) for (int k=1; k<=kmax; k++) { double Fl_sum = 0.0; double Fr_sum = 0.0; for (int ell=1; ell<=dogParams.get_space_order(); ell++) { Fl_sum = Fl_sum + 0.5*EdgeData.wgts1d->get(ell) *EdgeData.phi_left->get(i,ell,k) *Fl_tmp.get(m,ell); Fr_sum = Fr_sum + 0.5*EdgeData.wgts1d->get(ell) *EdgeData.phi_right->get(i,ell,k)*Fr_tmp.get(m,ell); } EdgeFluxIntegral.set(ileft, m,k, EdgeFluxIntegral.get(ileft, m,k) + Fl_sum/Areal ); EdgeFluxIntegral.set(iright,m,k, EdgeFluxIntegral.get(iright,m,k) - Fr_sum/Arear ); } } // --------------------------------------------------------- // --------------------------------------------------------- // Part III: compute intra-element contributions // --------------------------------------------------------- if( dogParams.get_space_order() > 1 ) { L2ProjectGradAddLegendre_Unst(1, NumPhysElems, space_order, Mesh, &F, &G, &ElemFluxIntegral ); } // --------------------------------------------------------- // --------------------------------------------------------- // Part IV: construct Lstar // --------------------------------------------------------- if (dogParams.get_source_term()==0) // Without Source Term { #pragma omp parallel for for (int i=1; i<=NumPhysElems; i++) for (int m=1; m<=meqn; m++) for (int k=1; k<=kmax; k++) { double tmp = ElemFluxIntegral.get(i,m,k) - EdgeFluxIntegral.get(i,m,k); Lstar.set(i,m,k, tmp ); } } else // With Source Term { #pragma omp parallel for for (int i=1; i<=NumPhysElems; i++) for (int m=1; m<=meqn; m++) for (int k=1; k<=kmax; k++) { // double tmp = ElemFluxIntegral.get(i,m,k) // - EdgeFluxIntegral.get(i,m,k) // + Psi.get(i,m,k); // Lstar.set(i,m,k, tmp ); printf("Source term has not been implemented for LxW solver. Terminating program."); exit(1); } } // --------------------------------------------------------- // --------------------------------------------------------- // Part V: add extra contributions to Lstar // --------------------------------------------------------- // Call LstarExtra LstarExtra_Unst(Mesh, &q, &aux, &Lstar); // --------------------------------------------------------- // --------------------------------------------------------- // Part VI: artificial viscosity limiter // --------------------------------------------------------- // if (dogParams.get_space_order()>1 && // dogParams.using_viscosity_limiter()) // { ArtificialViscosity(&aux,&q,&Lstar); } // --------------------------------------------------------- }
void ConstructL_Unst( const double t, const dTensor2* vel_vec, const mesh& Mesh, const edge_data_Unst& EdgeData, dTensor3& aux, // SetBndValues_Unst modifies ghost cells dTensor3& q, // SetBndValues_Unst modifies ghost cells dTensor3& Lstar, dTensor1& smax) { const int NumElems = Mesh.get_NumElems(); const int NumPhysElems = Mesh.get_NumPhysElems(); const int NumEdges = Mesh.get_NumEdges(); const int meqn = q.getsize(2); const int kmax = q.getsize(3); const int maux = aux.getsize(2); const int space_order = dogParams.get_space_order(); dTensor3 EdgeFluxIntegral(NumElems,meqn,kmax); dTensor3 ElemFluxIntegral(NumElems,meqn,kmax); dTensor3 Psi(NumElems,meqn,kmax); // --------------------------------------------------------- // Boundary Conditions SetBndValues_Unst(Mesh,&q,&aux); // Positivity limiter void ApplyPosLimiter_Unst(const mesh& Mesh, const dTensor3& aux, dTensor3& q); if( dogParams.using_moment_limiter() ) { ApplyPosLimiter_Unst(Mesh, aux, q); } // --------------------------------------------------------- // --------------------------------------------------------- // Part I: compute flux integral on element edges // --------------------------------------------------------- // Loop over all interior edges and solve Riemann problems // dTensor1 nvec(2); // Loop over all interior edges EdgeFluxIntegral.setall(0.); ElemFluxIntegral.setall(0.); // Loop over all interior edges #pragma omp parallel for for (int i=1; i<=NumEdges; i++) { // Edge coordinates double x1 = Mesh.get_edge(i,1); double y1 = Mesh.get_edge(i,2); double x2 = Mesh.get_edge(i,3); double y2 = Mesh.get_edge(i,4); // Elements on either side of edge int ileft = Mesh.get_eelem(i,1); int iright = Mesh.get_eelem(i,2); double Areal = Mesh.get_area_prim(ileft); double Arear = Mesh.get_area_prim(iright); // Scaled normal to edge dTensor1 nhat(2); nhat.set(1, (y2-y1) ); nhat.set(2, (x1-x2) ); // Variables to store flux integrals along edge dTensor2 Fr_tmp(meqn,dogParams.get_space_order()); dTensor2 Fl_tmp(meqn,dogParams.get_space_order()); // Loop over number of quadrature points along each edge for (int ell=1; ell<=dogParams.get_space_order(); ell++) { dTensor1 Ql(meqn),Qr(meqn); dTensor1 Auxl(maux),Auxr(maux); // Riemann data - q for (int m=1; m<=meqn; m++) { Ql.set(m, 0.0 ); Qr.set(m, 0.0 ); for (int k=1; k<=kmax; k++) { Ql.set(m, Ql.get(m) + EdgeData.phi_left->get(i,ell,k) *q.get(ileft, m,k) ); Qr.set(m, Qr.get(m) + EdgeData.phi_right->get(i,ell,k) *q.get(iright,m,k) ); } } // Riemann data - aux for (int m=1; m<=maux; m++) { Auxl.set(m, 0.0 ); Auxr.set(m, 0.0 ); for (int k=1; k<=kmax; k++) { Auxl.set(m, Auxl.get(m) + EdgeData.phi_left->get(i,ell,k) *aux.get(ileft, m,k) ); Auxr.set(m, Auxr.get(m) + EdgeData.phi_right->get(i,ell,k) *aux.get(iright,m,k) ); } } // Solve Riemann problem dTensor1 xedge(2); double s = EdgeData.xpts1d->get(ell); xedge.set(1, x1 + 0.5*(s+1.0)*(x2-x1) ); xedge.set(2, y1 + 0.5*(s+1.0)*(y2-y1) ); dTensor1 Fl(meqn),Fr(meqn); const double smax_edge = RiemannSolve(vel_vec, nhat, xedge, Ql, Qr, Auxl, Auxr, Fl, Fr); smax.set(i, Max(smax_edge,smax.get(i)) ); // Construct fluxes for (int m=1; m<=meqn; m++) { Fr_tmp.set(m,ell, Fr.get(m) ); Fl_tmp.set(m,ell, Fl.get(m) ); } } // Add edge integral to line integral around the full element for (int m=1; m<=meqn; m++) for (int k=1; k<=kmax; k++) { double Fl_sum = 0.0; double Fr_sum = 0.0; for (int ell=1; ell<=dogParams.get_space_order(); ell++) { Fl_sum = Fl_sum + 0.5*EdgeData.wgts1d->get(ell) *EdgeData.phi_left->get(i,ell,k) *Fl_tmp.get(m,ell); Fr_sum = Fr_sum + 0.5*EdgeData.wgts1d->get(ell) *EdgeData.phi_right->get(i,ell,k)*Fr_tmp.get(m,ell); } EdgeFluxIntegral.set(ileft, m,k, EdgeFluxIntegral.get(ileft, m,k) + Fl_sum/Areal ); EdgeFluxIntegral.set(iright,m,k, EdgeFluxIntegral.get(iright,m,k) - Fr_sum/Arear ); } } // --------------------------------------------------------- // --------------------------------------------------------- // Part II: compute intra-element contributions // --------------------------------------------------------- L2ProjectGrad_Unst(vel_vec, 1,NumPhysElems, space_order,space_order,space_order,space_order, Mesh,&q,&aux,&ElemFluxIntegral,&FluxFunc); // --------------------------------------------------------- // --------------------------------------------------------- // Part III: compute source term // --------------------------------------------------------- if ( dogParams.get_source_term()>0 ) { // Set source term on computational grid // Set values and apply L2-projection L2Project_Unst(t, vel_vec, 1,NumPhysElems, space_order,space_order,space_order,space_order, Mesh,&q,&aux,&Psi,&SourceTermFunc); } // --------------------------------------------------------- // --------------------------------------------------------- // Part IV: construct Lstar // --------------------------------------------------------- if (dogParams.get_source_term()==0) // Without Source Term { #pragma omp parallel for for (int i=1; i<=NumPhysElems; i++) for (int m=1; m<=meqn; m++) for (int k=1; k<=kmax; k++) { double tmp = ElemFluxIntegral.get(i,m,k) - EdgeFluxIntegral.get(i,m,k); Lstar.set(i,m,k, tmp ); } } else // With Source Term { #pragma omp parallel for for (int i=1; i<=NumPhysElems; i++) for (int m=1; m<=meqn; m++) for (int k=1; k<=kmax; k++) { double tmp = ElemFluxIntegral.get(i,m,k) - EdgeFluxIntegral.get(i,m,k) + Psi.get(i,m,k); Lstar.set(i,m,k, tmp ); } } // --------------------------------------------------------- // --------------------------------------------------------- // Part V: add extra contributions to Lstar // --------------------------------------------------------- // Call LstarExtra LstarExtra_Unst(Mesh,&q,&aux,&Lstar); // --------------------------------------------------------- }