22 int& sm,
int& sn,
int& si,
int& sj);
28 const std::array<int, 4> &verts);
30bool Reorder2D(
int ori, std::array<int, 2> &s0);
46 aux_e_meshOffsets(orig.aux_e_meshOffsets),
47 aux_f_meshOffsets(orig.aux_f_meshOffsets),
48 aux_e_spaceOffsets(orig.aux_e_spaceOffsets),
49 aux_f_spaceOffsets(orig.aux_f_spaceOffsets),
50 auxEdges(orig.auxEdges),
51 auxFaces(orig.auxFaces),
55void NCNURBSExtension::GetMasterEdgeEntities(
58 const int mid = masterEdgeToId.at(edge);
59 const std::size_t nes = masterEdgeInfo[mid].slaves.size();
60 MFEM_ASSERT(masterEdgeInfo[mid].vertices.size() + 1 == nes,
"");
71 MFEM_ASSERT(masterEdgeInfo[mid].vertices.size() ==
72 masterEdgeInfo[mid].ks.size(),
"");
73 for (std::size_t i=0; i<masterEdgeInfo[mid].vertices.size(); ++i)
75 edgeV.
Append(masterEdgeInfo[mid].vertices[i]);
76 edgeVki.
Append(masterEdgeInfo[mid].ks[i]);
84 for (std::size_t i=0; i<nes; ++i)
86 const int edge_i = slaveEdges[masterEdgeInfo[mid].slaves[i]];
96 const int auxEdge = -1 - edge_i;
97 GetAuxEdgeVertices(auxEdge, sverts);
100 MFEM_ASSERT((sverts[0] == edgeV[i] &&
101 sverts[1] == edgeV[i+1]) ||
102 (sverts[1] == edgeV[i] &&
103 sverts[0] == edgeV[i+1]),
"");
107void NCNURBSExtension::FindAdditionalFacesSA(
108 std::map<std::pair<int, int>,
int> &v2f,
109 std::set<int> &addParentFaces,
110 std::vector<FacePairInfo> &facePairs)
114 if (masterFaces.find(
f) != masterFaces.end())
119 Array<int> edges, ori, verts;
123 MFEM_ASSERT(edges.Size() == 4 && verts.Size() == 4,
"");
129 for (
int p=0;
p<2; ++
p)
131 std::array<int, 2> oppEdges;
132 const int sideEdge0 = edges[1 -
p];
133 bool bothMaster =
true;
134 for (
int s=0; s<2; ++s)
136 oppEdges[s] = edges[
p + 2*s];
138 bool isTrueMasterEdge =
false;
139 if (masterEdges.count(oppEdges[s]) > 0)
141 const int mid = masterEdgeToId.at(oppEdges[s]);
142 if (masterEdgeInfo[mid].slaves.size() != 0) { isTrueMasterEdge =
true; }
145 if (!isTrueMasterEdge) { bothMaster =
false; }
148 if (!bothMaster) {
continue; }
153 std::vector<Array<int>> sideAuxEdges(2);
154 std::vector<Array<int>> sideSlaveEdges(2);
155 for (
int s=0; s<2; ++s)
157 const int mid = masterEdgeToId.at(oppEdges[s]);
158 for (
auto edge : masterEdgeInfo[mid].slaves)
162 sideAuxEdges[s].Append(-1 - edge);
166 sideSlaveEdges[s].Append(edge);
171 const bool hasAux = sideAuxEdges[0].Size() > 0;
172 const bool hasSlave = sideSlaveEdges[0].Size() > 0;
175 if (hasAux || hasSlave)
177 std::vector<Array<int>> edgeV(2);
178 std::vector<Array<int>> edgeE(2);
179 std::vector<Array<int>> edgeVki(2);
181 for (
int s=0; s<2; ++s)
183 GetMasterEdgeEntities(oppEdges[s], edgeV[s], edgeE[s], edgeVki[s]);
188 if (edgeE[0].Size() != edgeE[1].Size()) {
continue; }
190 const int nes = edgeE[0].
Size();
193 bool matching =
true;
194 for (
int i=0; i<nes; ++i)
196 if ((edgeE[0][i] >= 0) != (edgeE[1][i] >= 0))
203 if (!matching) {
continue; }
210 Array<int> sideVerts0;
214 std::array<bool, 2> found{
false,
false};
216 for (
int e=0; e<2; ++e)
218 for (
int s=0; s<2; ++s)
220 ep[s] = edgeV[s][e * (edgeV[s].
Size() - 1)];
222 for (
int i=0; i<2; ++i)
224 if (ep[s] == sideVerts0[i])
232 if (ep == sideVerts0)
238 MFEM_ASSERT(found[0] && found[1],
"");
244 for (
int i=0; i<2; ++i)
246 MFEM_ASSERT(edgeV[i].Size() == nes + 1,
"");
249 for (
int e=0; e<nes; ++e)
251 std::array<int, 4> fverts{edgeV[0][e], edgeV[0][e + 1],
252 edgeV[1][rev ? nes - e - 1 : e + 1],
253 edgeV[1][rev ? nes - e : e]};
256 const int eki = edgeVki[0][e];
257 const int eki1 = edgeVki[0][e + 1];
259 const int e1ki = edgeVki[1][rev ? nes - e : e];
260 const int e1ki1 = edgeVki[1][rev ? nes - e - 1 : e + 1];
269 Array2D<int> fki(4,2);
274 const int eNE = edgeVki[0][edgeVki[0].
Size() - 1];
278 MFEM_ASSERT(edgeV[0][0] == verts[0] ||
279 edgeV[0][edgeV[0].Size() - 1] == verts[0],
281 MFEM_ASSERT(edgeV[1][0] == verts[3] ||
282 edgeV[1][edgeV[0].Size() - 1] == verts[3],
284 MFEM_ASSERT(eNE == fn1,
"");
285 MFEM_ASSERT(edgeVki[1][edgeVki[1].Size() - 1] == fn1,
288 const bool rev0 = edgeV[0][0] != verts[0];
289 fki(0,0) = rev0 ? eNE - eki : eki;
292 fki(1,0) = rev0 ? eNE - eki1 : eki1;
295 if (rev0) { ori_f = -2; }
298 const bool rev1 = edgeV[1][0] != verts[3];
300 fki(2,0) = rev1 ? eNE - e1ki1 : e1ki1;
303 fki(3,0) = rev1 ? eNE - e1ki : e1ki;
306 MFEM_ASSERT(fki(0,0) == fki(3,0) &&
307 fki(1,0) == fki(2,0),
"");
311 MFEM_ASSERT(edgeV[0][0] == verts[1] ||
312 edgeV[0][edgeV[0].Size() - 1] == verts[1],
314 MFEM_ASSERT(edgeV[1][0] == verts[0] ||
315 edgeV[1][edgeV[0].Size() - 1] == verts[0],
317 MFEM_ASSERT(eNE == fn2,
"");
318 MFEM_ASSERT(edgeVki[1][edgeVki[1].Size() - 1] == fn2,
321 const bool rev0 = edgeV[0][0] != verts[1];
323 fki(0,1) = rev0 ? eNE - eki : eki;
326 fki(1,1) = rev0 ? eNE - eki1 : eki1;
338 const bool rev1 = edgeV[1][0] != verts[0];
341 fki(2,1) = rev1 ? fn2 - e1ki1 : e1ki1;
344 fki(3,1) = rev1 ? fn2 - e1ki : e1ki;
346 MFEM_ASSERT(fki(0,1) == fki(3,1) &&
347 fki(1,1) == fki(2,1),
"");
352 auto VertexMinKI = [&fki]()
356 std::array<int, 2> kiMin;
357 for (
int j=0; j<2; ++j)
360 for (
int i=1; i<4; ++i)
362 if (fki(i,j) < kiMin[j]) { kiMin[j] = fki(i,j); }
366 for (
int i=0; i<4; ++i)
368 if (fki(i,0) == kiMin[0] && fki(i,1) == kiMin[1])
370 MFEM_ASSERT(
id == -1,
"");
376 MFEM_ASSERT(
id >= 0,
"");
381 if (edgeE[0][e] >= 0)
383 const bool vPairTopo = v2f.count(vpair) > 0;
384 if (!vPairTopo) {
continue; }
386 const int sface = v2f.at(vpair);
387 addParentFaces.insert(
f);
392 const int vMinID = VertexMinKI();
394 std::array<int, 4> fvertsMasterOrdering;
395 for (
int i=0; i<4; ++i)
399 fvertsMasterOrdering[i] = fverts[(vMinID + i) % 4];
403 fvertsMasterOrdering[i] = fverts[(vMinID + 4 - i) % 4];
408 fvertsMasterOrdering);
410 facePairs.emplace_back(FacePairInfo{fverts[vMinID],
f,
411 SlaveFaceInfo{sface, ori_sface,
412 {fki(vMinID,0), fki(vMinID,1)},
414 fki((vMinID + 2) % 4,0) - fki(vMinID,0),
415 fki((vMinID + 2) % 4,1) - fki(vMinID,1)
420 const int afid = auxv2f.count(vpair) > 0 ?
421 auxv2f.at(vpair) : -1;
423 addParentFaces.insert(
f);
425 const int vMinID = VertexMinKI();
431 std::array<int, 4> fvertsOrdered, afverts;
434 for (
int i=0; i<4; ++i)
436 afverts[i] = auxFaces[afid].v[i];
439 fvertsOrdered[i] = fverts[(vMinID + i) % 4];
443 fvertsOrdered[i] = fverts[(vMinID + 4 - i) % 4];
446 if (fvertsOrdered[i] == afverts[0]) { ori_f2 = i; }
449 MFEM_ASSERT(ori_f2 >= 0,
"");
451 if (fvertsOrdered[(ori_f2 + 1) % 4] != afverts[1])
453 for (
int j=0; j<4; ++j)
455 MFEM_ASSERT(fvertsOrdered[(ori_f2 + 4 - j) % 4]
459 ori_f2 = -1 - ori_f2;
463 for (
int j=0; j<4; ++j)
465 MFEM_ASSERT(fvertsOrdered[(ori_f2 + j) % 4]
470 facePairs.emplace_back(FacePairInfo{fverts[vMinID],
f,
471 SlaveFaceInfo{-1 - afid, ori_f2,
472 {fki(vMinID,0), fki(vMinID,1)},
474 fki((vMinID + 2) % 4,0) - fki(vMinID,0),
475 fki((vMinID + 2) % 4,1) - fki(vMinID,1)
481 const int auxFaceId = auxFaces.size();
484 AuxiliaryFace auxFace;
485 for (
int i=0; i<4; ++i)
489 auxFace.v[i] = fverts[(vMinID + i) % 4];
493 auxFace.v[i] = fverts[(vMinID + 4 - i) % 4];
502 for (
int i=0; i<2; ++i)
504 auxFace.ksi0[i] = fki(vMinID,i);
505 auxFace.ksi1[i] = fki((vMinID + 2) % 4,i);
508 auxv2f[vpair] = auxFaces.size();
509 auxFaces.push_back(auxFace);
511 facePairs.emplace_back(FacePairInfo{fverts[vMinID],
f,
512 SlaveFaceInfo{-1 - auxFaceId, ori_f,
513 {fki(vMinID,0), fki(vMinID,1)},
515 fki((vMinID + 2) % 4,0) - fki(vMinID,0),
516 fki((vMinID + 2) % 4,1) - fki(vMinID,1)
526void NCNURBSExtension::ProcessFacePairs(
int start,
int midStart,
527 const std::vector<std::array<int, 2>> &parentSize,
528 std::vector<int> &parentVerts,
529 const std::vector<FacePairInfo> &facePairs)
531 const int nfpairs = facePairs.size();
533 MFEM_VERIFY(nfpairs > 0 || !is3D,
"");
536 for (
int q=start; q<nfpairs; ++q)
540 const int i = facePairs[q].info.ksi[0];
541 const int j = facePairs[q].info.ksi[1];
542 const int nfe1 = facePairs[q].info.ne[0];
543 const int nfe2 = facePairs[q].info.ne[1];
544 const int v0 = facePairs[q].v0;
545 const int childFace = facePairs[q].info.index;
546 const int parentFace = facePairs[q].parent;
548 facePairs[q].info.ori;
549 const int mid = masterFaceToId.at(parentFace);
552 if (mid < midStart) {
continue; }
554 MFEM_ASSERT(0 <= i && i < parentSize[mid][0] && 0 <= j &&
555 j < parentSize[mid][1],
"");
558 std::array<int, 4> pv;
559 for (
int k=0; k<4; ++k) { pv[k] = parentVerts[(4*mid) + k]; }
564 if (q > start && midPrev >= 0)
568 std::array<int, 2> s0;
569 masterFaceInfo[midPrev].rev =
Reorder2D(orientation, s0);
570 masterFaceInfo[midPrev].s0 = s0;
577 slaveFaces.emplace_back(SlaveFaceInfo{childFace, cpori, {i, j},
580 const int si = slaveFaces.size() - 1;
581 masterFaceInfo[mid].slaves.push_back(si);
582 masterFaceInfo[mid].slaveCorners.push_back(v0);
583 masterFaceInfo[mid].ne[0] = parentSize[mid][0];
584 masterFaceInfo[mid].ne[1] = parentSize[mid][1];
589 std::array<int, 2> s0;
590 masterFaceInfo[midPrev].rev =
Reorder2D(orientation, s0);
591 masterFaceInfo[midPrev].s0 = s0;
595void NCNURBSExtension::GetAuxEdgeVertices(
int auxEdge, Array<int> &verts)
const
598 for (
int i=0; i<2; ++i) { verts[i] = auxEdges[auxEdge].v[i]; }
601void NCNURBSExtension::GetAuxFaceVertices(
int auxFace, Array<int> &verts)
const
604 for (
int i=0; i<4; ++i) { verts[i] = auxFaces[auxFace].v[i]; }
607void NCNURBSExtension::GetAuxFaceEdges(
int auxFace, Array<int> &edges)
const
611 for (
int i=0; i<4; ++i)
613 for (
int j=0; j<2; ++j) { verts[j] = auxFaces[auxFace].v[(i + j) % 4]; }
616 const std::pair<int, int> edge_v(verts[0], verts[1]);
619 if (v2e.count(edge_v) > 0)
621 edges[i] = v2e.at(edge_v);
625 edges[i] = -1 - auxv2e.at(edge_v);
636 return b[-1 - i + j];
638 else if (i + j <
a.Size())
648int NCNURBSExtension::GetEdgeOffset(
bool dof,
int edge,
int increment)
const
651 dof ? aux_e_spaceOffsets : aux_e_meshOffsets);
654int NCNURBSExtension::GetFaceOffset(
bool dof,
int face,
int increment)
const
657 dof ? aux_f_spaceOffsets : aux_f_meshOffsets);
663 MFEM_ASSERT(masterEdges.count(me) > 0,
"Not a master edge");
664 const int mid = masterEdgeToId.at(me);
666 MFEM_ASSERT(masterEdgeInfo[mid].vertices.size() ==
667 masterEdgeInfo[mid].slaves.size() - 1,
"");
670 const std::size_t nes = masterEdgeInfo[mid].slaves.size();
671 for (std::size_t s=0; s<nes; ++s)
673 const int slaveId = slaveEdges[masterEdgeInfo[mid].slaves[s]];
682 GetAuxEdgeVertices(-1 - slaveId, svert);
685 bool reverse =
false;
688 const int mev = masterEdgeInfo[mid].vertices[std::max((
int) s - 1,0)];
689 MFEM_ASSERT(mev == svert[0] || mev == svert[1],
"");
693 if (svert[0] == mev) { reverse =
true; }
698 if (svert[1] == mev) { reverse =
true; }
702 const int eos = GetEdgeOffset(dof, slaveId, 0);
703 const int eos1 = GetEdgeOffset(dof, slaveId, 1);
704 const int nvs = eos1 - eos;
705 MFEM_ASSERT(nvs >= 0,
"");
710 for (
int j=0; j<nvs; ++j) { sdofs[j] = reverse ? eos1 - 1 - j : eos + j; }
714 if (s < masterEdgeInfo[mid].slaves.size() - 1)
717 dofs.
Append(v_offsets[masterEdgeInfo[mid].vertices[s]]);
723void NURBSPatchMap::SetMasterEdges(
bool dof,
const KnotVector *kv[])
725 edgeMaster.
SetSize(edges.Size());
726 edgeMasterOffset.
SetSize(edges.Size());
730 for (
int i=0; i<edges.Size(); ++i)
733 edgeMasterOffset[i] = mos;
745void NCNURBSExtension::GetFaceOrdering(
int sf,
int n1,
int n2,
int v0,
746 int e1,
int e2, Array<int> &perm)
const
748 perm.SetSize(n1 * n2);
752 Array<int> faceEdges, ori, evert, e2vert, vert;
756 MFEM_ASSERT(evert[0] == v0 || evert[1] == v0,
"");
759 d[0] = (evert[0] == v0);
761 const int v10 = d[0] ? evert[1] : evert[0];
766 for (
int i=0; i<4; ++i)
769 if ((evert[0] == v0 && evert[1] == v10) ||
770 (evert[1] == v0 && evert[0] == v10)) { e0 = i; }
773 MFEM_ASSERT(e0 >= 0,
"");
775 const bool tr = e0 % 2 == 1;
778 MFEM_ASSERT(evert[0] == v10 || evert[1] == v10,
"");
779 d[1] = (evert[0] == v10);
781 const int v11 = d[1] ? evert[1] : evert[0];
784 for (
int i=0; i<4; ++i)
786 if (vert[i] != v0 && vert[i] != v10 && vert[i] != v11) { v01 = vert[i]; }
789 MFEM_ASSERT(v01 >= 0 && v01 == vert.Sum() - v0 - v10 - v11,
"");
792 constexpr char ipair[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
795 int allv[4] = {v0, v10, v11, v01};
797 for (
int i=0; i<4; ++i)
800 for (
int j=0; j<4; ++j)
802 if (vert[j] == allv[i])
808 MFEM_ASSERT(locv[i] >= 0,
"");
811 for (
int i=0; i<2; ++i) { f00[i] = ipair[locv[0]][i]; }
813 const int i0 = f00[0];
814 const int j0 = f00[1];
816 for (
int i=0; i<n1; ++i)
817 for (
int j=0; j<n2; ++j)
825 const int fi = i0 == 0 ? j : n2 - 1 - j;
826 const int fj = j0 == 0 ? i : n1 - 1 - i;
827 const int p = fi + (fj * n2);
828 const int m = i + (j * n1);
833 const int fi = i0 == 0 ? i : n1 - 1 - i;
834 const int fj = j0 == 0 ? j : n2 - 1 - j;
835 const int p = fi + (fj * n1);
836 const int m = i + (j * n1);
845 const bool consistent = e == -1 || e == v;
854 const int m =
a.NumRows();
855 const int n =
a.NumCols();
859 const int s0 = i0 == 0 ? 1 : -1;
860 const int s1 = j0 == 0 ? 1 : -1;
861 for (
int i=0; i<m; ++i)
863 const int ia = (i0 * (m - 1)) + (s0 * i);
864 for (
int j=0; j<n; ++j)
866 const int ja = (j0 * (n - 1)) + (s1 * j);
875 const int oriAbs = ori < 0 ? -1 - ori : ori;
877 for (
int i=0; i<4; ++i)
881 perm[i] = (oriAbs - i + 4) % 4;
885 perm[i] = (ori + i) % 4;
891void NURBSPatchMap::SetMasterFaces(
bool dof)
899 int mos = masterDofs.
Size();
900 for (
int i=0; i<faces.
Size(); ++i)
903 faceMasterOffset[i] = mos;
905 if (!faceMaster[i]) {
continue; }
909 if (mdof.NumRows() == 0)
911 faceMaster[i] =
false;
915 for (
int j=0; j<mdof.NumCols(); ++j)
916 for (
int k=0; k<mdof.NumRows(); ++k)
918 masterDofs.
Append(mdof(k,j));
921 mos += mdof.NumRows() * mdof.NumCols();
928 const int mid = masterFaceToId.at(mf);
929 const bool rev = masterFaceInfo[mid].rev;
930 const int s0i = masterFaceInfo[mid].s0[0];
931 const int s0j = masterFaceInfo[mid].s0[1];
932 const int n1orig = masterFaceInfo[mid].ne[0];
933 const int n2orig = masterFaceInfo[mid].ne[1];
936 if (n1orig == 0 && n2orig == 0) {
return; }
938 const int n1 = rev ? n2orig : n1orig;
939 const int n2 = rev ? n1orig : n2orig;
941 MFEM_ASSERT((n1 > 1 || n2 > 1) &&
942 n1 * n2 >= (
int) masterFaceInfo[mid].slaves.size(),
943 "Inconsistent number of faces");
946 for (
auto slaveId : masterFaceInfo[mid].slaves)
948 fcnt += slaveFaces[slaveId].ne[0] * slaveFaces[slaveId].ne[1];
951 MFEM_VERIFY(fcnt == n1 * n2,
"");
952 MFEM_VERIFY((
int) masterFaceInfo[mid].slaveCorners.size() <= n1 * n2,
"");
963 MFEM_ASSERT(medges.
Size() == 4,
"");
977 const int sne1 = (mnf1 - n1 + 1) / n1;
978 const int sne2 = (mnf2 - n2 + 1) / n2;
980 MFEM_ASSERT(sne1 * n1 == mnf1 - n1 + 1,
"");
981 MFEM_ASSERT(sne2 * n2 == mnf2 - n2 + 1,
"");
988 bool consistent =
true;
990 for (std::size_t s=0; s<masterFaceInfo[mid].slaves.size(); ++s)
992 const int sId = masterFaceInfo[mid].slaves[s];
993 const int slaveId = slaveFaces[sId].index;
994 const int v0 = masterFaceInfo[mid].slaveCorners[s];
995 const int ori = slaveFaces[sId].ori;
1000 const int sI = slaveFaces[sId].ksi[0];
1001 const int sJ = slaveFaces[sId].ksi[1];
1002 const int ne1 = slaveFaces[sId].ne[0];
1003 const int ne2 = slaveFaces[sId].ne[1];
1005 const int fos = GetFaceOffset(dof, slaveId, 0);
1006 const int fos1 = GetFaceOffset(dof, slaveId, 1);
1007 const int nvs = fos1 - fos;
1011 const int os1 = (sI * sne1) + sI;
1012 const int os2 = (sJ * sne2) + sJ;
1014 std::array<int, 4> orderedVertices;
1015 std::array<bool, 4> edgeBdry;
1016 std::set<int> vbdry;
1017 int nf1 = 0, nf2 = 0;
1018 auto SetEdgeEntries = [&](
int eidx,
int edge,
const Array<int> &evert,
1021 const bool reverse = (vstart == evert[1]);
1022 const int vend = evert.Sum() - vstart;
1028 for (
auto v : evert) { vbdry.insert(v); }
1031 const bool horizontal = (eidx % 2 == 0);
1032 const int nf_e = horizontal ? nf1 : nf2;
1035 const int eos = GetEdgeOffset(dof, edge, 0);
1037 const int eos1 = GetEdgeOffset(dof, edge, 1);
1039 const bool edgeIsMaster = masterEdges.count(edge) > 0;
1051 MFEM_ASSERT(eos1 - eos == nf_e,
"");
1054 for (
int j=0; j<nf_e; ++j)
1060 MFEM_ASSERT(edofs.
Size() == nf_e,
"");
1062 for (
int j=0; j<nf_e; ++j)
1077 m1 = os1 + nf1 - 1 - j;
1083 m2 = os2 + nf2 - 1 - j;
1087 : edofs[j], mdof(m1, m2)))
1097 const int auxFace = -1 - slaveId;
1102 nf1 = (sne1 * ne1) + ne1 - 1;
1103 nf2 = (sne2 * ne2) + ne2 - 1;
1107 nf1 = auxFaces[auxFace].ksi1[0] - auxFaces[auxFace].ksi0[0] - 1;
1108 nf2 = auxFaces[auxFace].ksi1[1] - auxFaces[auxFace].ksi0[1] - 1;
1111 MFEM_VERIFY(sne1 * ne1 == nf1 - ne1 + 1 &&
1112 sne2 * ne2 == nf2 - ne2 + 1 &&
1113 nvs == nf1 * nf2,
"");
1131 for (
int k=0; k<onf2; ++k)
1132 for (
int j=0; j<onf1; ++j)
1136 const int q = j + (k * onf1);
1146 edgeBdry[0] = sJ == 0;
1147 edgeBdry[2] = sJ + ne2 == n2;
1150 edgeBdry[1] = sI + ne1 == n1;
1151 edgeBdry[3] = sI == 0;
1154 GetAuxFaceEdges(auxFace, faceEdges);
1156 std::array<int, 4> perm;
1160 for (
int eidx=0; eidx<4; ++eidx)
1162 orderedVertices[eidx] = vstart;
1163 MFEM_ASSERT(orderedVertices[eidx] ==
1164 auxFaces[auxFace].v[perm[eidx]],
"");
1165 const int eperm = ori < 0 ? (perm[eidx] - 1 + 4) % 4 : perm[eidx];
1166 const int edge = faceEdges[eperm];
1174 const int auxEdge = -1 - edge;
1175 GetAuxEdgeVertices(auxEdge, evert);
1177 MFEM_ASSERT(evert[0] == vstart || evert[1] == vstart,
"");
1178 SetEdgeEntries(eidx, edge, evert, vstart);
1185 int e1 = -1, e2 = -1;
1187 const int aori = ori < 0 ? -1 - ori : ori;
1222 if (evert.
Find(v0) == -1)
1228 const int idv0 = evert.
Find(v0);
1229 MFEM_ASSERT(idv0 >= 0,
"");
1230 v1 = evert[1 - idv0];
1233 if (evert.
Find(v1) == -1)
1239 MFEM_ASSERT(evert.
Find(v1) >= 0,
"");
1254 MFEM_ASSERT(sne1 * ne1 == nf1 - ne1 + 1,
"");
1255 MFEM_ASSERT(sne2 * ne2 == nf2 - ne2 + 1,
"");
1257 MFEM_ASSERT(nvs == nf1 * nf2,
"");
1263 GetFaceOrdering(slaveId, nf1, nf2, v0, e1, e2, perm);
1265 for (
int k=0; k<nf2; ++k)
1266 for (
int j=0; j<nf1; ++j)
1268 const int q = j + (k * nf1);
1270 mdof(os1 + j, os2 + k)))
1277 std::array<int, 4> edgeOrder{e1, e2, (e1 + 2) % 4, (e2 + 2) % 4};
1280 edgeBdry[0] = sJ == 0;
1281 edgeBdry[2] = sJ + ne2 == n2;
1284 edgeBdry[1] = sI + ne1 == n1;
1285 edgeBdry[3] = sI == 0;
1288 for (
int eidx=0; eidx<4; ++eidx)
1290 orderedVertices[eidx] = vstart;
1291 const int edge = sedges[edgeOrder[eidx]];
1294 SetEdgeEntries(eidx, edge, evert, vstart);
1299 for (
int vidx=0; vidx<4; ++vidx)
1301 const int v = orderedVertices[vidx];
1302 if (vbdry.count(v) == 0)
1347 MFEM_VERIFY(all_set && consistent,
"");
1350int NURBSPatchMap::GetMasterEdgeDof(
const int e,
const int i)
const
1352 const int os = edgeMasterOffset[e];
1353 return masterDofs[os + i];
1356int NURBSPatchMap::GetMasterFaceDof(
const int f,
const int i)
const
1358 const int os = faceMasterOffset[
f];
1359 return masterDofs[os + i];
1362void NCNURBSExtension::ProcessVertexToKnot2D(
const VertexToKnotSpan &v2k,
1363 std::set<int> &reversedParents,
1364 std::vector<EdgePairInfo> &edgePairs)
1369 const int nv2k = v2k.Size();
1371 int prevParent = -1;
1374 for (
int i=0; i<nv2k; ++i)
1377 std::array<int, 2> pv;
1378 v2k.GetVertex2D(i, tv, ks, pv);
1386 const std::pair<int, int> parentPair(pv[0] < pv[1] ? pv[0] : pv[1],
1387 pv[0] < pv[1] ? pv[1] : pv[0]);
1389 MFEM_ASSERT(v2e.count(parentPair) > 0,
"Vertex pair not found");
1390 const int parentEdge = v2e[parentPair];
1391 masterEdges.insert(parentEdge);
1393 const int kv =
KnotInd(parentEdge);
1394 parentToKV[parentPair] = std::array<int, 2> {kv, -1};
1396 const bool rev = pv[1] < pv[0];
1397 if (rev) { reversedParents.insert(parentEdge); }
1402 const bool newParentEdge = (prevParent != parentEdge);
1403 const int v0 = newParentEdge ? pv[0] : prevV;
1405 if (ks == 1) { MFEM_ASSERT(newParentEdge,
""); }
1410 const std::pair<int, int> childPair(v0 < tv ? v0 : tv, v0 < tv ? tv : v0);
1411 const bool childPairTopo = v2e.count(childPair) > 0;
1415 if (auxv2e.count(childPair) == 0)
1418 auxv2e[childPair] = auxEdges.size();
1419 auxEdges.emplace_back(AuxiliaryEdge{pv[0] < pv[1] ?
1420 parentEdge : -1 - parentEdge,
1421 {childPair.first, childPair.second},
1422 {newParentEdge ? 0 : prevKI, ks}});
1426 const int childEdge = childPairTopo ? v2e[childPair] : -1 - auxv2e[childPair];
1432 bool finalVertex = (i == nv2k-1);
1435 int tv_next, ks_next;
1436 std::array<int, 2> pv_next;
1437 v2k.GetVertex2D(i + 1, tv_next, ks_next, pv_next);
1438 if (pv_next[0] != pv[0] || pv_next[1] != pv[1])
1444 edgePairs.emplace_back(tv, ks, childEdge, parentEdge);
1450 const std::pair<int, int> finalChildPair(tv < pv[1] ? tv : pv[1],
1451 tv < pv[1] ? pv[1] : tv);
1452 const bool finalChildPairTopo = v2e.count(finalChildPair) > 0;
1453 if (!finalChildPairTopo)
1456 if (auxv2e.count(finalChildPair) == 0)
1459 auxv2e[finalChildPair] = auxEdges.size();
1462 auxEdges.emplace_back(AuxiliaryEdge{pv[0] < pv[1] ?
1463 -1 - parentEdge : parentEdge,
1464 {finalChildPair.first, finalChildPair.second},
1469 const int finalChildEdge = finalChildPairTopo ? v2e[finalChildPair] :
1470 -1 - auxv2e[finalChildPair];
1471 edgePairs.emplace_back(-1, -1, finalChildEdge, parentEdge);
1476 prevParent = parentEdge;
1480void NCNURBSExtension::ProcessVertexToKnot3D(
1481 const VertexToKnotSpan &v2k,
1482 const std::map<std::pair<int, int>,
int> &v2f,
1483 std::vector<std::array<int, 2>> &parentSize,
1484 std::vector<EdgePairInfo> &edgePairs,
1485 std::vector<FacePairInfo> &facePairs,
1486 std::vector<int> &parentFaces,
1487 std::vector<int> &parentVerts)
1494 const int nv2k = v2k.Size();
1502 int prevParent = -1;
1503 std::vector<int> parentOffset;
1504 std::vector<bool> parentV2Kedge;
1509 for (
int i = 0; i < nv2k; ++i)
1512 std::array<int, 2> ks;
1513 std::array<int, 4> pv;
1514 v2k.GetVertex3D(i, tv, ks, pv);
1519 const int parentFace = v2f.at(parentPair);
1520 const bool newParentFace = (prevParent != parentFace);
1523 parentOffset.push_back(i);
1524 parentFaces.push_back(parentFace);
1528 Array<int> edges, ori, verts;
1532 std::array<int,2> kv = {-1, -1};
1533 for (
int e=0; e<2; ++e)
1536 for (
auto edge : edges)
1540 const bool matching = (evert[0] == pv[e] && evert[1] == pv[e+1]) ||
1541 (evert[1] == pv[e] && evert[0] == pv[e+1]);
1542 if (matching) { kv[e] =
KnotInd(edge); }
1545 MFEM_ASSERT(kv[e] >= 0,
"");
1548 parentToKV[parentPair] = std::array<int, 2> {kv[0], kv[1]};
1559 const int n1range = n1 - n1min;
1560 const int n2range = n2 - n2min;
1561 parentV2Kedge.push_back(n1range == 0 || n2range == 0);
1564 auto getEdgeNE = [&](
int d)
1567 for (
int j=0; j<2; ++j) { ev[j] = pv[j + d]; }
1569 return KnotVecNE(v2e.at(std::pair<int, int>(ev[0], ev[1])));
1571 parentSize.emplace_back(std::array<int, 2> {getEdgeNE(0), getEdgeNE(1)});
1581 n1 = std::max(n1, ks[0]);
1582 n2 = std::max(n2, ks[1]);
1584 n1min = std::min(n1min, ks[0]);
1585 n2min = std::min(n2min, ks[1]);
1588 prevParent = parentFace;
1592 const int n1range = n1 - n1min;
1593 const int n2range = n2 - n2min;
1594 parentV2Kedge.push_back(n1range == 0 || n2range == 0);
1597 const int numParents = parentOffset.size();
1598 parentOffset.push_back(nv2k);
1600 std::set<int> visitedParentEdges;
1601 std::map<int, int> edgePairOS;
1602 bool consistent =
true;
1604 for (
int parent = 0; parent < numParents; ++parent)
1606 const int parentFace = parentFaces[parent];
1609 bool parentEdgeRev[4];
1612 std::array<int, 2> ks;
1613 std::array<int, 4> pv;
1614 v2k.GetVertex3D(parentOffset[parent], tvi, ks, pv);
1619 for (
int i=0; i<4; ++i)
1621 for (
int j=0; j<2; ++j)
1623 ev[j] = pv[(i + j) % 4];
1626 const bool reverse = (ev[1] < ev[0]);
1627 parentEdgeRev[i] = reverse;
1631 const std::pair<int, int> edge_i(ev[0], ev[1]);
1633 const int parentEdge = v2e.at(edge_i);
1634 masterEdges.insert(parentEdge);
1635 parentEdges[i] = parentEdge;
1639 n1 = parentSize[parent][0];
1640 n2 = parentSize[parent][1];
1641 Array2D<int> gridVertex(n1 + 1, n2 + 1);
1644 gridVertex(0,0) = pv[0];
1645 gridVertex(n1,0) = pv[1];
1646 gridVertex(n1,n2) = pv[2];
1647 gridVertex(0,n2) = pv[3];
1649 for (
int i=0; i<4; ++i) { parentVerts.push_back(pv[i]); }
1656 for (
int i = parentOffset[parent]; i < parentOffset[parent + 1]; ++i)
1658 v2k.GetVertex3D(i, tvi, ks, pv);
1659 gridVertex(ks[0], ks[1]) = tvi;
1660 if (i == parentOffset[parent])
1671 r1min = std::min(r1min, ks[0]);
1672 r1max = std::max(r1max, ks[0]);
1674 r2min = std::min(r2min, ks[1]);
1675 r2max = std::max(r2max, ks[1]);
1679 MFEM_ASSERT((r1max - r1min + 1) * (r2max - r2min + 1) >=
1680 parentOffset[parent + 1] - parentOffset[parent],
"");
1682 std::array<int,2> kvi;
1685 const std::pair<int, int> parentPair = v2k.GetVertexParentPair(
1686 parentOffset[parent]);
1687 std::array<int, 2> kv = parentToKV.at(parentPair);
1688 for (
int i=0; i<2; ++i) { kvi[i] = kv[i]; }
1699 n1orig =
kvf[kvi[0]].Size();
1700 n2orig =
kvf[kvi[1]].Size();
1705 MFEM_ASSERT(
kvf[kvi[0]].Sum() == n1 &&
kvf[kvi[1]].Sum() == n2,
"");
1708 std::vector<Array<int>> cgrid(2);
1709 std::array<int,2> n_orig = {n1orig, n2orig};
1710 for (
int dir=0; dir<2; ++dir)
1712 cgrid[dir].SetSize(n_orig[dir] + 1);
1714 for (
int ii = 0; ii < n_orig[dir]; ++ii)
1716 const int iir = parentEdgeRev[dir] ? n_orig[dir] - 1 - ii : ii;
1724 else if (
kvf.size() > 0)
1726 d =
kvf[kvi[dir]][iir];
1729 cgrid[dir][ii + 1] = cgrid[dir][ii] + d;
1733 MFEM_ASSERT(cgrid[0][n_orig[0]] == n1 && cgrid[1][n_orig[1]] == n2,
"");
1736 bool hasSlaveFaces =
false;
1737 bool hasAuxFace =
false;
1739 for (
int ii=0; ii<=n_orig[0]; ++ii)
1741 const int i = cgrid[0][ii];
1742 for (
int jj=0; jj<=n_orig[1]; ++jj)
1744 const int j = cgrid[1][jj];
1745 if (gridVertex(i,j) < 0)
1749 else if (0 < i && i < n1 && 0 < j && j < n2)
1751 hasSlaveFaces =
true;
1756 auto SetFacePairOnGridRange = [&](
int i0,
int i1,
int j0,
int j1)
1758 std::array<int, 4> cv{gridVertex(i0, j0), gridVertex(i1, j0),
1759 gridVertex(i1, j1), gridVertex(i0, j1)};
1763 if (childPair.first < 0) {
return; }
1765 const int d0 = i1 - i0;
1766 const int d1 = j1 - j0;
1768 const bool childPairTopo = v2f.count(childPair) > 0;
1771 const int childFace = v2f.at(childPair);
1775 facePairs.emplace_back(
1776 FacePairInfo{cv[0], parentFace, SlaveFaceInfo{childFace,
1777 ori, {i0, j0}, {d0, d1}}});
1784 const bool bdryParentFace = faceInfo.
IsBoundary();
1786 if (!allset && !bdryParentFace)
1790 if (auxv2f.count(childPair) == 0)
1793 auxv2f[childPair] = auxFaces.size();
1794 AuxiliaryFace auxFace;
1795 for (
int k=0; k<4; ++k) { auxFace.v[k] = cv[k]; }
1797 auxFace.parent = parentFace;
1800 auxFace.ksi0[0] = i0;
1801 auxFace.ksi0[1] = j0;
1802 auxFace.ksi1[0] = i1;
1803 auxFace.ksi1[1] = j1;
1805 auxFaces.push_back(auxFace);
1806 facePairs.emplace_back(
1807 FacePairInfo{cv[0], parentFace,
1808 SlaveFaceInfo{-1 - auxv2f[childPair],
1809 0, {i0, j0}, {d0, d1}}});
1816 for (
int ii=0; ii<n_orig[0]; ++ii)
1818 const int i = cgrid[0][ii];
1819 const int i1 = cgrid[0][ii + 1];
1820 for (
int jj=0; jj<n_orig[1]; ++jj)
1822 const int j = cgrid[1][jj];
1823 const int j1 = cgrid[1][jj + 1];
1824 SetFacePairOnGridRange(i, i1, j, j1);
1829 for (
int dir=1; dir<=2; ++dir)
1831 const int ne = dir == 1 ? n1 : n2;
1832 for (
int s=0; s<2; ++s)
1834 const int parentEdge = parentEdges[dir == 1 ? 2*s : (2*s) + 1];
1835 const bool reverse_p = parentEdgeRev[dir == 1 ? 2*s : (2*s) + 1];
1837 const bool reverse = s == 0 ? reverse_p : !reverse_p;
1838 const bool parentVisited = visitedParentEdges.count(parentEdge) > 0;
1842 edgePairOS[parentEdge] = edgePairs.size();
1843 edgePairs.resize(edgePairs.size() + ne);
1853 for (
int e_orig = 0; e_orig < n_orig[dir-1]; ++e_orig)
1855 const int e_i = os_e;
1856 const int e_orig_rev = reverse ? n_orig[dir-1] - 1 - e_orig : e_orig;
1862 else if (
kvf.size() > 0)
1864 de =
kvf[kvi[dir - 1]][e_orig_rev];
1873 const int i1 = e_i + de;
1876 const int e_idx = reverse ? ne - e_i - de : e_i;
1881 cv[0] = gridVertex(i0,s*n2);
1882 cv[1] = gridVertex(i1,s*n2);
1886 cv[0] = gridVertex((1-s)*n1, i0);
1887 cv[1] = gridVertex((1-s)*n1, i1);
1890 const int cv0 = cv[0];
1902 kiprev = (i0 == 0 || i0 == ne) ? i1 : i0;
1904 tvprev = (i0 == 0 || i0 == ne) ? cv[1] : cv[0];
1906 else if (e_i < ne - 1)
1908 kiprev = (tvprev == cv[0]) ? i1 : i0;
1910 tvprev = (tvprev == cv[0]) ? cv[1] : cv[0];
1924 else if (firstEdge == -1)
1931 tvprev = cv.Sum() - cv0;
1937 const int tv = (e_idx == ne - de) ? -1 : tv_int;
1938 const int tvki = (e_idx == ne - de) ? -1 : (reverse ? ne - ki : ki);
1940 const std::pair<int, int> edge_i(cv[0], cv[1]);
1941 const int childEdge = v2e.at(edge_i);
1943 if (tv == -1) { lagTV =
true; }
1948 edgePairs[edgePairOS[parentEdge] + e_idx].Set(tv, tvki,
1955 const int os = edgePairOS[parentEdge];
1956 if (edgePairs[os + e_idx].child != childEdge ||
1957 edgePairs[os + e_idx].parent != parentEdge)
1964 visitedParentEdges.insert(parentEdge);
1973 std::array<int, 4> gv1 = {0, r1min, r1max, n1};
1974 std::array<int, 4> gv2 = {0, r2min, r2max, n2};
1976 if (hasSlaveFaces && !allset)
1978 for (
int i=0; i<3; ++i)
1979 for (
int j=0; j<3; ++j)
1982 if (i == 1 && j == 1) {
continue; }
1985 if (gv1[i] == gv1[i+1] || gv2[j] == gv2[j+1]) {
continue; }
1988 SetFacePairOnGridRange(gv1[i], gv1[i+1], gv2[j], gv2[j+1]);
1999 for (
int d=0; d<2; ++d)
2001 for (
int i=0; i<3; ++i)
2008 for (
int s=0; s<2; ++s)
2014 const int n_d = d == 0 ? n1 : n2;
2015 for (
int j=1; j<n_d; ++j)
2017 const int tv = d == 0 ? gridVertex(j,s*n2) :
2018 gridVertex((1-s)*n1,j);
2029 rmin = std::min(rmin, j);
2030 rmax = std::max(rmax, j);
2052 const int pid = d == 0 ? 2*s : (2*s) + 1;
2053 const bool reverse_p = parentEdgeRev[pid];
2055 const bool reverse = s == 0 ? reverse_p : !reverse_p;
2059 std::array<int, 2> ki;
2063 cv[0] = gridVertex(gv1[i],s*n2);
2064 cv[1] = gridVertex(gv1[i+1],s*n2);
2071 cv[0] = gridVertex((1-s)*n1,gv2[i]);
2072 cv[1] = gridVertex((1-s)*n1,gv2[i+1]);
2084 const int tv = i == 0 ? cv[1] : cv[0];
2085 const int tvki_f = i == 0 ? ki[1] : ki[0];
2086 const int tvki = reverse ? n_d - tvki_f : tvki_f;
2089 MFEM_ASSERT(cv[0] >= 0,
"");
2091 const std::pair<int, int> childPair(cv[0], cv[1]);
2092 const bool childPairTopo = v2e.count(childPair) > 0;
2095 const int pv0 = d == 0 ? gridVertex(0,s*n2) :
2096 gridVertex((1-s)*n1,0);
2097 const int pv1 = d == 0 ? gridVertex(n1,s*n2) :
2098 gridVertex((1-s)*n1,n2);
2099 const std::pair<int, int> parentPair(pv0 < pv1 ? pv0 : pv1,
2100 pv0 < pv1 ? pv1 : pv0);
2101 const int parentEdge = v2e.at(parentPair);
2102 MFEM_ASSERT(parentEdges[pid] == parentEdge,
"");
2105 if (auxv2e.count(childPair) == 0)
2107 const int knotIndex0 = (d == 0) ? gv1[i] : gv2[i];
2108 const int knotIndex1 = (d == 0) ? gv1[i+1] : gv2[i+1];
2111 auxv2e[childPair] = auxEdges.size();
2112 auxEdges.emplace_back(AuxiliaryEdge{pv0 < pv1 ?
2115 {childPair.first, childPair.second},
2116 {knotIndex0, knotIndex1}});
2119 const bool start = (i == 0 && !reverse) || (i != 0 && reverse);
2121 (start ? 0 :
kvf_coarse[kvi[d]].Size() - 1) : 0;
2125 end_idx = start ? 0 :
kvf[kvi[d]].Size() - 1;
2126 de =
kvf[kvi[d]][end_idx];
2129 const int e_idx_i = i == 0 ? 0 : n_d - de;
2130 const int e_idx = reverse ? n_d - de - e_idx_i : e_idx_i;
2132 const EdgePairInfo ep_e((e_idx == n_d - de) ? -1 : tv,
2133 (e_idx == n_d - de) ? -1 : tvki,
2134 -1 - auxv2e[childPair], parentEdge);
2136 const bool unset = !edgePairs[edgePairOS[parentEdge] + e_idx].isSet;
2139 edgePairs[edgePairOS[parentEdge] + e_idx] = ep_e;
2144 MFEM_ASSERT(edgePairs[edgePairOS[parentEdge] + e_idx] == ep_e,
"");
2149 const int childEdge = v2e.at(childPair);
2151 const int pv0 = d == 0 ? gridVertex(0,s*n2) : gridVertex((1-s)*n1,0);
2152 const int pv1 = d == 0 ? gridVertex(n1,s*n2) : gridVertex((1-s)*n1,n2);
2153 const std::pair<int, int> parentPair(pv0 < pv1 ? pv0 : pv1,
2154 pv0 < pv1 ? pv1 : pv0);
2155 const int parentEdge = v2e.at(parentPair);
2156 MFEM_ASSERT(parentEdges[pid] == parentEdge,
"");
2158 const bool start = (i == 0 && !reverse) || (i != 0 && reverse);
2160 (start ? 0 :
kvf_coarse[kvi[d]].Size() - 1) : 0;
2164 end_idx = start ? 0 :
kvf[kvi[d]].Size() - 1;
2165 de =
kvf[kvi[d]][end_idx];
2168 const int e_idx_i = i == 0 ? 0 : n_d - de;
2169 const int e_idx = reverse ? n_d - de - e_idx_i : e_idx_i;
2171 const int tv_e = (e_idx == n_d - de) ? -1 : tv;
2172 const int tv_ki = (e_idx == n_d - de) ? -1 : tvki;
2174 const EdgePairInfo ep_e(tv_e, tv_ki, childEdge, parentEdge);
2178 !edgePairs[edgePairOS[parentEdge] + e_idx].isSet;
2179 const bool matching =
2180 edgePairs[edgePairOS[parentEdge] + e_idx] == ep_e;
2181 MFEM_ASSERT(unset || matching,
"");
2184 edgePairs[edgePairOS[parentEdge] + e_idx] = ep_e;
2190 if (hasSlaveFaces || hasAuxFace) { masterFaces.insert(parentFace); }
2193 MFEM_VERIFY(consistent,
"");
2196void NCNURBSExtension::GetAuxFaceToPatchTable(Array2D<int> &auxface2patch)
2198 auxface2patch.SetSize(auxFaces.size(), 2);
2200 if (auxFaces.size() == 0) {
return; }
2206 bool consistent =
true;
2210 Array<int> faces, orient;
2214 for (
auto face : faces)
2216 const bool isMaster =
dim == 2 ? masterEdgeToId.count(face) > 0 :
2217 masterFaceToId.count(face) > 0;
2220 const int mid =
dim == 2 ? masterEdgeToId.at(face) :
2221 masterFaceToId.at(face);
2222 const std::vector<int> &slaves =
dim == 2 ? masterEdgeInfo[mid].slaves :
2223 masterFaceInfo[mid].slaves;
2224 for (
auto s : slaves)
2229 const int aux = -1 - s;
2230 if (auxface2patch(aux, 0) >= 0)
2232 if (auxface2patch(aux, 1) != -1) { consistent =
false; }
2233 auxface2patch(aux, 1) =
p;
2237 auxface2patch(aux, 0) =
p;
2245 MFEM_VERIFY(consistent,
"");
2248void NCNURBSExtension::GetSlaveFaceToPatchTable(Array2D<int> &sface2patch)
2251 const int numUnique =
dim == 2 ? slaveEdgesUnique.
Size() :
2252 slaveFacesUnique.
Size();
2253 sface2patch.SetSize(numUnique, 2);
2255 if (numUnique == 0) {
return; }
2259 bool consistent =
true;
2263 Array<int> faces, orient;
2267 for (
auto face : faces)
2269 const bool isMaster =
dim == 2 ? masterEdgeToId.count(face) > 0 :
2270 masterFaceToId.count(face) > 0;
2273 const int mid =
dim == 2 ? masterEdgeToId.at(face) :
2274 masterFaceToId.at(face);
2275 const std::vector<int> &slaves =
dim == 2 ? masterEdgeInfo[mid].slaves :
2276 masterFaceInfo[mid].slaves;
2277 for (
auto id : slaves)
2281 const int s =
dim == 2 ? slaveEdges[id] : slaveFaces[id].index;
2282 const int u =
dim == 2 ? slaveEdgesToUnique[s] :
2283 slaveFacesToUnique[s];
2284 if (sface2patch(
u, 0) >= 0)
2286 if (sface2patch(
u, 1) != -1) { consistent =
false; }
2287 sface2patch(
u, 1) =
p;
2291 sface2patch(
u, 0) =
p;
2299 MFEM_VERIFY(consistent,
"");
2304 const int ne = rf.
Size();
2307 for (
int p=0;
p<k0; ++
p)
2309 const int rp = rev ? ne - 1 -
p :
p;
2314void NCNURBSExtension::UpdateAuxiliaryKnotSpans(
const Array<int> &rf)
2316 for (
auto auxEdge : auxEdges)
2318 const int p = auxEdge.parent;
2319 const int parent =
p < 0 ? -1 -
p :
p;
2320 const int kv =
KnotInd(parent);
2321 for (
int i=0; i<2; ++i)
2327 for (
auto auxFace : auxFaces)
2330 std::array<int, 4> quad;
2332 MFEM_ASSERT(pv.Size() == 4,
"");
2333 for (
int i=0; i<4; ++i) { quad[i] = pv[i]; }
2336 const std::array<int, 2> kv = parentToKV.at(parentPair);
2359 if (filename.empty()) {
return; }
2361 ifstream
f(filename);
2365 for (
int i=0; i<nkv; ++i)
2369 MFEM_ASSERT(nf == 1,
"");
2372 for (
int j=0; j<nf; ++j) {
f >> rf; }
2374 for (
int j=0; j<
kvf[kv].Size(); ++j) {
kvf[kv][j] = rf; }
2380int NCNURBSExtension::AuxiliaryEdgeNE(
int aux_edge)
2382 const int signedParentEdge = auxEdges[aux_edge].parent;
2383 const int ki0 = auxEdges[aux_edge].ksi[0];
2384 const int ki1raw = auxEdges[aux_edge].ksi[1];
2388 const bool rev = signedParentEdge < 0;
2389 const int parentEdge = rev ? -1 - signedParentEdge : signedParentEdge;
2398void NCNURBSExtension::SlaveEdgeToParent(
int se,
int parent,
2399 const Array<int> &os,
2400 const std::vector<int> &parentVerts,
2406 for (
int i=0; i<2; ++i) { sev[i] = auxEdges[-1 - se].v[i]; }
2414 const int nedge = parentVerts.size() + 1;
2415 MFEM_ASSERT((
int) parentVerts.size() + 2 == os.Size(),
"");
2417 Array<int> parentEndpoints;
2421 for (
int i=0; i<nedge; ++i)
2423 const bool first = (i == 0);
2424 const bool last = (i == nedge - 1);
2425 const int v0 = first ? parentEndpoints[0] : parentVerts[i - 1];
2426 const int v1 = last ? parentEndpoints[1] : parentVerts[i];
2427 if (sev[0] == v0 && sev[1] == v1)
2430 MFEM_ASSERT(edges.Size() == os[i + 1] - os[i],
"");
2431 for (
int j=0; j<edges.Size(); ++j) { edges[j] = os[i] + j; }
2433 else if (sev[0] == v1 && sev[1] == v0)
2436 MFEM_ASSERT(edges.Size() == os[i + 1] - os[i],
"");
2437 for (
int j=0; j<edges.Size(); ++j) { edges[j] = os[i + 1] - 1 - j; }
2441 MFEM_VERIFY(found,
"");
2444void NCNURBSExtension::GetMasterEdgePieceOffsets(
int mid, Array<int> &os)
2446 const int np = masterEdgeInfo[mid].slaves.size();
2447 MFEM_VERIFY(np > 0,
"");
2451 for (
int i=0; i<np; ++i)
2453 const int p = masterEdgeInfo[mid].slaves[i];
2454 const int s = slaveEdges[
p];
2462 nes = AuxiliaryEdgeNE(-1 - s);
2465 os[i+1] = os[i] + nes;
2475 for (
int i=0; i<
f; ++i)
2488 constexpr char dirEdges3D[3][4] = {{0, 2, 4, 6}, {1, 3, 5, 7}, {8, 9, 10, 11}};
2489 constexpr char dirEdges2D[2][2] = {{0, 2}, {1, 3}};
2495 const int nedge =
dim == 3 ? 4 : 2;
2499 bool partialChange =
false;
2500 bool consistent =
true;
2502 auto SetFactorsDirection = [&](
int j,
int os_final,
int af,
Array<int> &rf)
2507 rf.SetSize(os_final);
2510 if (rf[j] !=
unsetFactor && af != rf[j]) { consistent =
false; }
2514 auto SetFactorsEdge = [&](
int j,
int rf,
Array<int> &pf)
2517 if (pf[j] !=
unsetFactor && pf[j] != rf) { consistent =
false; }
2521 auto LoopEdgesForDirection = [&](
int d,
Array<int> &rf,
bool first)
2523 for (
int i=0; i<nedge; ++i)
2525 const int edgeIndex =
dim == 3 ? dirEdges3D[d][i] : dirEdges2D[d][i];
2526 const int edge = edges[edgeIndex];
2529 const bool rev =
KnotSign(edge) < 0;
2534 const bool fullSize =
kvf.size() > 0 &&
kvf[kv].Size() == nfe;
2537 if (rf_i.
Size() > 0 && rf.Size() == 0) { rf = rf_i; }
2541 if (
kvf[kv] != rf) { partialChange =
true; }
2548 const int mid = masterEdgeToId.at(edge);
2549 const int numPieces = masterEdgeInfo[mid].slaves.size();
2551 GetMasterEdgePieceOffsets(mid, os);
2553 for (
int piece=0; piece<numPieces; ++piece)
2555 const int e = masterEdgeInfo[mid].slaves[piece];
2556 const int s = slaveEdges[e];
2568 const int aux_edge = -1 - s;
2569 if (auxef[aux_edge].Size() == 0)
2571 auxef[aux_edge].SetSize(AuxiliaryEdgeNE(aux_edge));
2574 parentEdges.
SetSize(auxef[aux_edge].Size());
2575 pf = &auxef[aux_edge];
2578 if (first && parentEdges.
Size() == 0) {
continue; }
2579 SlaveEdgeToParent(s, edge, os, masterEdgeInfo[mid].vertices, parentEdges);
2580 MFEM_ASSERT(parentEdges.
Size() == os[piece + 1] - os[piece],
"");
2582 for (
int j = os[piece]; j < os[piece + 1]; ++j)
2584 const int jj = parentEdges[j - os[piece]];
2585 const int jr = rev ? rf.
Size() - 1 - jj : jj;
2588 SetFactorsDirection(jr, os[numPieces],
2589 (*pf)[j - os[piece]], rf);
2593 SetFactorsEdge(j - os[piece], rf[jr], *pf);
2601 for (
int d=0; d<
dim; ++d)
2605 LoopEdgesForDirection(d, rf,
true);
2606 if (rf.
Size() == 0) {
continue; }
2609 LoopEdgesForDirection(d, rf,
false);
2610 if (rf.
Min() >
unsetFactor) { dirSet +=
static_cast<int>(pow(2, d)); }
2613 MFEM_VERIFY(consistent,
"");
2614 return partialChange ? -1 - dirSet : dirSet;
2622 for (
size_t i=0; i<
kvf.size(); ++i)
2624 kvf[i] = rf_default;
2636 slaveEdgesUnique.
Reserve(slaveEdges.size());
2637 for (
auto s : slaveEdges)
2639 if (slaveEdgesToUnique.count(s) == 0)
2641 slaveEdgesToUnique[s] = slaveEdgesUnique.
Size();
2642 slaveEdgesUnique.
Append(s);
2650 slaveFacesUnique.
Reserve(slaveFaces.size());
2651 for (
auto s : slaveFaces)
2653 if (slaveFacesToUnique.count(s.index) == 0)
2655 slaveFacesToUnique[s.index] = slaveFacesUnique.
Size();
2656 slaveFacesUnique.
Append(s.index);
2666 GetAuxFaceToPatchTable(auxface2patch);
2667 GetSlaveFaceToPatchTable(sface2patch);
2671 auto faceNeighbors = [&](
int p, std::set<int> &nghb)
2676 for (
auto face : faces)
2679 face2elem->
GetRow(face, row);
2681 const bool isSlave =
dim == 2 ? slaveEdgesToUnique.count(
2682 face) > 0 : slaveFacesToUnique.count(face) > 0;
2685 const int u =
dim == 2 ? slaveEdgesToUnique[face] :
2686 slaveFacesToUnique[face];
2687 for (
int i=0; i<2; ++i)
2689 const int elem = sface2patch(
u, i);
2690 if (elem >= 0 && elem !=
p) { nghb.insert(elem); }
2694 for (
auto elem : row) { nghb.insert(elem); }
2698 auto masterFaceNeighbors = [&](
int p, std::set<int> &nghb)
2703 for (
auto face : faces)
2705 const bool isMaster =
dim == 2 ? masterEdgeToId.count(face) > 0 :
2706 masterFaceToId.count(face) > 0;
2709 const int mid =
dim == 2 ? masterEdgeToId.at(face) :
2710 masterFaceToId.at(face);
2711 const std::vector<int> &slaves =
2712 dim == 2 ? masterEdgeInfo[mid].slaves : masterFaceInfo[mid].slaves;
2713 for (
auto s : slaves)
2718 const int aux = -1 - s;
2719 for (
int i=0; i<2; ++i)
2721 const int patch = auxface2patch(aux, i);
2722 if (patch >= 0) { nghb.insert(patch); }
2729 face2elem->
GetRow(s, row);
2730 for (
auto elem : row) { nghb.insert(elem); }
2737 const int npatchall =
patches.Size();
2741 auxef.resize(auxEdges.size());
2743 std::set<int> nextPatches, unchanged;
2744 const int dirAllSet =
dim == 3 ? 7 : 3;
2745 int lastChanged = 0;
2748 while (iter < 100 && !done)
2751 nextPatches.clear();
2752 nextPatches.insert(lastChanged);
2754 std::set<int> visited;
2757 while (nextPatches.size() > 0)
2759 const int p = *nextPatches.begin();
2760 nextPatches.erase(
p);
2765 const bool partialChange = dirSetSigned < 0;
2766 const int dirSet = partialChange ? -1 - dirSetSigned : dirSetSigned;
2767 const bool changed = (patchState[
p] != dirSet) || partialChange;
2768 patchState[
p] = dirSet;
2771 std::set<int> neighbors;
2774 faceNeighbors(
p, neighbors);
2777 masterFaceNeighbors(
p, neighbors);
2783 for (
auto n : neighbors)
2785 if (n < npatchall && n !=
p && patchState[n] != dirAllSet &&
2786 visited.count(n) == 0)
2788 nextPatches.insert(n);
2799 unchanged.insert(
p);
2802 if (unchanged.size() == (size_t) npatchall)
2805 for (
int i=0; i<npatchall; ++i)
2808 const bool partialChange_i = dirSetSigned_i < 0;
2809 const int dirSet_i = partialChange_i ? -1 - dirSetSigned_i :
2811 const bool changed_i = (patchState[i] != dirSet_i) ||
2813 patchState[
p] = dirSet_i;
2822 if (unchanged.size() == (size_t) npatchall)
2831 for (
size_t i=0; i<
kvf.size(); ++i)
2833 if (
kvf[i].Size() == 0)
2836 kvf[i] = rf_default;
2840 for (
int j=0; j<
kvf[i].Size(); ++j)
2854 const int np = pwn.
Size();
2855 const int f =
kvf[i].Size() / pwn.
Sum();
2856 MFEM_ASSERT(
kvf[i].Size() ==
f * pwn.
Sum(),
"");
2860 for (
int j=1; j<np+1; ++j)
2862 const int jp = rev ? np - j : j - 1;
2863 os[j] = os[j-1] + (
f * pwn[jp]);
2867 for (
int j=0; j<np; ++j)
2869 pwf[j] =
kvf[i][os[j]];
2870 for (
int r=os[j]+1; r<os[j+1]; ++r)
2872 MFEM_ASSERT(
kvf[i][r] == pwf[j],
"");
2887 for (
int i=0; i<
f.Size(); ++i)
2889 const int f_i =
f[i];
2890 for (
int j=0; j<f_i; ++j) { rf[os + j] = f_i; }
2895 MFEM_ASSERT(os == rf.
Size(),
"");
2901 const std::string &kvf_filename,
2921void NCNURBSExtension::ReadCoarsePatchCP(std::istream &input)
2930 const int ncp1D = maxOrder + 1;
2931 const int ncp =
static_cast<int>(pow(ncp1D,
Dimension()));
2935 for (
int i=0; i<ncp; ++i)
2939void NCNURBSExtension::PrintCoarsePatches(std::ostream &os)
2946 if (patchCP_size1 == 0) {
return; }
2951 const int ncp1D = maxOrder + 1;
2952 const int ncp =
static_cast<int>(
pow(ncp1D,
Dimension()));
2957 for (
int i=0; i<ncp; ++i)
2971 MFEM_ASSERT(
f.Size() == c.
Sum(),
"");
2972 bool consistent =
true;
2974 for (
int j=0; j<c.
Size(); ++j)
2976 const int cf = c[j];
2977 const int ff =
f[os];
2978 for (
int i=0; i<cf; ++i)
2980 if (
f[os + i] != ff) { consistent =
false; }
2988 MFEM_VERIFY(consistent,
"");
2991void NCNURBSExtension::UpdateCoarseKVF()
3001 const std::array<int, 4> &verts)
3005 MFEM_ASSERT(fverts.
Size() == 4,
"");
3013 for (
int i=0; i<4; ++i) { s1[i] = verts[i]; }
3016 MFEM_ASSERT(s1 == s2,
"");
3021 for (
int i=0; i<4; ++i)
3023 if (verts[i] == fverts[0]) { s = i; }
3027 const bool rev = verts[(s + 1) % 4] != fverts[1];
3028 if (rev) { s = -1 - s; }
3041 const int shift = ori < 0 ? -1 - ori : ori;
3045 const int s0i = (shift == 0 || shift == 3) ? 0 : 1;
3046 const int s0j = (shift < 2) ? 0 : 1;
3053 const int shift1 = ori < 0 ? shift - 1: shift + 1;
3054 const int s1 = (shift1 + 4) % 4;
3055 const int s1i = (s1 == 0 || s1 == 3) ? 0 : 1;
3056 const bool dimReverse = s0i == s1i;
3064 const bool rev = (signedShift < 0);
3065 const int shift = rev ? -1 - signedShift : signedShift;
3066 MFEM_ASSERT(0 <= shift && shift < 4,
"");
3078 else if (shift == 1)
3085 else if (shift == 2)
3109 else if (shift == 1)
3116 else if (shift == 2)
3134 int& sm,
int& sn,
int& si,
int& sj)
3136 const bool rev = (signedShift < 0);
3137 const int shift = rev ? -1 - signedShift : signedShift;
3138 MFEM_ASSERT(0 <= shift && shift < 4,
"");
3156 else if (shift == 1)
3166 else if (shift == 2)
3199 else if (shift == 1)
3209 else if (shift == 2)
3239 const auto qmin = std::min_element(q.begin(), q.end());
3240 const int idmin = std::distance(q.begin(), qmin);
3241 return std::pair<int, int>(q[idmin], q[(idmin + 2) % 4]);
3247 MFEM_ASSERT((
dim == 2 ||
dim == 3) && numVertices > 0,
"Invalid size");
3252 const std::array<int, 2> &pv)
3256 data(
index,2) = pv[0];
3257 data(
index,3) = pv[1];
3261 const std::array<int, 2> &ks,
3262 const std::array<int, 4> &pv)
3265 data(
index,1) = ks[0];
3266 data(
index,2) = ks[1];
3267 data(
index,3) = pv[0];
3268 data(
index,4) = pv[1];
3269 data(
index,5) = pv[2];
3270 data(
index,6) = pv[3];
3280 data(
index,1) = ks[0];
3281 data(
index,2) = ks[1];
3285 std::array<int, 2> &pv)
const
3289 pv[0] = data(
index,2);
3290 pv[1] = data(
index,3);
3294 std::array<int, 4> &pv)
const
3297 ks[0] = data(
index,1);
3298 ks[1] = data(
index,2);
3299 pv[0] = data(
index,3);
3300 pv[1] = data(
index,4);
3301 pv[2] = data(
index,5);
3302 pv[3] = data(
index,6);
3307 const int nv = data.
NumRows();
3310 for (
int i = 0; i < nv; i++)
3313 for (
int j = 1; j < m; j++)
3315 os <<
" " << data(i,j);
3325 std::array<int, 4> pv;
3326 for (
int i=0; i<4; ++i) { pv[i] = data(
index, 3 + i); }
3332 int c0 = data(
index, 2);
3333 int c1 = data(
index, 3);
3334 if (c0 > c1) { std::swap(c0, c1); }
3335 return std::pair<int, int>(c0, c1);
3341 "NURBS NC-patch meshes cannot use this method of refinement");
3356void NCNURBSExtension::Refine(
bool coarsened,
const Array<int> *rf)
3365 std::vector<Array<int>> prf(
dim);
3372 constexpr char e3[3] = {0, 3, 8};
3373 for (
int i=0; i<3; ++i)
3381 MFEM_VERIFY(
dim == 2,
"");
3382 for (
int i=0; i<2; ++i)
3391 for (
int i=0; i<
dim; ++i)
3394 MFEM_VERIFY(prf[i].IsConstant(),
"");
3399 patches[
p]->UpdateSpacingPartitions(pkv);
3400 patches[
p]->UniformRefinement(prf, coarsened, maxOrder);
3404 patches[
p]->UniformRefinement(*rf);
3416void NCNURBSExtension::SetDofToPatch()
3422 if (
dim == 1) {
return; }
3424 Array<int> edges, faces, orient;
3427 for (
int p = 0;
p < np;
p++)
3430 for (
auto e : edges)
3432 if (masterEdges.count(e) > 0)
3436 for (
auto dof : mdof) {
dof2patch[dof] =
p; }
3444 for (
auto f : faces)
3446 if (masterFaces.count(
f) > 0)
3450 for (
int j=0; j<mdof.NumCols(); ++j)
3451 for (
int k=0; k<mdof.NumRows(); ++k)
3464 const int ne = kv->
GetNE();
3467 const int totalEdgeCP = kv->
GetNCP() - 2 - ne + 1;
3468 const int perEdgeCP = totalEdgeCP / ne;
3470 MFEM_VERIFY(perEdgeCP * ne == totalEdgeCP,
"");
3483 std::set<int> reversedParents;
3493 masterEdges.clear();
3494 masterFaces.clear();
3497 masterEdgeToId.clear();
3498 masterFaceToId.clear();
3500 MFEM_VERIFY(nce.
masters.Size() > 0 ||
3502 MFEM_VERIFY(!(nce.
masters.Size() > 0 &&
3505 std::vector<EdgePairInfo> edgePairs;
3506 std::vector<FacePairInfo> facePairs;
3507 std::vector<int> parentFaces, parentVerts;
3508 std::vector<std::array<int, 2>> parentSize;
3510 const bool is3D =
dim == 3;
3512 std::map<std::pair<int, int>,
int> v2f;
3525 v2e[std::pair<int, int> (vert_index[0], vert_index[1])] = edgeID.index;
3535 const int vmin = vert.
Min();
3536 const int idmin = vert.
Find(vmin);
3537 v2f[std::pair<int, int> (vert[idmin], vert[(idmin + 2) % 4])] = i;
3544 ProcessVertexToKnot3D(v2k, v2f, parentSize, edgePairs,
3545 facePairs, parentFaces, parentVerts);
3548 ProcessVertexToKnot2D(v2k, reversedParents, edgePairs);
3552 const int numMasters = is3D ? ncf.
masters.Size() : nce.
masters.Size();
3556 for (
auto masterFace : ncf.
masters)
3558 masterFaces.insert(masterFace.index);
3562 for (
auto masterEdge : nce.
masters)
3564 masterEdges.insert(masterEdge.index);
3567 masterEdgeIndex.
SetSize(masterEdges.size());
3569 for (
auto medge : masterEdges)
3571 masterEdgeIndex[cnt] = medge;
3572 masterEdgeToId[medge] = cnt;
3575 MFEM_VERIFY(cnt == masterEdgeIndex.
Size(),
"");
3577 Array<int> masterFaceIndex(parentFaces.size());
3580 MFEM_VERIFY(masterFaces.size() <= parentFaces.size(),
"");
3583 for (
auto mface : parentFaces)
3585 masterFaceIndex[cnt] = mface;
3586 masterFaceToId[mface] = cnt;
3590 MFEM_VERIFY(cnt == masterFaceIndex.
Size(),
"");
3592 masterEdgeInfo.clear();
3593 masterEdgeInfo.resize(masterEdgeIndex.
Size());
3595 masterFaceInfo.clear();
3596 masterFaceInfo.resize(masterFaceIndex.
Size());
3601 const int npairs = edgePairs.size();
3603 for (
int i=0; i<npairs; ++i)
3605 if (!edgePairs[i].isSet) {
continue; }
3607 const int v = edgePairs[i].v;
3608 const int s = edgePairs[i].child;
3609 const int m = edgePairs[i].parent;
3610 const int ksi = edgePairs[i].ksi;
3612 slaveEdges.push_back(s);
3614 const int mid = masterEdgeToId[m];
3615 const int si = slaveEdges.size() - 1;
3616 masterEdgeInfo[mid].slaves.push_back(si);
3619 masterEdgeInfo[mid].vertices.push_back(v);
3620 masterEdgeInfo[mid].ks.push_back(ksi);
3624 ProcessFacePairs(0, 0, parentSize, parentVerts, facePairs);
3627 for (
int i=0; i<nce.
slaves.Size(); ++i)
3632 slaveEdges.push_back(slaveEdge.
index);
3634 const int mid = masterEdgeToId[slaveEdge.
master];
3635 masterEdgeInfo[mid].slaves.push_back(i);
3640 for (
int m=0; m<numMasters; ++m)
3644 const int numSlaves = masterEdgeInfo[m].slaves.size();
3645 MFEM_ASSERT(numSlaves > 0,
"");
3650 std::vector<int> orderedSlaves(numSlaves);
3654 for (
int s=0; s<numSlaves; ++s)
3658 orderedSlaves[s] = -1;
3659 for (
int t=0; t<numSlaves; ++t)
3661 const int sid = masterEdgeInfo[m].slaves[t];
3662 if (used.count(sid) > 0) {
continue; }
3664 if (svert[0] == vi || svert[1] == vi)
3666 orderedSlaves[s] = sid;
3672 MFEM_ASSERT(orderedSlaves[s] >= 0,
"");
3675 vi = (svert[0] == vi) ? svert[1] : svert[0];
3677 if (s < numSlaves - 1)
3679 masterEdgeInfo[m].vertices.push_back(vi);
3680 masterEdgeInfo[m].ks.push_back(-1);
3684 masterEdgeInfo[m].slaves = orderedSlaves;
3691 std::vector<int> falseMasterEdges;
3692 for (
auto me : masterEdges)
3694 const int mid = masterEdgeToId.at(me);
3695 if (masterEdgeInfo[mid].slaves.size() <= 1)
3697 falseMasterEdges.push_back(me);
3701 for (
auto me : falseMasterEdges) { masterEdges.erase(me); }
3704 const int nfp0 = facePairs.size();
3705 std::set<int> addParentFaces;
3706 FindAdditionalFacesSA(v2f, addParentFaces, facePairs);
3708 cnt = parentFaces.size();
3709 const int npf0 = cnt;
3711 for (
auto pf : addParentFaces)
3713 if (masterFaces.count(pf) == 0)
3715 masterFaces.insert(pf);
3716 masterFaceIndex.
Append(pf);
3718 masterFaceToId[pf] = cnt;
3725 MFEM_ASSERT(edges.
Size() == 4 && verts.
Size() == 4,
"");
3727 parentSize.emplace_back(std::array<int, 2>
3733 masterFaceInfo.push_back(
3737 for (
int i=0; i<4; ++i) { parentVerts.push_back(verts[i]); }
3742 MFEM_VERIFY(cnt == masterFaceIndex.
Size(),
"");
3744 ProcessFacePairs(nfp0, npf0, parentSize, parentVerts, facePairs);
3748 for (
auto rp : reversedParents)
3750 masterEdgeInfo[masterEdgeToId[rp]].Reverse();
3766 for (meshCounter = 0; meshCounter < nv; meshCounter++)
3771 spaceCounter = meshCounter;
3774 for (
int e = 0; e < ne; e++)
3779 if (masterEdges.count(e) == 0)
3786 const int nauxe = auxEdges.size();
3787 aux_e_meshOffsets.
SetSize(nauxe + 1);
3788 aux_e_spaceOffsets.
SetSize(nauxe + 1);
3789 for (
int e = 0; e < nauxe; e++)
3791 aux_e_meshOffsets[e] = meshCounter;
3792 aux_e_spaceOffsets[e] = spaceCounter;
3796 const int signedParentEdge = auxEdges[e].parent;
3797 const int ki0 = auxEdges[e].ksi[0];
3798 const int ki1raw = auxEdges[e].ksi[1];
3799 const bool rev = signedParentEdge < 0;
3800 const int parentEdge = rev ? -1 - signedParentEdge : signedParentEdge;
3802 const int ki1 = ki1raw == -1 ? masterNE : ki1raw;
3804 const int auxne = ki1 - ki0;
3805 MFEM_ASSERT(auxne > 0,
"");
3806 meshCounter += auxne - 1;
3807 spaceCounter += (auxne * perEdgeCP) + auxne - 1;
3810 aux_e_meshOffsets[nauxe] = meshCounter;
3811 aux_e_spaceOffsets[nauxe] = spaceCounter;
3814 for (
int f = 0;
f < nf;
f++)
3819 if (masterFaces.count(
f) == 0)
3832 const int nauxf = auxFaces.size();
3833 aux_f_meshOffsets.
SetSize(nauxf + 1);
3834 aux_f_spaceOffsets.
SetSize(nauxf + 1);
3835 for (
int f = 0;
f < nauxf;
f++)
3837 aux_f_meshOffsets[
f] = meshCounter;
3838 aux_f_spaceOffsets[
f] = spaceCounter;
3840 const int parentFace = auxFaces[
f].parent;
3847 const int auxne0 = auxFaces[
f].ksi1[0] - auxFaces[
f].ksi0[0];
3848 const int auxne1 = auxFaces[
f].ksi1[1] - auxFaces[
f].ksi0[1];
3849 meshCounter += (auxne0 - 1) * (auxne1 - 1);
3850 spaceCounter += ((auxne0 * perEdgeCP0) + auxne0 - 1) *
3851 ((auxne1 * perEdgeCP1) + auxne1 - 1);
3854 aux_f_meshOffsets[nauxf] = meshCounter;
3855 aux_f_spaceOffsets[nauxf] = spaceCounter;
Dynamic 2D array using row-major layout.
T Min() const
Find the minimal element in the array, using the comparison operator < for class T.
void SetSize(int m, int n)
Set the 2D array size to m x n.
int GetSize1() const
Get the 3D array size in the first dimension.
void SetSize(int n1, int n2, int n3)
Set the 3D array size to n1 x n2 x n3.
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
int size
Size of the array.
void Sort()
Sorts the array in ascending order. This requires operator< to be defined for T.
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
T Min() const
Find the minimal element in the array, using the comparison operator < for class T.
int Size() const
Return the logical size of the array.
int Find(const T &el) const
Return the first index where 'el' is found; return -1 if not found.
int Append(const T &el)
Append element 'el' to array, resize if necessary.
T Sum() const
Return the sum of all the array entries using the '+'' operator for class 'T'.
A vector of knots in one dimension, with B-spline basis functions of a prescribed order.
int GetNCP() const
Return the number of control points.
int GetNE() const
Return the number of elements, defined by distinct knots.
void GetFaceEdges(int i, Array< int > &edges, Array< int > &o) const
void LoadNonconformingPatchTopo(std::istream &input, Array< int > &edge_to_ukv)
Read NURBS patch/macro-element mesh (MFEM NURBS NC-patch mesh format)
int GetNEdges() const
Return the number of edges.
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
int GetNFaces() const
Return the number of faces in a 3D mesh.
int GetNE() const
Returns number of elements.
FaceInformation GetFaceInformation(int f) const
void GetElementFaces(int i, Array< int > &faces, Array< int > &ori) const
Return the indices and the orientations of all faces of element i.
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
void GetFaceVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of face i.
NCMesh * ncmesh
Optional nonconforming mesh extension.
void GetElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of element i.
Table * GetFaceToElementTable() const
const VertexToKnotSpan & GetVertexToKnotSpan() const
void GetEdgeVertices(const MeshId &edge_id, int vert_index[2], bool oriented=true) const
Return Mesh vertex indices of an edge identified by 'edge_id'.
const NCList & GetNCList(int entity)
Return vertex/edge/face list (entity = 0/1/2, respectively).
void RefineVertexToKnotSpan(const std::vector< Array< int > > &kvf, const Array< KnotVector * > &kvext, std::map< std::pair< int, int >, std::array< int, 2 > > &parentToKV)
Remap knot-span indices vertex_to_knotspan after refinement.
const NCList & GetEdgeList()
Return the current list of conforming and nonconforming edges.
NCNURBSExtension extends NURBSExtension to support NC-patch NURBS meshes.
void GenerateOffsets() override
Set the mesh and space offsets, and also count the global NumOfVertices and the global NumOfDofs.
NCNURBSExtension(const NCNURBSExtension &orig)
Copy constructor: deep copy.
void GetMasterFaceDofs(bool dof, int mf, Array2D< int > &dofs) const override
Get the DOFs (dof = true) or vertices (dof = false) for master face mf.
bool IsMasterEdge(int edge) const override
Return true if edge is a master NC-patch edge.
void UniformRefinement(const Array< int > &rf) override
void PropagateFactorsForKV(int rf_default)
Ensure consistent refinement factors on all knotvectors.
void RefineWithKVFactors(int rf, const std::string &kvf_filename, bool coarsened) override
void LoadFactorsForKV(const std::string &filename)
Load refinement factors for a list of knotvectors from file.
int SetPatchFactors(int p)
Set consistent refinement factors on patch p.
void GetMasterEdgeDofs(bool dof, int me, Array< int > &dofs) const override
Get the DOFs (dof = true) or vertices (dof = false) for master edge me.
NURBSExtension generally contains multiple NURBSPatch objects spanning an entire Mesh....
std::vector< Array< int > > kvf_coarse
Mesh * patchTopo
Patch topology mesh.
Array< int > ref_factors
Knotvector refinement factors.
Array< int > p_meshOffsets
Array< int > mOrders
Orders of all KnotVectors.
int num_structured_patches
Whether patchTopo is a nonconforming mesh.
Array3D< double > patchCP
Number of structured patches.
static constexpr int unsetFactor
Refinement factors in each dimension.
int KnotInd(int edge) const
Return the unsigned index of the KnotVector for edge edge.
KnotVector * KnotVec(int edge)
DOF to owning patch map in SetSolutionVector()
Array< int > v_meshOffsets
Global mesh offsets, meshOffsets == meshVertexOffsets.
virtual void GetMasterEdgeDofs(bool dof, int me, Array< int > &dofs) const
Get the DOFs (dof = true) or vertices (dof = false) for master edge me.
Array< int > f_spaceOffsets
int NumOfVertices
Global entity counts.
Array< NURBSPatch * > patches
Array of all patches in the mesh.
virtual bool IsMasterEdge(int edge) const
Return true if edge is a master NC-patch edge.
void GetPatchOffsets(int &meshCounter, int &spaceCounter)
Helper function for GenerateOffsets().
void Load(std::istream &input, bool spacing)
Load data from file (used by constructor).
int NumOfKnotVectors
Number of unique (not comprehensive) KnotVectors.
Array< int > edge_to_ukv
Map from patchTopo edge indices to unique KnotVector indices.
std::vector< Array< int > > kvf
Control points for coarse structured patches.
int KnotVecNE(int edge) const
Return the number of knotvector elements for edge edge.
virtual void GetMasterFaceDofs(bool dof, int mf, Array2D< int > &dofs) const
Get the DOFs (dof = true) or vertices (dof = false) for master face mf.
virtual bool IsMasterFace(int face) const
Return true if face is a master NC-patch face.
Array< int > e_meshOffsets
int KnotSign(int edge) const
Return the sign (orientation) of the KnotVector for edge edge.
Array< int > dof2patch
Unset refinement factor value.
int Dimension() const
Return the dimension of the reference space (not physical space).
Array< int > f_meshOffsets
Array< KnotVector * > knotVectors
Set of unique KnotVectors.
Array< int > p_spaceOffsets
Array< int > v_spaceOffsets
Global space offsets, spaceOffsets == dofOffsets.
int GetNE() const
Return the number of active elements.
Array< int > e_spaceOffsets
Piecewise spacing function, with spacing functions defining spacing within arbitarily many fixed subi...
Array< int > RelativePieceSizes() const
void ScalePartition(Array< int > const &f, bool reorient)
Table stores the connectivity of elements of TYPE I to elements of TYPE II. For example,...
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
For a NURBS mesh with nonconforming patch topology, this struct provides a map from hanging vertices ...
void GetVertex3D(int index, int &v, std::array< int, 2 > &ks, std::array< int, 4 > &pv) const
Get the data for a vertex in 3D.
void SetVertex2D(int index, int v, int ks, const std::array< int, 2 > &pv)
Set the data for a vertex in 2D.
void SetVertex3D(int index, int v, const std::array< int, 2 > &ks, const std::array< int, 4 > &pv)
Set the data for a vertex in 3D.
void SetSize(int dimension, int numVertices)
Set the spatial dimension and number of vertices.
void GetVertex2D(int index, int &v, int &ks, std::array< int, 2 > &pv) const
Get the data for a vertex in 2D.
void Print(std::ostream &os) const
Print all the data.
void SetKnotSpans3D(int index, const std::array< int, 2 > &ks)
Set the knot-span indices for a vertex in 3D.
std::pair< int, int > GetVertexParentPair(int index) const
Return the vertex pair representing the parent edge (2D) or face (3D).
int Size() const
Return the number of vertices.
void SetKnotSpan2D(int index, int ks)
Set the knot-span index for a vertex in 2D.
constexpr int dimension
This example only works in 3D. Kernels for 2D are not implemented.
int index(int i, int j, int nx, int ny)
MFEM_HOST_DEVICE T tr(const tensor< T, n, n > &A)
Returns the trace of a square matrix.
MFEM_HOST_DEVICE dual< value_type, gradient_type > pow(dual< value_type, gradient_type > a, dual< value_type, gradient_type > b)
implementation of a (dual) raised to the b (dual) power
int OffsetHelper(int i, int j, const Array< int > &a, const Array< int > &b)
void GetShiftedGridPoints2D(int m, int n, int i, int j, int signedShift, int &sm, int &sn, int &si, int &sj)
real_t u(const Vector &xvec)
void UpdateFactors(Array< int > &f)
int GetNCPperEdge(const KnotVector *kv)
bool ConsistentlySetEntry(int v, int &e)
void ApplyFineToCoarse(const Array< int > &f, Array< int > &c)
void GetInverseShiftedDimensions2D(int signedShift, int sm, int sn, int &m, int &n)
void GetVertexOrdering(int ori, std::array< int, 4 > &perm)
std::pair< int, int > QuadrupleToPair(const std::array< int, 4 > &q)
bool Reorder2D(int ori, std::array< int, 2 > &s0)
void RemapKnotIndex(bool rev, const Array< int > &rf, int &k)
int GetFaceOrientation(const Mesh *mesh, const int face, const std::array< int, 4 > &verts)
std::function< real_t(const Vector &)> f(real_t mass_coeff)
void ReorderArray2D(int i0, int j0, const Array2D< int > &a, Array2D< int > &b)
Array< int > CoarseToFineFactors(const Array< int > &rf)
real_t p(const Vector &x, real_t t)
Lists all edges/faces in the nonconforming mesh.
Array< MeshId > conforming
All MeshIds corresponding to conformal faces.
Array< Slave > slaves
All MeshIds corresponding to slave faces.
Array< Master > masters
All MeshIds corresponding to master faces.
Nonconforming edge/face within a bigger edge/face.
int master
master number (in Mesh numbering)