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]];
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)
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]
463 for (
int j=0; j<4; ++j)
465 MFEM_ASSERT(fvertsOrdered[(ori_f2 + j) % 4]
470 facePairs.emplace_back(FacePairInfo{fverts[vMinID],
f,
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,
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);
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]];
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);
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)))
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];
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;
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] ? parentEdge :
1421 {childPair.first, childPair.second},
1422 {newParentEdge ? 0 : prevKI, ks}});
1426 const int childEdge = childPairTopo ? v2e[childPair] :
1433 bool finalVertex = (i == nv2k-1);
1436 int tv_next, ks_next;
1437 std::array<int, 2> pv_next;
1438 v2k.GetVertex2D(i + 1, tv_next, ks_next, pv_next);
1439 if (pv_next[0] != pv[0] || pv_next[1] != pv[1])
1445 edgePairs.emplace_back(tv, ks, childEdge, parentEdge);
1451 const std::pair<int, int> finalChildPair(tv < pv[1] ? tv : pv[1],
1452 tv < pv[1] ? pv[1] : tv);
1453 const bool finalChildPairTopo = v2e.count(finalChildPair) > 0;
1454 if (!finalChildPairTopo)
1457 if (auxv2e.count(finalChildPair) == 0)
1460 auxv2e[finalChildPair] = auxEdges.size();
1463 auxEdges.emplace_back(AuxiliaryEdge{pv[0] < pv[1] ?
1466 {finalChildPair.first, finalChildPair.second},
1471 const int finalChildEdge = finalChildPairTopo ? v2e[finalChildPair] :
1473 edgePairs.emplace_back(-1, -1, finalChildEdge, parentEdge);
1478 prevParent = parentEdge;
1482void NCNURBSExtension::ProcessVertexToKnot3D(
1483 const VertexToKnotSpan &v2k,
1484 const std::map<std::pair<int, int>,
int> &v2f,
1485 std::vector<std::array<int, 2>> &parentSize,
1486 std::vector<EdgePairInfo> &edgePairs,
1487 std::vector<FacePairInfo> &facePairs,
1488 std::vector<int> &parentFaces,
1489 std::vector<int> &parentVerts)
1496 const int nv2k = v2k.Size();
1504 int prevParent = -1;
1505 std::vector<int> parentOffset;
1506 std::vector<bool> parentV2Kedge;
1511 for (
int i = 0; i < nv2k; ++i)
1514 std::array<int, 2> ks;
1515 std::array<int, 4> pv;
1516 v2k.GetVertex3D(i, tv, ks, pv);
1521 const int parentFace = v2f.at(parentPair);
1522 const bool newParentFace = (prevParent != parentFace);
1525 parentOffset.push_back(i);
1526 parentFaces.push_back(parentFace);
1530 Array<int> edges, ori, verts;
1534 std::array<int,2> kv = {-1, -1};
1535 for (
int e=0; e<2; ++e)
1538 for (
auto edge : edges)
1542 const bool matching = (evert[0] == pv[e] && evert[1] == pv[e+1]) ||
1543 (evert[1] == pv[e] && evert[0] == pv[e+1]);
1544 if (matching) { kv[e] =
KnotInd(edge); }
1547 MFEM_ASSERT(kv[e] >= 0,
"");
1550 parentToKV[parentPair] = std::array<int, 2> {kv[0], kv[1]};
1561 const int n1range = n1 - n1min;
1562 const int n2range = n2 - n2min;
1563 parentV2Kedge.push_back(n1range == 0 || n2range == 0);
1566 auto getEdgeNE = [&](
int d)
1569 for (
int j=0; j<2; ++j) { ev[j] = pv[j + d]; }
1571 return KnotVecNE(v2e.at(std::pair<int, int>(ev[0], ev[1])));
1573 parentSize.emplace_back(std::array<int, 2> {getEdgeNE(0), getEdgeNE(1)});
1583 n1 = std::max(n1, ks[0]);
1584 n2 = std::max(n2, ks[1]);
1586 n1min = std::min(n1min, ks[0]);
1587 n2min = std::min(n2min, ks[1]);
1590 prevParent = parentFace;
1594 const int n1range = n1 - n1min;
1595 const int n2range = n2 - n2min;
1596 parentV2Kedge.push_back(n1range == 0 || n2range == 0);
1599 const int numParents = parentOffset.size();
1600 parentOffset.push_back(nv2k);
1602 std::set<int> visitedParentEdges;
1603 std::map<int, int> edgePairOS;
1604 bool consistent =
true;
1606 for (
int parent = 0; parent < numParents; ++parent)
1608 const int parentFace = parentFaces[parent];
1611 bool parentEdgeRev[4];
1614 std::array<int, 2> ks;
1615 std::array<int, 4> pv;
1616 v2k.GetVertex3D(parentOffset[parent], tvi, ks, pv);
1621 for (
int i=0; i<4; ++i)
1623 for (
int j=0; j<2; ++j)
1625 ev[j] = pv[(i + j) % 4];
1628 const bool reverse = (ev[1] < ev[0]);
1629 parentEdgeRev[i] = reverse;
1633 const std::pair<int, int> edge_i(ev[0], ev[1]);
1635 const int parentEdge = v2e.at(edge_i);
1636 masterEdges.insert(parentEdge);
1637 parentEdges[i] = parentEdge;
1641 n1 = parentSize[parent][0];
1642 n2 = parentSize[parent][1];
1643 Array2D<int> gridVertex(n1 + 1, n2 + 1);
1646 gridVertex(0,0) = pv[0];
1647 gridVertex(n1,0) = pv[1];
1648 gridVertex(n1,n2) = pv[2];
1649 gridVertex(0,n2) = pv[3];
1651 for (
int i=0; i<4; ++i) { parentVerts.push_back(pv[i]); }
1658 for (
int i = parentOffset[parent]; i < parentOffset[parent + 1]; ++i)
1660 v2k.GetVertex3D(i, tvi, ks, pv);
1661 gridVertex(ks[0], ks[1]) = tvi;
1662 if (i == parentOffset[parent])
1673 r1min = std::min(r1min, ks[0]);
1674 r1max = std::max(r1max, ks[0]);
1676 r2min = std::min(r2min, ks[1]);
1677 r2max = std::max(r2max, ks[1]);
1681 MFEM_ASSERT((r1max - r1min + 1) * (r2max - r2min + 1) >=
1682 parentOffset[parent + 1] - parentOffset[parent],
"");
1684 std::array<int,2> kvi;
1687 const std::pair<int, int> parentPair = v2k.GetVertexParentPair(
1688 parentOffset[parent]);
1689 std::array<int, 2> kv = parentToKV.at(parentPair);
1690 for (
int i=0; i<2; ++i) { kvi[i] = kv[i]; }
1701 n1orig =
kvf[kvi[0]].Size();
1702 n2orig =
kvf[kvi[1]].Size();
1707 MFEM_ASSERT(
kvf[kvi[0]].Sum() == n1 &&
kvf[kvi[1]].Sum() == n2,
"");
1710 std::vector<Array<int>> cgrid(2);
1711 std::array<int,2> n_orig = {n1orig, n2orig};
1712 for (
int dir=0; dir<2; ++dir)
1714 cgrid[dir].SetSize(n_orig[dir] + 1);
1716 for (
int ii = 0; ii < n_orig[dir]; ++ii)
1718 const int iir = parentEdgeRev[dir] ? n_orig[dir] - 1 - ii : ii;
1726 else if (
kvf.size() > 0)
1728 d =
kvf[kvi[dir]][iir];
1731 cgrid[dir][ii + 1] = cgrid[dir][ii] + d;
1735 MFEM_ASSERT(cgrid[0][n_orig[0]] == n1 && cgrid[1][n_orig[1]] == n2,
"");
1738 bool hasSlaveFaces =
false;
1739 bool hasAuxFace =
false;
1741 for (
int ii=0; ii<=n_orig[0]; ++ii)
1743 const int i = cgrid[0][ii];
1744 for (
int jj=0; jj<=n_orig[1]; ++jj)
1746 const int j = cgrid[1][jj];
1747 if (gridVertex(i,j) < 0)
1751 else if (0 < i && i < n1 && 0 < j && j < n2)
1753 hasSlaveFaces =
true;
1758 auto SetFacePairOnGridRange = [&](
int i0,
int i1,
int j0,
int j1)
1760 std::array<int, 4> cv{gridVertex(i0, j0), gridVertex(i1, j0),
1761 gridVertex(i1, j1), gridVertex(i0, j1)};
1765 if (childPair.first < 0) {
return; }
1767 const int d0 = i1 - i0;
1768 const int d1 = j1 - j0;
1770 const bool childPairTopo = v2f.count(childPair) > 0;
1773 const int childFace = v2f.at(childPair);
1777 facePairs.emplace_back(
1778 FacePairInfo{cv[0], parentFace, SlaveFaceInfo{childFace,
1779 ori, {i0, j0}, {d0, d1}}});
1786 const bool bdryParentFace = faceInfo.
IsBoundary();
1788 if (!allset && !bdryParentFace)
1792 if (auxv2f.count(childPair) == 0)
1795 auxv2f[childPair] = auxFaces.size();
1796 AuxiliaryFace auxFace;
1797 for (
int k=0; k<4; ++k) { auxFace.v[k] = cv[k]; }
1799 auxFace.parent = parentFace;
1802 auxFace.ksi0[0] = i0;
1803 auxFace.ksi0[1] = j0;
1804 auxFace.ksi1[0] = i1;
1805 auxFace.ksi1[1] = j1;
1807 auxFaces.push_back(auxFace);
1808 facePairs.emplace_back(
1809 FacePairInfo{cv[0], parentFace,
1811 0, {i0, j0}, {d0, d1}}});
1818 for (
int ii=0; ii<n_orig[0]; ++ii)
1820 const int i = cgrid[0][ii];
1821 const int i1 = cgrid[0][ii + 1];
1822 for (
int jj=0; jj<n_orig[1]; ++jj)
1824 const int j = cgrid[1][jj];
1825 const int j1 = cgrid[1][jj + 1];
1826 SetFacePairOnGridRange(i, i1, j, j1);
1831 for (
int dir=1; dir<=2; ++dir)
1833 const int ne = dir == 1 ? n1 : n2;
1834 for (
int s=0; s<2; ++s)
1836 const int parentEdge = parentEdges[dir == 1 ? 2*s : (2*s) + 1];
1837 const bool reverse_p = parentEdgeRev[dir == 1 ? 2*s : (2*s) + 1];
1839 const bool reverse = s == 0 ? reverse_p : !reverse_p;
1840 const bool parentVisited = visitedParentEdges.count(parentEdge) > 0;
1844 edgePairOS[parentEdge] = edgePairs.size();
1845 edgePairs.resize(edgePairs.size() + ne);
1855 for (
int e_orig = 0; e_orig < n_orig[dir-1]; ++e_orig)
1857 const int e_i = os_e;
1858 const int e_orig_rev = reverse ? n_orig[dir-1] - 1 - e_orig : e_orig;
1864 else if (
kvf.size() > 0)
1866 de =
kvf[kvi[dir - 1]][e_orig_rev];
1875 const int i1 = e_i + de;
1878 const int e_idx = reverse ? ne - e_i - de : e_i;
1883 cv[0] = gridVertex(i0,s*n2);
1884 cv[1] = gridVertex(i1,s*n2);
1888 cv[0] = gridVertex((1-s)*n1, i0);
1889 cv[1] = gridVertex((1-s)*n1, i1);
1892 const int cv0 = cv[0];
1904 kiprev = (i0 == 0 || i0 == ne) ? i1 : i0;
1906 tvprev = (i0 == 0 || i0 == ne) ? cv[1] : cv[0];
1908 else if (e_i < ne - 1)
1910 kiprev = (tvprev == cv[0]) ? i1 : i0;
1912 tvprev = (tvprev == cv[0]) ? cv[1] : cv[0];
1926 else if (firstEdge == -1)
1933 tvprev = cv.Sum() - cv0;
1939 const int tv = (e_idx == ne - de) ? -1 : tv_int;
1940 const int tvki = (e_idx == ne - de) ? -1 : (reverse ? ne - ki : ki);
1942 const std::pair<int, int> edge_i(cv[0], cv[1]);
1943 const int childEdge = v2e.at(edge_i);
1945 if (tv == -1) { lagTV =
true; }
1950 edgePairs[edgePairOS[parentEdge] + e_idx].Set(tv, tvki,
1957 const int os = edgePairOS[parentEdge];
1958 if (edgePairs[os + e_idx].child != childEdge ||
1959 edgePairs[os + e_idx].parent != parentEdge)
1966 visitedParentEdges.insert(parentEdge);
1975 std::array<int, 4> gv1 = {0, r1min, r1max, n1};
1976 std::array<int, 4> gv2 = {0, r2min, r2max, n2};
1978 if (hasSlaveFaces && !allset)
1980 for (
int i=0; i<3; ++i)
1981 for (
int j=0; j<3; ++j)
1984 if (i == 1 && j == 1) {
continue; }
1987 if (gv1[i] == gv1[i+1] || gv2[j] == gv2[j+1]) {
continue; }
1990 SetFacePairOnGridRange(gv1[i], gv1[i+1], gv2[j], gv2[j+1]);
2001 for (
int d=0; d<2; ++d)
2003 for (
int i=0; i<3; ++i)
2010 for (
int s=0; s<2; ++s)
2016 const int n_d = d == 0 ? n1 : n2;
2017 for (
int j=1; j<n_d; ++j)
2019 const int tv = d == 0 ? gridVertex(j,s*n2) :
2020 gridVertex((1-s)*n1,j);
2031 rmin = std::min(rmin, j);
2032 rmax = std::max(rmax, j);
2054 const int pid = d == 0 ? 2*s : (2*s) + 1;
2055 const bool reverse_p = parentEdgeRev[pid];
2057 const bool reverse = s == 0 ? reverse_p : !reverse_p;
2061 std::array<int, 2> ki;
2065 cv[0] = gridVertex(gv1[i],s*n2);
2066 cv[1] = gridVertex(gv1[i+1],s*n2);
2073 cv[0] = gridVertex((1-s)*n1,gv2[i]);
2074 cv[1] = gridVertex((1-s)*n1,gv2[i+1]);
2086 const int tv = i == 0 ? cv[1] : cv[0];
2087 const int tvki_f = i == 0 ? ki[1] : ki[0];
2088 const int tvki = reverse ? n_d - tvki_f : tvki_f;
2091 MFEM_ASSERT(cv[0] >= 0,
"");
2093 const std::pair<int, int> childPair(cv[0], cv[1]);
2094 const bool childPairTopo = v2e.count(childPair) > 0;
2097 const int pv0 = d == 0 ? gridVertex(0,s*n2) :
2098 gridVertex((1-s)*n1,0);
2099 const int pv1 = d == 0 ? gridVertex(n1,s*n2) :
2100 gridVertex((1-s)*n1,n2);
2101 const std::pair<int, int> parentPair(pv0 < pv1 ? pv0 : pv1,
2102 pv0 < pv1 ? pv1 : pv0);
2103 const int parentEdge = v2e.at(parentPair);
2104 MFEM_ASSERT(parentEdges[pid] == parentEdge,
"");
2107 if (auxv2e.count(childPair) == 0)
2109 const int knotIndex0 = (d == 0) ? gv1[i] : gv2[i];
2110 const int knotIndex1 = (d == 0) ? gv1[i+1] : gv2[i+1];
2113 auxv2e[childPair] = auxEdges.size();
2114 auxEdges.emplace_back(AuxiliaryEdge{pv0 < pv1 ?
2117 {childPair.first, childPair.second},
2118 {knotIndex0, knotIndex1}});
2121 const bool start = (i == 0 && !reverse) || (i != 0 && reverse);
2123 (start ? 0 :
kvf_coarse[kvi[d]].Size() - 1) : 0;
2127 end_idx = start ? 0 :
kvf[kvi[d]].Size() - 1;
2128 de =
kvf[kvi[d]][end_idx];
2131 const int e_idx_i = i == 0 ? 0 : n_d - de;
2132 const int e_idx = reverse ? n_d - de - e_idx_i : e_idx_i;
2134 const EdgePairInfo ep_e((e_idx == n_d - de) ? -1 : tv,
2135 (e_idx == n_d - de) ? -1 : tvki,
2139 const bool unset = !edgePairs[edgePairOS[parentEdge] + e_idx].isSet;
2142 edgePairs[edgePairOS[parentEdge] + e_idx] = ep_e;
2147 MFEM_ASSERT(edgePairs[edgePairOS[parentEdge] + e_idx] == ep_e,
"");
2152 const int childEdge = v2e.at(childPair);
2154 const int pv0 = d == 0 ? gridVertex(0,s*n2) : gridVertex((1-s)*n1,0);
2155 const int pv1 = d == 0 ? gridVertex(n1,s*n2) : gridVertex((1-s)*n1,n2);
2156 const std::pair<int, int> parentPair(pv0 < pv1 ? pv0 : pv1,
2157 pv0 < pv1 ? pv1 : pv0);
2158 const int parentEdge = v2e.at(parentPair);
2159 MFEM_ASSERT(parentEdges[pid] == parentEdge,
"");
2161 const bool start = (i == 0 && !reverse) || (i != 0 && reverse);
2163 (start ? 0 :
kvf_coarse[kvi[d]].Size() - 1) : 0;
2167 end_idx = start ? 0 :
kvf[kvi[d]].Size() - 1;
2168 de =
kvf[kvi[d]][end_idx];
2171 const int e_idx_i = i == 0 ? 0 : n_d - de;
2172 const int e_idx = reverse ? n_d - de - e_idx_i : e_idx_i;
2174 const int tv_e = (e_idx == n_d - de) ? -1 : tv;
2175 const int tv_ki = (e_idx == n_d - de) ? -1 : tvki;
2177 const EdgePairInfo ep_e(tv_e, tv_ki, childEdge, parentEdge);
2181 !edgePairs[edgePairOS[parentEdge] + e_idx].isSet;
2182 const bool matching =
2183 edgePairs[edgePairOS[parentEdge] + e_idx] == ep_e;
2184 MFEM_ASSERT(unset || matching,
"");
2187 edgePairs[edgePairOS[parentEdge] + e_idx] = ep_e;
2193 if (hasSlaveFaces || hasAuxFace) { masterFaces.insert(parentFace); }
2196 MFEM_VERIFY(consistent,
"");
2199void NCNURBSExtension::GetAuxFaceToPatchTable(Array2D<int> &auxface2patch)
2201 auxface2patch.SetSize(auxFaces.size(), 2);
2203 if (auxFaces.size() == 0) {
return; }
2209 bool consistent =
true;
2213 Array<int> faces, orient;
2217 for (
auto face : faces)
2219 const bool isMaster =
dim == 2 ? masterEdgeToId.count(face) > 0 :
2220 masterFaceToId.count(face) > 0;
2223 const int mid =
dim == 2 ? masterEdgeToId.at(face) :
2224 masterFaceToId.at(face);
2225 const std::vector<int> &slaves =
dim == 2 ? masterEdgeInfo[mid].slaves :
2226 masterFaceInfo[mid].slaves;
2227 for (
auto s : slaves)
2233 if (auxface2patch(aux, 0) >= 0)
2235 if (auxface2patch(aux, 1) != -1) { consistent =
false; }
2236 auxface2patch(aux, 1) =
p;
2240 auxface2patch(aux, 0) =
p;
2248 MFEM_VERIFY(consistent,
"");
2251void NCNURBSExtension::GetSlaveFaceToPatchTable(Array2D<int> &sface2patch)
2254 const int numUnique =
dim == 2 ? slaveEdgesUnique.
Size() :
2255 slaveFacesUnique.
Size();
2256 sface2patch.SetSize(numUnique, 2);
2258 if (numUnique == 0) {
return; }
2262 bool consistent =
true;
2266 Array<int> faces, orient;
2270 for (
auto face : faces)
2272 const bool isMaster =
dim == 2 ? masterEdgeToId.count(face) > 0 :
2273 masterFaceToId.count(face) > 0;
2276 const int mid =
dim == 2 ? masterEdgeToId.at(face) :
2277 masterFaceToId.at(face);
2278 const std::vector<int> &slaves =
dim == 2 ? masterEdgeInfo[mid].slaves :
2279 masterFaceInfo[mid].slaves;
2280 for (
auto id : slaves)
2284 const int s =
dim == 2 ? slaveEdges[id] : slaveFaces[id].index;
2285 const int u =
dim == 2 ? slaveEdgesToUnique[s] :
2286 slaveFacesToUnique[s];
2287 if (sface2patch(
u, 0) >= 0)
2289 if (sface2patch(
u, 1) != -1) { consistent =
false; }
2290 sface2patch(
u, 1) =
p;
2294 sface2patch(
u, 0) =
p;
2302 MFEM_VERIFY(consistent,
"");
2307 const int ne = rf.
Size();
2310 for (
int p=0;
p<k0; ++
p)
2312 const int rp = rev ? ne - 1 -
p :
p;
2317void NCNURBSExtension::UpdateAuxiliaryKnotSpans(
const Array<int> &rf)
2319 for (
auto auxEdge : auxEdges)
2321 const int p = auxEdge.parent;
2323 const int kv =
KnotInd(parent);
2324 for (
int i=0; i<2; ++i)
2330 for (
auto auxFace : auxFaces)
2333 std::array<int, 4> quad;
2335 MFEM_ASSERT(pv.Size() == 4,
"");
2336 for (
int i=0; i<4; ++i) { quad[i] = pv[i]; }
2339 const std::array<int, 2> kv = parentToKV.at(parentPair);
2362 if (filename.empty()) {
return; }
2364 ifstream
f(filename);
2368 for (
int i=0; i<nkv; ++i)
2372 MFEM_ASSERT(nf == 1,
"");
2375 for (
int j=0; j<nf; ++j) {
f >> rf; }
2377 for (
int j=0; j<
kvf[kv].Size(); ++j) {
kvf[kv][j] = rf; }
2383int NCNURBSExtension::AuxiliaryEdgeNE(
int aux_edge)
2385 const int signedParentEdge = auxEdges[aux_edge].parent;
2386 const int ki0 = auxEdges[aux_edge].ksi[0];
2387 const int ki1raw = auxEdges[aux_edge].ksi[1];
2395void NCNURBSExtension::SlaveEdgeToParent(
int se,
int parent,
2396 const Array<int> &os,
2397 const std::vector<int> &parentVerts,
2403 for (
int i=0; i<2; ++i) { sev[i] = auxEdges[
FlipIndexSign(se)].v[i]; }
2411 const int nedge = parentVerts.size() + 1;
2412 MFEM_ASSERT((
int) parentVerts.size() + 2 == os.Size(),
"");
2414 Array<int> parentEndpoints;
2418 for (
int i=0; i<nedge; ++i)
2420 const bool first = (i == 0);
2421 const bool last = (i == nedge - 1);
2422 const int v0 = first ? parentEndpoints[0] : parentVerts[i - 1];
2423 const int v1 = last ? parentEndpoints[1] : parentVerts[i];
2424 if (sev[0] == v0 && sev[1] == v1)
2427 MFEM_ASSERT(edges.Size() == os[i + 1] - os[i],
"");
2428 for (
int j=0; j<edges.Size(); ++j) { edges[j] = os[i] + j; }
2430 else if (sev[0] == v1 && sev[1] == v0)
2433 MFEM_ASSERT(edges.Size() == os[i + 1] - os[i],
"");
2434 for (
int j=0; j<edges.Size(); ++j) { edges[j] = os[i + 1] - 1 - j; }
2438 MFEM_VERIFY(found,
"");
2441void NCNURBSExtension::GetMasterEdgePieceOffsets(
int mid, Array<int> &os)
2443 const int np = masterEdgeInfo[mid].slaves.size();
2444 MFEM_VERIFY(np > 0,
"");
2448 for (
int i=0; i<np; ++i)
2450 const int p = masterEdgeInfo[mid].slaves[i];
2451 const int s = slaveEdges[
p];
2462 os[i+1] = os[i] + nes;
2472 for (
int i=0; i<
f; ++i)
2485 constexpr char dirEdges3D[3][4] = {{0, 2, 4, 6}, {1, 3, 5, 7}, {8, 9, 10, 11}};
2486 constexpr char dirEdges2D[2][2] = {{0, 2}, {1, 3}};
2492 const int nedge =
dim == 3 ? 4 : 2;
2496 bool partialChange =
false;
2497 bool consistent =
true;
2499 auto SetFactorsDirection = [&](
int j,
int os_final,
int af,
Array<int> &rf)
2504 rf.SetSize(os_final);
2507 if (rf[j] !=
unsetFactor && af != rf[j]) { consistent =
false; }
2511 auto SetFactorsEdge = [&](
int j,
int rf,
Array<int> &pf)
2514 if (pf[j] !=
unsetFactor && pf[j] != rf) { consistent =
false; }
2518 auto LoopEdgesForDirection = [&](
int d,
Array<int> &rf,
bool first)
2520 for (
int i=0; i<nedge; ++i)
2522 const int edgeIndex =
dim == 3 ? dirEdges3D[d][i] : dirEdges2D[d][i];
2523 const int edge = edges[edgeIndex];
2526 const bool rev =
KnotSign(edge) < 0;
2531 const bool fullSize =
kvf.size() > 0 &&
kvf[kv].Size() == nfe;
2534 if (rf_i.
Size() > 0 && rf.Size() == 0) { rf = rf_i; }
2538 if (
kvf[kv] != rf) { partialChange =
true; }
2545 const int mid = masterEdgeToId.at(edge);
2546 const int numPieces = masterEdgeInfo[mid].slaves.size();
2548 GetMasterEdgePieceOffsets(mid, os);
2550 for (
int piece=0; piece<numPieces; ++piece)
2552 const int e = masterEdgeInfo[mid].slaves[piece];
2553 const int s = slaveEdges[e];
2566 if (auxef[aux_edge].Size() == 0)
2568 auxef[aux_edge].SetSize(AuxiliaryEdgeNE(aux_edge));
2571 parentEdges.
SetSize(auxef[aux_edge].Size());
2572 pf = &auxef[aux_edge];
2575 if (first && parentEdges.
Size() == 0) {
continue; }
2576 SlaveEdgeToParent(s, edge, os, masterEdgeInfo[mid].vertices, parentEdges);
2577 MFEM_ASSERT(parentEdges.
Size() == os[piece + 1] - os[piece],
"");
2579 for (
int j = os[piece]; j < os[piece + 1]; ++j)
2581 const int jj = parentEdges[j - os[piece]];
2582 const int jr = rev ? rf.
Size() - 1 - jj : jj;
2585 SetFactorsDirection(jr, os[numPieces],
2586 (*pf)[j - os[piece]], rf);
2590 SetFactorsEdge(j - os[piece], rf[jr], *pf);
2598 for (
int d=0; d<
dim; ++d)
2602 LoopEdgesForDirection(d, rf,
true);
2603 if (rf.
Size() == 0) {
continue; }
2606 LoopEdgesForDirection(d, rf,
false);
2607 if (rf.
Min() >
unsetFactor) { dirSet +=
static_cast<int>(pow(2, d)); }
2610 MFEM_VERIFY(consistent,
"");
2619 for (
size_t i=0; i<
kvf.size(); ++i)
2621 kvf[i] = rf_default;
2633 slaveEdgesUnique.
Reserve(slaveEdges.size());
2634 for (
auto s : slaveEdges)
2636 if (slaveEdgesToUnique.count(s) == 0)
2638 slaveEdgesToUnique[s] = slaveEdgesUnique.
Size();
2639 slaveEdgesUnique.
Append(s);
2647 slaveFacesUnique.
Reserve(slaveFaces.size());
2648 for (
auto s : slaveFaces)
2650 if (slaveFacesToUnique.count(s.index) == 0)
2652 slaveFacesToUnique[s.index] = slaveFacesUnique.
Size();
2653 slaveFacesUnique.
Append(s.index);
2663 GetAuxFaceToPatchTable(auxface2patch);
2664 GetSlaveFaceToPatchTable(sface2patch);
2668 auto faceNeighbors = [&](
int p, std::set<int> &nghb)
2673 for (
auto face : faces)
2676 face2elem->
GetRow(face, row);
2678 const bool isSlave =
dim == 2 ? slaveEdgesToUnique.count(
2679 face) > 0 : slaveFacesToUnique.count(face) > 0;
2682 const int u =
dim == 2 ? slaveEdgesToUnique[face] :
2683 slaveFacesToUnique[face];
2684 for (
int i=0; i<2; ++i)
2686 const int elem = sface2patch(
u, i);
2687 if (elem >= 0 && elem !=
p) { nghb.insert(elem); }
2691 for (
auto elem : row) { nghb.insert(elem); }
2695 auto masterFaceNeighbors = [&](
int p, std::set<int> &nghb)
2700 for (
auto face : faces)
2702 const bool isMaster =
dim == 2 ? masterEdgeToId.count(face) > 0 :
2703 masterFaceToId.count(face) > 0;
2706 const int mid =
dim == 2 ? masterEdgeToId.at(face) :
2707 masterFaceToId.at(face);
2708 const std::vector<int> &slaves =
2709 dim == 2 ? masterEdgeInfo[mid].slaves : masterFaceInfo[mid].slaves;
2710 for (
auto s : slaves)
2716 for (
int i=0; i<2; ++i)
2718 const int patch = auxface2patch(aux, i);
2719 if (patch >= 0) { nghb.insert(patch); }
2726 face2elem->
GetRow(s, row);
2727 for (
auto elem : row) { nghb.insert(elem); }
2734 const int npatchall =
patches.Size();
2738 auxef.resize(auxEdges.size());
2740 std::set<int> nextPatches, unchanged;
2741 const int dirAllSet =
dim == 3 ? 7 : 3;
2742 int lastChanged = 0;
2745 while (iter < 100 && !done)
2748 nextPatches.clear();
2749 nextPatches.insert(lastChanged);
2751 std::set<int> visited;
2754 while (nextPatches.size() > 0)
2756 const int p = *nextPatches.begin();
2757 nextPatches.erase(
p);
2762 const bool partialChange = dirSetSigned < 0;
2764 const bool changed = (patchState[
p] != dirSet) || partialChange;
2765 patchState[
p] = dirSet;
2768 std::set<int> neighbors;
2771 faceNeighbors(
p, neighbors);
2774 masterFaceNeighbors(
p, neighbors);
2780 for (
auto n : neighbors)
2782 if (n < npatchall && n !=
p && patchState[n] != dirAllSet &&
2783 visited.count(n) == 0)
2785 nextPatches.insert(n);
2796 unchanged.insert(
p);
2799 if (unchanged.size() == (size_t) npatchall)
2802 for (
int i=0; i<npatchall; ++i)
2805 const bool partialChange_i = dirSetSigned_i < 0;
2806 const int dirSet_i = partialChange_i ?
2808 const bool changed_i = (patchState[i] != dirSet_i) ||
2810 patchState[
p] = dirSet_i;
2819 if (unchanged.size() == (size_t) npatchall)
2830 for (
size_t i=0; i<
kvf.size(); ++i)
2832 if (
kvf[i].Size() == 0)
2835 kvf[i] = rf_default;
2839 for (
int j=0; j<
kvf[i].Size(); ++j)
2853 const int np = pwn.
Size();
2854 const int f =
kvf[i].Size() / pwn.
Sum();
2855 MFEM_ASSERT(
kvf[i].Size() ==
f * pwn.
Sum(),
"");
2859 for (
int j=1; j<np+1; ++j)
2861 const int jp = rev ? np - j : j - 1;
2862 os[j] = os[j-1] + (
f * pwn[jp]);
2866 for (
int j=0; j<np; ++j)
2868 pwf[j] =
kvf[i][os[j]];
2869 for (
int r=os[j]+1; r<os[j+1]; ++r)
2871 MFEM_ASSERT(
kvf[i][r] == pwf[j],
"");
2886 for (
int i=0; i<
f.Size(); ++i)
2888 const int f_i =
f[i];
2889 for (
int j=0; j<f_i; ++j) { rf[os + j] = f_i; }
2894 MFEM_ASSERT(os == rf.
Size(),
"");
2900 const std::string &kvf_filename,
2920void NCNURBSExtension::ReadCoarsePatchCP(std::istream &input)
2929 const int ncp1D = maxOrder + 1;
2930 const int ncp =
static_cast<int>(pow(ncp1D,
Dimension()));
2934 for (
int i=0; i<ncp; ++i)
2938void NCNURBSExtension::PrintCoarsePatches(std::ostream &os)
2945 if (patchCP_size1 == 0) {
return; }
2950 const int ncp1D = maxOrder + 1;
2951 const int ncp =
static_cast<int>(
pow(ncp1D,
Dimension()));
2956 for (
int i=0; i<ncp; ++i)
2970 MFEM_ASSERT(
f.Size() == c.
Sum(),
"");
2971 bool consistent =
true;
2973 for (
int j=0; j<c.
Size(); ++j)
2975 const int cf = c[j];
2976 const int ff =
f[os];
2977 for (
int i=0; i<cf; ++i)
2979 if (
f[os + i] != ff) { consistent =
false; }
2987 MFEM_VERIFY(consistent,
"");
2990void NCNURBSExtension::UpdateCoarseKVF()
3000 const std::array<int, 4> &verts)
3004 MFEM_ASSERT(fverts.
Size() == 4,
"");
3012 for (
int i=0; i<4; ++i) { s1[i] = verts[i]; }
3015 MFEM_ASSERT(s1 == s2,
"");
3020 for (
int i=0; i<4; ++i)
3022 if (verts[i] == fverts[0]) { s = i; }
3026 const bool rev = verts[(s + 1) % 4] != fverts[1];
3044 const int s0i = (shift == 0 || shift == 3) ? 0 : 1;
3045 const int s0j = (shift < 2) ? 0 : 1;
3052 const int shift1 = ori < 0 ? shift - 1: shift + 1;
3053 const int s1 = (shift1 + 4) % 4;
3054 const int s1i = (s1 == 0 || s1 == 3) ? 0 : 1;
3055 const bool dimReverse = s0i == s1i;
3063 const bool rev = (signedShift < 0);
3065 MFEM_ASSERT(0 <= shift && shift < 4,
"");
3077 else if (shift == 1)
3084 else if (shift == 2)
3108 else if (shift == 1)
3115 else if (shift == 2)
3133 int& sm,
int& sn,
int& si,
int& sj)
3135 const bool rev = (signedShift < 0);
3137 MFEM_ASSERT(0 <= shift && shift < 4,
"");
3155 else if (shift == 1)
3165 else if (shift == 2)
3198 else if (shift == 1)
3208 else if (shift == 2)
3238 const auto qmin = std::min_element(q.begin(), q.end());
3239 const int idmin = std::distance(q.begin(), qmin);
3240 return std::pair<int, int>(q[idmin], q[(idmin + 2) % 4]);
3246 MFEM_ASSERT((
dim == 2 ||
dim == 3) && numVertices > 0,
"Invalid size");
3251 const std::array<int, 2> &pv)
3255 data(
index,2) = pv[0];
3256 data(
index,3) = pv[1];
3260 const std::array<int, 2> &ks,
3261 const std::array<int, 4> &pv)
3264 data(
index,1) = ks[0];
3265 data(
index,2) = ks[1];
3266 data(
index,3) = pv[0];
3267 data(
index,4) = pv[1];
3268 data(
index,5) = pv[2];
3269 data(
index,6) = pv[3];
3279 data(
index,1) = ks[0];
3280 data(
index,2) = ks[1];
3284 std::array<int, 2> &pv)
const
3288 pv[0] = data(
index,2);
3289 pv[1] = data(
index,3);
3293 std::array<int, 4> &pv)
const
3296 ks[0] = data(
index,1);
3297 ks[1] = data(
index,2);
3298 pv[0] = data(
index,3);
3299 pv[1] = data(
index,4);
3300 pv[2] = data(
index,5);
3301 pv[3] = data(
index,6);
3306 const int nv = data.
NumRows();
3309 for (
int i = 0; i < nv; i++)
3312 for (
int j = 1; j < m; j++)
3314 os <<
" " << data(i,j);
3324 std::array<int, 4> pv;
3325 for (
int i=0; i<4; ++i) { pv[i] = data(
index, 3 + i); }
3331 int c0 = data(
index, 2);
3332 int c1 = data(
index, 3);
3333 if (c0 > c1) { std::swap(c0, c1); }
3334 return std::pair<int, int>(c0, c1);
3340 "NURBS NC-patch meshes cannot use this method of refinement");
3355void NCNURBSExtension::Refine(
bool coarsened,
const Array<int> *rf)
3364 std::vector<Array<int>> prf(
dim);
3371 constexpr char e3[3] = {0, 3, 8};
3372 for (
int i=0; i<3; ++i)
3380 MFEM_VERIFY(
dim == 2,
"");
3381 for (
int i=0; i<2; ++i)
3390 for (
int i=0; i<
dim; ++i)
3393 MFEM_VERIFY(prf[i].IsConstant(),
"");
3398 patches[
p]->UpdateSpacingPartitions(pkv);
3399 patches[
p]->UniformRefinement(prf, coarsened, maxOrder);
3403 patches[
p]->UniformRefinement(*rf);
3415void NCNURBSExtension::SetDofToPatch()
3421 if (
dim == 1) {
return; }
3423 Array<int> edges, faces, orient;
3426 for (
int p = 0;
p < np;
p++)
3429 for (
auto e : edges)
3431 if (masterEdges.count(e) > 0)
3435 for (
auto dof : mdof) {
dof2patch[dof] =
p; }
3443 for (
auto f : faces)
3445 if (masterFaces.count(
f) > 0)
3449 for (
int j=0; j<mdof.NumCols(); ++j)
3450 for (
int k=0; k<mdof.NumRows(); ++k)
3463 const int ne = kv->
GetNE();
3466 const int totalEdgeCP = kv->
GetNCP() - 2 - ne + 1;
3467 const int perEdgeCP = totalEdgeCP / ne;
3469 MFEM_VERIFY(perEdgeCP * ne == totalEdgeCP,
"");
3482 std::set<int> reversedParents;
3492 masterEdges.clear();
3493 masterFaces.clear();
3496 masterEdgeToId.clear();
3497 masterFaceToId.clear();
3499 MFEM_VERIFY(nce.
masters.Size() > 0 ||
3501 MFEM_VERIFY(!(nce.
masters.Size() > 0 &&
3504 std::vector<EdgePairInfo> edgePairs;
3505 std::vector<FacePairInfo> facePairs;
3506 std::vector<int> parentFaces, parentVerts;
3507 std::vector<std::array<int, 2>> parentSize;
3509 const bool is3D =
dim == 3;
3511 std::map<std::pair<int, int>,
int> v2f;
3524 v2e[std::pair<int, int> (vert_index[0], vert_index[1])] = edgeID.index;
3534 const int vmin = vert.
Min();
3535 const int idmin = vert.
Find(vmin);
3536 v2f[std::pair<int, int> (vert[idmin], vert[(idmin + 2) % 4])] = i;
3543 ProcessVertexToKnot3D(v2k, v2f, parentSize, edgePairs,
3544 facePairs, parentFaces, parentVerts);
3547 ProcessVertexToKnot2D(v2k, reversedParents, edgePairs);
3551 const int numMasters = is3D ? ncf.
masters.Size() : nce.
masters.Size();
3555 for (
auto masterFace : ncf.
masters)
3557 masterFaces.insert(masterFace.index);
3561 for (
auto masterEdge : nce.
masters)
3563 masterEdges.insert(masterEdge.index);
3566 masterEdgeIndex.
SetSize(masterEdges.size());
3568 for (
auto medge : masterEdges)
3570 masterEdgeIndex[cnt] = medge;
3571 masterEdgeToId[medge] = cnt;
3574 MFEM_VERIFY(cnt == masterEdgeIndex.
Size(),
"");
3576 Array<int> masterFaceIndex(parentFaces.size());
3579 MFEM_VERIFY(masterFaces.size() <= parentFaces.size(),
"");
3582 for (
auto mface : parentFaces)
3584 masterFaceIndex[cnt] = mface;
3585 masterFaceToId[mface] = cnt;
3589 MFEM_VERIFY(cnt == masterFaceIndex.
Size(),
"");
3591 masterEdgeInfo.clear();
3592 masterEdgeInfo.resize(masterEdgeIndex.
Size());
3594 masterFaceInfo.clear();
3595 masterFaceInfo.resize(masterFaceIndex.
Size());
3600 const int npairs = edgePairs.size();
3602 for (
int i=0; i<npairs; ++i)
3604 if (!edgePairs[i].isSet) {
continue; }
3606 const int v = edgePairs[i].v;
3607 const int s = edgePairs[i].child;
3608 const int m = edgePairs[i].parent;
3609 const int ksi = edgePairs[i].ksi;
3611 slaveEdges.push_back(s);
3613 const int mid = masterEdgeToId[m];
3614 const int si = slaveEdges.size() - 1;
3615 masterEdgeInfo[mid].slaves.push_back(si);
3618 masterEdgeInfo[mid].vertices.push_back(v);
3619 masterEdgeInfo[mid].ks.push_back(ksi);
3623 ProcessFacePairs(0, 0, parentSize, parentVerts, facePairs);
3626 for (
int i=0; i<nce.
slaves.Size(); ++i)
3631 slaveEdges.push_back(slaveEdge.
index);
3633 const int mid = masterEdgeToId[slaveEdge.
master];
3634 masterEdgeInfo[mid].slaves.push_back(i);
3639 for (
int m=0; m<numMasters; ++m)
3643 const int numSlaves = masterEdgeInfo[m].slaves.size();
3644 MFEM_ASSERT(numSlaves > 0,
"");
3649 std::vector<int> orderedSlaves(numSlaves);
3653 for (
int s=0; s<numSlaves; ++s)
3657 orderedSlaves[s] = -1;
3658 for (
int t=0; t<numSlaves; ++t)
3660 const int sid = masterEdgeInfo[m].slaves[t];
3661 if (used.count(sid) > 0) {
continue; }
3663 if (svert[0] == vi || svert[1] == vi)
3665 orderedSlaves[s] = sid;
3671 MFEM_ASSERT(orderedSlaves[s] >= 0,
"");
3674 vi = (svert[0] == vi) ? svert[1] : svert[0];
3676 if (s < numSlaves - 1)
3678 masterEdgeInfo[m].vertices.push_back(vi);
3679 masterEdgeInfo[m].ks.push_back(-1);
3683 masterEdgeInfo[m].slaves = orderedSlaves;
3690 std::vector<int> falseMasterEdges;
3691 for (
auto me : masterEdges)
3693 const int mid = masterEdgeToId.at(me);
3694 if (masterEdgeInfo[mid].slaves.size() <= 1)
3696 falseMasterEdges.push_back(me);
3700 for (
auto me : falseMasterEdges) { masterEdges.erase(me); }
3703 const int nfp0 = facePairs.size();
3704 std::set<int> addParentFaces;
3705 FindAdditionalFacesSA(v2f, addParentFaces, facePairs);
3707 cnt = parentFaces.size();
3708 const int npf0 = cnt;
3710 for (
auto pf : addParentFaces)
3712 if (masterFaces.count(pf) == 0)
3714 masterFaces.insert(pf);
3715 masterFaceIndex.
Append(pf);
3717 masterFaceToId[pf] = cnt;
3724 MFEM_ASSERT(edges.
Size() == 4 && verts.
Size() == 4,
"");
3726 parentSize.emplace_back(std::array<int, 2>
3732 masterFaceInfo.push_back(
3736 for (
int i=0; i<4; ++i) { parentVerts.push_back(verts[i]); }
3741 MFEM_VERIFY(cnt == masterFaceIndex.
Size(),
"");
3743 ProcessFacePairs(nfp0, npf0, parentSize, parentVerts, facePairs);
3747 for (
auto rp : reversedParents)
3749 masterEdgeInfo[masterEdgeToId[rp]].Reverse();
3765 for (meshCounter = 0; meshCounter < nv; meshCounter++)
3770 spaceCounter = meshCounter;
3773 for (
int e = 0; e < ne; e++)
3778 if (masterEdges.count(e) == 0)
3785 const int nauxe = auxEdges.size();
3786 aux_e_meshOffsets.
SetSize(nauxe + 1);
3787 aux_e_spaceOffsets.
SetSize(nauxe + 1);
3788 for (
int e = 0; e < nauxe; e++)
3790 aux_e_meshOffsets[e] = meshCounter;
3791 aux_e_spaceOffsets[e] = spaceCounter;
3795 const int signedParentEdge = auxEdges[e].parent;
3796 const int ki0 = auxEdges[e].ksi[0];
3797 const int ki1raw = auxEdges[e].ksi[1];
3798 const int parentEdge =
UnsignIndex(signedParentEdge);
3800 const int ki1 = ki1raw == -1 ? masterNE : ki1raw;
3802 const int auxne = ki1 - ki0;
3803 MFEM_ASSERT(auxne > 0,
"");
3804 meshCounter += auxne - 1;
3805 spaceCounter += (auxne * perEdgeCP) + auxne - 1;
3808 aux_e_meshOffsets[nauxe] = meshCounter;
3809 aux_e_spaceOffsets[nauxe] = spaceCounter;
3812 for (
int f = 0;
f < nf;
f++)
3817 if (masterFaces.count(
f) == 0)
3830 const int nauxf = auxFaces.size();
3831 aux_f_meshOffsets.
SetSize(nauxf + 1);
3832 aux_f_spaceOffsets.
SetSize(nauxf + 1);
3833 for (
int f = 0;
f < nauxf;
f++)
3835 aux_f_meshOffsets[
f] = meshCounter;
3836 aux_f_spaceOffsets[
f] = spaceCounter;
3838 const int parentFace = auxFaces[
f].parent;
3845 const int auxne0 = auxFaces[
f].ksi1[0] - auxFaces[
f].ksi0[0];
3846 const int auxne1 = auxFaces[
f].ksi1[1] - auxFaces[
f].ksi0[1];
3847 meshCounter += (auxne0 - 1) * (auxne1 - 1);
3848 spaceCounter += ((auxne0 * perEdgeCP0) + auxne0 - 1) *
3849 ((auxne1 * perEdgeCP1) + auxne1 - 1);
3852 aux_f_meshOffsets[nauxf] = meshCounter;
3853 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 arbitrarily many fixed sub...
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 SetSize(int dim, int connections_per_row)
Set the size and the number of connections for the table.
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)
MFEM_HOST_DEVICE int FlipIndexSign(int i)
Signed indices i -> -1 - i are used as a convention to encode orientation.
void UpdateFactors(Array< int > &f)
int GetNCPperEdge(const KnotVector *kv)
bool ConsistentlySetEntry(int v, int &e)
MFEM_HOST_DEVICE int UnsignIndex(int i)
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)