23#if defined(_MSC_VER) && (_MSC_VER < 1800)
25#define copysign _copysign
60 for (
int i = 0 ; i <
Order + 1; i++)
77 const int size = k.
Size();
78 const int last = size - 1;
85 for (
int i = 0; i <=
Order; i++)
87 if (k[i] != k[0]) { repeated =
false; }
88 if (k[last - i] != k[last]) { repeated =
false; }
99 for (
int i = 0; i <=
Order; i++)
104 for (
int i = 0; i < last; i++)
109 for (
int i = 0; i <=
Order; i++)
124 MFEM_ASSERT(continuity.
Size() == (intervals.
Size() + 1),
125 "Incompatible sizes of continuity and intervals.");
127 const int num_knots =
Order * continuity.
Size() - continuity.
Sum();
130 MFEM_ASSERT(num_knots >= 0,
"Invalid continuity vector for order.");
135 for (
int i = 0; i < continuity.
Size(); ++i)
137 const int multiplicity =
Order - continuity[i];
138 MFEM_ASSERT(multiplicity >= 1 && multiplicity <=
Order+1,
139 "Invalid knot multiplicity for order.");
140 for (
int j = 0; j < multiplicity; ++j)
145 if (i < intervals.
Size()) { accum += intervals[i]; }
150 "Insufficient number of knots to define NURBS.");
153 for (
int i = 0; i <
GetNKS(); ++i)
183 else if (
u ==
knot(0))
191 mid = (low + high)/2;
192 while ( (
u <
knot(mid)) || (
u >=
knot(mid+1)) )
202 mid = (low + high)/2;
207 mfem_error(
"Knot location outside of the range of the KnotVector");
216 for (
int j = 1; j <
Order+1; j++) { sum +=
knot[i + j]; }
224 for (
int i = 0; i < ncp; i++)
232 constexpr int itermax = 10;
233 constexpr real_t tol = 1e-8;
250 for (iter = 0; iter < itermax; iter++)
254 o =
Order - (ks - i);
259 u -= (grad[o]/hess[o])*(
knot(ks+1) -
knot(ks));
261 if (fabs(grad[o])< tol) {
break; }
265 MFEM_WARNING(
"KnotVector::GetBotella not converged");
266 mfem::out<<
"i = "<<i<<
",iter = "<<iter<<
", grad = "<< grad[o]<<endl;
275 for (
int i = 0; i < ncp; i++)
301 constexpr int itermax1 = 50;
302 constexpr int itermax2 = 50;
304 constexpr real_t tol1 = 1e-10;
305 constexpr real_t tol2 = 1e-8;
308 for (
int i = 0; i <x.
Size(); i++)
310 x[i] = i % 2 == 0 ? 1.0 : -1.0;
314 for (
int i = 0; i <
GetNCP(); i++)
329 int iter1, iter2, ks;
332 for (iter1 = 0; iter1 < itermax1; iter1++)
337 for (
int i = 0; i <
GetNCP(); i++)
349 for (iter2 = 0; iter2 <itermax2; iter2++)
358 val = grad = hess = 0.0;
366 if (fabs(grad)< tol2) {
break; }
368 if (fabs(hess) < pow(3.0,
Order))
370 u += 0.25*pow(0.45,
Order)*(val/fabs(val))*grad*(
knot(ks+1) -
knot(ks));
374 u -= (grad/hess)*(
knot(ks+1) -
knot(ks));
384 for (
int i = 0; i <
GetNCP()-1; i++)
392 if (
a.Norml2() < tol1) {
break; }
396 if (iter1 >= itermax1)
398 mfem::out<<
"Demko: Remez iteration not converged"<<endl;
408 " Parent KnotVector order higher than child");
411 const int nOrder =
Order + t;
414 for (
int i = 0; i <= nOrder; i++)
416 (*newkv)[i] =
knot(0);
418 for (
int i = nOrder + 1; i < newkv->
GetNCP(); i++)
420 (*newkv)[i] =
knot(i - t);
422 for (
int i = 0; i <= nOrder; i++)
434 MFEM_VERIFY(rf > 1,
"Refinement factor must be at least 2.");
440 for (
int i = 0; i <
knot.
Size()-1; i++)
444 for (
int m = 1; m < rf; ++m)
446 new_knots(j) = ((1.0 - (m * h)) *
knot(i)) + (m * h *
knot(i+1));
475 if (cf < 2) {
return fine; }
478 MFEM_VERIFY(cne > 0 && cne * cf ==
NumOfElements,
"Invalid coarsening factor");
486 for (
int c=0; c<cne; ++c)
492 if (
knot(i) != kprev)
498 if (fcnt == 0) { ifine0 = i; }
499 fine[fcnt] =
knot(i);
506 MFEM_VERIFY(fcnt == fine.
Size(),
"");
512 for (
int j=ifine0+1, ifine=0; j<
knot.
Size(); ++j)
514 if (
knot(j) == fine(ifine))
521 if (ifine == fine.
Size()) {
break; }
527 MFEM_VERIFY(mlt.
Sum() == fine.
Size() * mlt[0],
"");
529 for (i=0; i<fine.
Size(); ++i)
531 for (
int j=0; j<mlt[0]; ++j)
533 mfine[(fine.
Size() * j) + i] = fine[i];
542 MFEM_VERIFY(rf > 1,
"Refinement factor must be at least 2.");
561 for (
int i = 0; i <
knot.
Size() - 1; i++)
570 MFEM_VERIFY(j ==
NumOfElements + 1,
"Incorrect number of knot spans");
588 for (j = 0; j < rf - 1; ++j)
591 new_knots(os1 + j) = ((1.0 - s0) * k0) + (s0 * k1);
622 for (
int i = 1; i <= ns; i++)
640 MFEM_VERIFY(
GetNE(),
"Elements not counted. Use GetElements().");
646 for (
int ks = 0; ks <
GetNKS(); ks++)
651 for (
int j = 0; j <samples; j++)
657 for (
int d = 0; d <
Order+1; d++) { os<<
"\t"<<shape[d]; }
660 for (
int d = 0; d <
Order+1; d++) { os<<
"\t"<<shape[d]; }
663 for (
int d = 0; d <
Order+1; d++) { os<<
"\t"<<shape[d]; }
672 MFEM_VERIFY(
GetNE(),
"Elements not counted. Use GetElements().");
680 for (
int ks = 0; ks <
GetNKS(); ks++)
685 for (
int j = 0; j <samples; j++)
694 val +=
a[ks +
p]*shape[
p];
702 val +=
a[ks +
p]*shape[
p];
710 val +=
a[ks +
p]*shape[
p];
733 int ip = (i >= 0) ? (i + p) : (-1 - i + p);
734 real_t u = GetKnotLocation((i >= 0) ? xi : 1. - xi, ip), saved, tmp;
735 real_t left[MaxOrder+1], right[MaxOrder+1];
738 for (int j = 1; j <= p; ++j)
740 left[j] = u - knot(ip+1-j);
741 right[j] = knot(ip+j) - u;
743 for (int r = 0; r < j; ++r)
745 tmp = shape(r)/(right[r+1] + left[j-r]);
746 shape(r) = saved + right[r+1]*tmp;
747 saved = left[j-r]*tmp;
753// Routine from "The NURBS Book
" - 2nd ed - Piegl and Tiller
754// Algorithm A2.3 p. 72
755void KnotVector::CalcDShape(Vector &grad, int i, real_t xi) const
757 int p = Order, rk, pk;
758 int ip = (i >= 0) ? (i + p) : (-1 - i + p);
759 real_t u = GetKnotLocation((i >= 0) ? xi : 1. - xi, ip), temp, saved, d;
760 real_t ndu[MaxOrder+1][MaxOrder+1], left[MaxOrder+1], right[MaxOrder+1];
770 for (int j = 1; j <= p; j++)
772 left[j] = u - knot(ip-j+1);
773 right[j] = knot(ip+j) - u;
775 for (int r = 0; r < j; r++)
777 ndu[j][r] = right[r+1] + left[j-r];
778 temp = ndu[r][j-1]/ndu[j][r];
779 ndu[r][j] = saved + right[r+1]*temp;
780 saved = left[j-r]*temp;
785 for (int r = 0; r <= p; ++r)
792 d = ndu[rk][pk]/ndu[p][rk];
796 d -= ndu[r][pk]/ndu[p][r];
803 grad *= p*(knot(ip+1) - knot(ip));
807 grad *= p*(knot(ip) - knot(ip+1));
811// Routine from "The NURBS Book
" - 2nd ed - Piegl and Tiller
812// Algorithm A2.3 p. 72
813void KnotVector::CalcDnShape(Vector &gradn, int n, int i, real_t xi) const
815 int p = Order, rk, pk, j1, j2,r,j,k;
816 int ip = (i >= 0) ? (i + p) : (-1 - i + p);
817 real_t u = GetKnotLocation((i >= 0) ? xi : 1. - xi, ip);
818 real_t temp, saved, d;
819 real_t a[2][MaxOrder+1],ndu[MaxOrder+1][MaxOrder+1], left[MaxOrder+1],
830 for (j = 1; j <= p; j++)
832 left[j] = u - knot(ip-j+1);
833 right[j] = knot(ip+j)- u;
836 for (r = 0; r < j; r++)
838 ndu[j][r] = right[r+1] + left[j-r];
839 temp = ndu[r][j-1]/ndu[j][r];
840 ndu[r][j] = saved + right[r+1]*temp;
841 saved = left[j-r]*temp;
846 for (r = 0; r <= p; r++)
851 for (k = 1; k <= n; k++)
858 a[s2][0] = a[s1][0]/ndu[pk+1][rk];
859 d = a[s2][0]*ndu[rk][pk];
880 for (j = j1; j <= j2; j++)
882 a[s2][j] = (a[s1][j] - a[s1][j-1])/ndu[pk+1][rk+j];
883 d += a[s2][j]*ndu[rk+j][pk];
888 a[s2][k] = - a[s1][k-1]/ndu[pk+1][r];
889 d += a[s2][j]*ndu[rk+j][pk];
900 u = (knot(ip+1) - knot(ip));
904 u = (knot(ip) - knot(ip+1));
908 for (k = 1; k <= n-1; k++) { temp *= (p-k)*u; }
910 for (j = 0; j <= p; j++) { gradn[j] *= temp; }
914void KnotVector::FindMaxima(Array<int> &ks, Vector &xi, Vector &u) const
916 Vector shape(Order+1);
917 Vector maxima(GetNCP());
918 real_t arg1, arg2, arg, max1, max2, max;
920 xi.SetSize(GetNCP());
922 ks.SetSize(GetNCP());
923 for (int j = 0; j < GetNCP(); j++)
926 for (int d = 0; d < Order+1; d++)
931 arg1 = std::numeric_limits<real_t>::epsilon() / 2_r;
932 CalcShape(shape, i, arg1);
936 CalcShape(shape, i, arg2);
939 arg = (arg1 + arg2)/2;
940 CalcShape(shape, i, arg);
943 while ( ( max > max1 ) || (max > max2) )
956 arg = (arg1 + arg2)/2;
957 CalcShape(shape, i, arg);
966 u[j] = GetKnotLocation(arg, i+Order);
973// Routine from "The NURBS Book
" - 2nd ed - Piegl and Tiller
974// Algorithm A9.1 p. 369
975void KnotVector::FindInterpolant(Array<Vector*> &x, bool reuse_inverse)
977 int order = GetOrder();
980 // Find interpolation points
982 Vector xi_args(ncp), u_args(ncp);
983 Array<int> i_args(ncp);
984 for (int i = 0; i < ncp; i++)
986 u_args[i] = GetDemko(i);
987 i_args[i] = GetSpan(u_args[i]) - Order;
988 xi_args[i] = GetRefPoint(u_args[i],i_args[i]+Order);
991 // Assemble collocation matrix
992#ifdef MFEM_USE_LAPACK
993 // If using LAPACK, we use banded matrix storage (order + 1 nonzeros per row).
994 // Find banded structure of matrix.
995 int KL = 0; // Number of subdiagonals
996 int KU = 0; // Number of superdiagonals
997 for (int i = 0; i < ncp; i++)
999 for (int p = 0; p < order+1; p++)
1001 const int col = i_args[i] + p;
1004 KL = std::max(KL, i - col);
1008 KU = std::max(KU, col - i);
1013 const int LDAB = (2*KL) + KU + 1;
1016 fact_AB.SetSize(LDAB, N);
1018 // Without LAPACK, we store and invert a DenseMatrix (inefficient).
1021 A_coll_inv.SetSize(ncp, ncp);
1026 Vector shape(order+1);
1028 if (!reuse_inverse) // Set collocation matrix entries
1030 for (int i = 0; i < ncp; i++)
1032 CalcShape(shape, i_args[i], xi_args[i]);
1033 for (int p = 0; p < order+1; p++)
1035 const int j = i_args[i] + p;
1036#ifdef MFEM_USE_LAPACK
1037 fact_AB(KL+KU+i-j,j) = shape[p];
1039 A_coll_inv(i,j) = shape[p];
1046#ifdef MFEM_USE_LAPACK
1047 const int NRHS = x.Size();
1048 DenseMatrix B(N, NRHS);
1049 for (int j=0; j<NRHS; ++j)
1051 for (int i=0; i<N; ++i) { B(i, j) = (*x[j])[i]; }
1056 BandedFactorizedSolve(KL, KU, fact_AB, B, false, fact_ipiv);
1060 BandedSolve(KL, KU, fact_AB, B, fact_ipiv);
1063 for (int j=0; j<NRHS; ++j)
1065 for (int i=0; i<N; ++i) { (*x[j])[i] = B(i, j); }
1068 if (!reuse_inverse) { A_coll_inv.Invert(); }
1070 for (int i = 0; i < x.Size(); i++)
1073 A_coll_inv.Mult(tmp, *x[i]);
1078// Routine from "The NURBS book
" - 2nd ed - Piegl and Tiller
1079// Algorithm A9.1 p. 369
1080void KnotVector::GetInterpolant(const Vector &x, const Vector &u,
1081 Vector &a, bool reuse_inverse) const
1085 Array<Vector*> tmp(1);
1087 GetInterpolant(tmp,u,reuse_inverse);
1090// Routine from "The NURBS book
" - 2nd ed - Piegl and Tiller
1091// Algorithm A9.1 p. 369
1092void KnotVector::GetInterpolant(Array<Vector*> &x, const Vector &u,
1093 bool reuse_inverse) const
1098 // Initialize matrix
1099#ifdef MFEM_USE_LAPACK
1100 // If using LAPACK, we use banded matrix storage (order + 1 nonzeros per row).
1101 // Find banded structure of matrix.
1102 int KL = 0; // Number of subdiagonals
1103 int KU = 0; // Number of superdiagonals
1104 for (int i = 0; i < ncp; i++)
1106 const int ks = GetSpan(u[i]);
1107 for (int p = 0; p < Order+1; p++)
1109 const int j = ks - Order + p;
1112 KL = std::max(KL, i - j);
1116 KU = std::max(KU, j - i);
1121 const int LDAB = (2*KL) + KU + 1;
1124 if (!reuse_inverse) { fact_AB.SetSize(LDAB, N); }
1126 // Without LAPACK, we store and invert a DenseMatrix (inefficient).
1129 A_coll_inv.SetSize(ncp, ncp);
1134 // Assemble collocation matrix
1137 Vector shape(Order+1);
1138 for (int i = 0; i < NumOfControlPoints; i++)
1140 const int ks = GetSpan(u[i]);
1141 const real_t xi = GetRefPoint(u[i], ks);
1142 CalcShape ( shape, ks-Order, xi);
1144 for (int p = 0; p < Order+1; p++)
1146 const int j = ks - Order + p;
1147#ifdef MFEM_USE_LAPACK
1148 fact_AB(KL+KU+i-j,j) = shape[p];
1150 A_coll_inv(i,j) = shape[p];
1157#ifdef MFEM_USE_LAPACK
1158 const int NRHS = x.Size();
1159 DenseMatrix B(N, NRHS);
1160 for (int j=0; j<NRHS; ++j)
1162 for (int i=0; i<N; ++i) { B(i, j) = (*x[j])[i]; }
1167 BandedFactorizedSolve(KL, KU, fact_AB, B, false, fact_ipiv);
1171 BandedSolve(KL, KU, fact_AB, B, fact_ipiv);
1174 for (int j=0; j<NRHS; ++j)
1176 for (int i=0; i<N; ++i) { (*x[j])[i] = B(i, j); }
1179 if (!reuse_inverse) { A_coll_inv.Invert(); }
1181 for (int i = 0; i < x.Size(); i++)
1184 A_coll_inv.Mult(tmp, *x[i]);
1190int KnotVector::findKnotSpan(real_t u) const
1194 if (u == knot(NumOfControlPoints+Order))
1196 mid = NumOfControlPoints;
1201 high = NumOfControlPoints + 1;
1202 mid = (low + high)/2;
1203 while ( (u < knot(mid-1)) || (u > knot(mid)) )
1205 if (u < knot(mid-1))
1213 mid = (low + high)/2;
1219void KnotVector::Difference(const KnotVector &kv, Vector &diff) const
1221 if (Order != kv.GetOrder())
1224 " Can not compare
knot vectors with different orders!
");
1227 int s = kv.Size() - Size();
1230 kv.Difference(*this, diff);
1236 if (s == 0) { return; }
1240 for (int j = 0; j < kv.Size(); j++)
1242 if (abs(knot(i) - kv[j]) < 2 * std::numeric_limits<real_t>::epsilon())
1254KnotVector* KnotVector::FullyCoarsen()
1256 KnotVector *kvc = new KnotVector(Order, Order + 1);
1257 MFEM_VERIFY(kvc->Size() == 2 * (Order + 1), "");
1258 for (int i=0; i<Order+1; ++i)
1261 (*kvc)[i + Order + 1] = 1.0;
1267 kvc->spacing = spacing->Clone();
1268 kvc->spacing->FullyCoarsen();
1274void NURBSPatch::init(int dim)
1276 MFEM_ASSERT(dim > 1, "NURBS patch
dimension (including
weight) must be
"
1283 ni = kv[0]->GetNCP();
1288 data = new real_t[ni*Dim];
1291 for (int i = 0; i < ni*Dim; i++)
1297 else if (kv.Size() == 2)
1299 ni = kv[0]->GetNCP();
1300 nj = kv[1]->GetNCP();
1301 MFEM_ASSERT(ni > 0 && nj > 0, "Invalid
knot vector dimensions.
");
1304 data = new real_t[ni*nj*Dim];
1307 for (int i = 0; i < ni*nj*Dim; i++)
1313 else if (kv.Size() == 3)
1315 ni = kv[0]->GetNCP();
1316 nj = kv[1]->GetNCP();
1317 nk = kv[2]->GetNCP();
1318 MFEM_ASSERT(ni > 0 && nj > 0 && nk > 0,
1319 "Invalid
knot vector dimensions.
");
1321 data = new real_t[ni*nj*nk*Dim];
1324 for (int i = 0; i < ni*nj*nk*Dim; i++)
1336NURBSPatch::NURBSPatch(const NURBSPatch &orig)
1337 : ni(orig.ni), nj(orig.nj), nk(orig.nk), Dim(orig.Dim),
1338 data(NULL), kv(orig.kv.Size()), nd(orig.nd), ls(orig.ls), sd(orig.sd)
1340 // Allocate and copy data:
1341 const int data_size = Dim*ni*nj*((kv.Size() == 2) ? 1 : nk);
1342 data = new real_t[data_size];
1343 std::memcpy(data, orig.data, data_size*sizeof(real_t));
1345 // Copy the knot vectors:
1346 for (int i = 0; i < kv.Size(); i++)
1348 kv[i] = new KnotVector(*orig.kv[i]);
1352NURBSPatch::NURBSPatch(std::istream &input)
1354 int pdim, dim, size = 1;
1357 skip_comment_lines(input, '#');
1358 input >> ws >> ident >> pdim; // knotvectors
1360 for (int i = 0; i < pdim; i++)
1362 skip_comment_lines(input, '#');
1363 kv[i] = new KnotVector(input);
1364 size *= kv[i]->GetNCP();
1367 skip_comment_lines(input, '#');
1368 input >> ws >> ident >> dim; // dimension
1371 skip_comment_lines(input, '#');
1372 input >> ws >> ident; // controlpoints (homogeneous coordinates)
1373 if (ident == "controlpoints
" || ident == "controlpoints_homogeneous
")
1375 for (int j = 0, i = 0; i < size; i++)
1377 skip_comment_lines(input, '#');
1378 for (int d = 0; d <= dim; d++, j++)
1384 else // "controlpoints_cartesian
" (Cartesian coordinates with weight)
1386 for (int j = 0, i = 0; i < size; i++)
1388 skip_comment_lines(input, '#');
1389 for (int d = 0; d <= dim; d++)
1393 for (int d = 0; d < dim; d++)
1395 data[j+d] *= data[j+dim];
1402NURBSPatch::NURBSPatch(const KnotVector *kv0, const KnotVector *kv1, int dim)
1405 kv[0] = new KnotVector(*kv0);
1406 kv[1] = new KnotVector(*kv1);
1410NURBSPatch::NURBSPatch(const KnotVector *kv0, const KnotVector *kv1,
1411 const KnotVector *kv2, int dim)
1414 kv[0] = new KnotVector(*kv0);
1415 kv[1] = new KnotVector(*kv1);
1416 kv[2] = new KnotVector(*kv2);
1420NURBSPatch::NURBSPatch(Array<const KnotVector *> &kvs, int dim)
1422 kv.SetSize(kvs.Size());
1423 for (int i = 0; i < kv.Size(); i++)
1425 kv[i] = new KnotVector(*kvs[i]);
1430NURBSPatch::NURBSPatch(NURBSPatch *parent, int dir, int Order, int NCP)
1432 kv.SetSize(parent->kv.Size());
1433 for (int i = 0; i < kv.Size(); i++)
1436 kv[i] = new KnotVector(*parent->kv[i]);
1440 kv[i] = new KnotVector(Order, NCP);
1445void NURBSPatch::swap(NURBSPatch *np)
1452 for (int i = 0; i < kv.Size(); i++)
1454 if (kv[i]) { delete kv[i]; }
1471NURBSPatch::~NURBSPatch()
1478 for (int i = 0; i < kv.Size(); i++)
1480 if (kv[i]) { delete kv[i]; }
1484void NURBSPatch::Print(std::ostream &os) const
1488 os << "knotvectors\n
" << kv.Size() << '\n';
1489 for (int i = 0; i < kv.Size(); i++)
1492 size *= kv[i]->GetNCP();
1495 os << "\ndimension\n
" << Dim - 1
1496 << "\n\ncontrolpoints\n
";
1497 for (int j = 0, i = 0; i < size; i++)
1500 for (int d = 1; d < Dim; d++)
1502 os << ' ' << data[j++];
1508int NURBSPatch::SetLoopDirection(int dir)
1510 if (nj == -1) // 1D case
1521 mfem::err << "NURBSPatch::SetLoopDirection :\n
"
1522 " Direction error in 1D patch, dir =
" << dir << '\n';
1526 else if (nk == -1) // 2D case
1544 mfem::err << "NURBSPatch::SetLoopDirection :\n
"
1545 " Direction error in 2D patch, dir =
" << dir << '\n';
1574 mfem::err << "NURBSPatch::SetLoopDirection :\n
"
1575 " Direction error in 3D patch, dir =
" << dir << '\n';
1583void NURBSPatch::UniformRefinement(Array<int> const& rf, int multiplicity)
1586 for (int dir = 0; dir < kv.Size(); dir++)
1590 kv[dir]->Refinement(new_knots, rf[dir]);
1591 for (int i=0; i<multiplicity; ++i)
1593 KnotInsert(dir, new_knots);
1599void NURBSPatch::UniformRefinement(const std::vector<Array<int>> &rf,
1600 bool coarsened, int multiplicity)
1603 for (int dir = 0; dir < kv.Size(); dir++)
1607 const int f = rf[dir].Sum();
1608 if (f == 1) { continue; }
1609 kv[dir]->Refinement(new_knots, f);
1613 MFEM_VERIFY(rf[dir].IsConstant(), "");
1614 if (rf[dir][0] == 1) { continue; }
1615 kv[dir]->Refinement(new_knots, rf[dir][0]);
1618 for (int i=0; i<multiplicity; ++i)
1620 KnotInsert(dir, new_knots);
1625void NURBSPatch::UniformRefinement(int rf, int multiplicity)
1627 Array<int> rf_array(kv.Size());
1629 UniformRefinement(rf_array, multiplicity);
1632void NURBSPatch::UpdateSpacingPartitions(const Array<KnotVector*> &pkv)
1634 MFEM_VERIFY(pkv.Size() == kv.Size(), "");
1636 for (int dir = 0; dir < kv.Size(); dir++)
1638 if (kv[dir]->spacing && pkv[dir]->spacing)
1640 PiecewiseSpacingFunction *pws = dynamic_cast<PiecewiseSpacingFunction*>
1641 (kv[dir]->spacing.get());
1642 const PiecewiseSpacingFunction *upws =
1643 dynamic_cast<const PiecewiseSpacingFunction*>(pkv[dir]->spacing.get());
1645 MFEM_VERIFY((pws == nullptr) == (upws == nullptr), "");
1649 Array<int> s0 = pws->RelativePieceSizes();
1650 Array<int> s1 = upws->RelativePieceSizes();
1651 MFEM_ASSERT(s0.Size() == s1.Size(), "");
1653 Array<int> rf(s0.Size());
1654 for (int i=0; i<s0.Size(); ++i)
1656 const int f = s1[i] / s0[i];
1657 MFEM_ASSERT(f * s0[i] == s1[i], "Inconsistent spacings
");
1661 pws->ScalePartition(rf, false);
1667void NURBSPatch::Coarsen(Array<int> const& cf, real_t tol)
1669 for (int dir = 0; dir < kv.Size(); dir++)
1671 if (!kv[dir]->coarse)
1673 const int ne_fine = kv[dir]->GetNE();
1674 KnotRemove(dir, kv[dir]->GetFineKnots(cf[dir]), tol);
1675 kv[dir]->coarse = true;
1676 kv[dir]->GetElements();
1678 const int ne_coarse = kv[dir]->GetNE();
1679 MFEM_VERIFY(ne_fine == cf[dir] * ne_coarse, "");
1680 if (kv[dir]->spacing)
1682 kv[dir]->spacing->SetSize(ne_coarse);
1683 kv[dir]->spacing->ScaleParameters((real_t) cf[dir]);
1689void NURBSPatch::Coarsen(int cf, real_t tol)
1691 Array<int> cf_array(kv.Size());
1693 Coarsen(cf_array, tol);
1696void NURBSPatch::GetCoarseningFactors(Array<int> & f) const
1698 f.SetSize(kv.Size());
1699 for (int dir = 0; dir < kv.Size(); dir++)
1701 f[dir] = kv[dir]->GetCoarseningFactor();
1705void NURBSPatch::KnotInsert(Array<KnotVector *> &newkv)
1707 MFEM_ASSERT(newkv.Size() == kv.Size(), "Invalid input to KnotInsert
");
1708 for (int dir = 0; dir < kv.Size(); dir++)
1710 KnotInsert(dir, *newkv[dir]);
1714void NURBSPatch::KnotInsert(int dir, const KnotVector &newkv)
1716 if (dir >= kv.Size() || dir < 0)
1721 int t = newkv.GetOrder() - kv[dir]->GetOrder();
1725 DegreeElevate(dir, t);
1729 mfem_error("NURBSPatch::KnotInsert : Incorrect order!
");
1733 GetKV(dir)->Difference(newkv, diff);
1734 if (diff.Size() > 0)
1736 KnotInsert(dir, diff);
1740void NURBSPatch::KnotInsert(Array<Vector *> &newkv)
1742 MFEM_ASSERT(newkv.Size() == kv.Size(), "Invalid input to KnotInsert
");
1743 for (int dir = 0; dir < kv.Size(); dir++)
1745 KnotInsert(dir, *newkv[dir]);
1749void NURBSPatch::KnotRemove(Array<Vector *> &rmkv, real_t tol)
1751 for (int dir = 0; dir < kv.Size(); dir++)
1753 KnotRemove(dir, *rmkv[dir], tol);
1757void NURBSPatch::KnotRemove(int dir, const Vector &knot, real_t tol)
1759 // TODO: implement an efficient version of this!
1762 KnotRemove(dir, k, 1, tol);
1766// Algorithm A5.5 from "The NURBS Book
", 2nd ed, Piegl and Tiller, chapter 5.
1767void NURBSPatch::KnotInsert(int dir, const Vector &knot)
1769 if (knot.Size() == 0 ) { return; }
1771 if (dir >= kv.Size() || dir < 0)
1776 NURBSPatch &oldp = *this;
1777 KnotVector &oldkv = *kv[dir];
1779 NURBSPatch *newpatch = new NURBSPatch(this, dir, oldkv.GetOrder(),
1780 oldkv.GetNCP() + knot.Size());
1781 NURBSPatch &newp = *newpatch;
1782 KnotVector &newkv = *newp.GetKV(dir);
1784 newkv.spacing = oldkv.spacing;
1786 int size = oldp.SetLoopDirection(dir);
1787 if (size != newp.SetLoopDirection(dir))
1792 int rr = knot.Size() - 1;
1793 int a = oldkv.GetSpan(knot(0));
1794 int b = oldkv.GetSpan(knot(rr));
1795 int pl = oldkv.GetOrder();
1796 int ml = oldkv.GetNCP();
1798 for (int j = 0; j <= a; j++)
1800 newkv[j] = oldkv[j];
1802 for (int j = b+pl; j <= ml+pl; j++)
1804 newkv[j+rr+1] = oldkv[j];
1806 for (int k = 0; k <= (a-pl); k++)
1808 for (int ll = 0; ll < size; ll++)
1810 newp.slice(k,ll) = oldp.slice(k,ll);
1813 for (int k = (b-1); k < ml; k++)
1815 for (int ll = 0; ll < size; ll++)
1817 newp.slice(k+rr+1,ll) = oldp.slice(k,ll);
1824 for (int j = rr; j >= 0; j--)
1826 while ( (knot(j) <= oldkv[i]) && (i > a) )
1828 newkv[k] = oldkv[i];
1829 for (int ll = 0; ll < size; ll++)
1831 newp.slice(k-pl-1,ll) = oldp.slice(i-pl-1,ll);
1838 for (int ll = 0; ll < size; ll++)
1840 newp.slice(k-pl-1,ll) = newp.slice(k-pl,ll);
1843 for (int l = 1; l <= pl; l++)
1846 real_t alfa = newkv[k+l] - knot(j);
1847 if (fabs(alfa) == 0.0)
1849 for (int ll = 0; ll < size; ll++)
1851 newp.slice(ind-1,ll) = newp.slice(ind,ll);
1856 alfa = alfa/(newkv[k+l] - oldkv[i-pl+l]);
1857 for (int ll = 0; ll < size; ll++)
1859 newp.slice(ind-1,ll) = alfa*newp.slice(ind-1,ll) +
1860 (1.0-alfa)*newp.slice(ind,ll);
1869 newkv.GetElements();
1874// Algorithm A5.8 from "The NURBS Book
", 2nd ed, Piegl and Tiller, chapter 5.
1875int NURBSPatch::KnotRemove(int dir, real_t knot, int ntimes, real_t tol)
1877 if (dir >= kv.Size() || dir < 0)
1882 NURBSPatch &oldp = *this;
1883 KnotVector &oldkv = *kv[dir];
1885 // Find the index of the last occurrence of the knot.
1887 int multiplicity = 0;
1888 for (int i=0; i<oldkv.Size(); ++i)
1890 if (oldkv[i] == knot)
1897 MFEM_VERIFY(0 < id && id < oldkv.Size() - 1 && ntimes <= multiplicity,
1898 "Only interior knots of sufficient multiplicity may be removed.
");
1900 const int p = oldkv.GetOrder();
1902 NURBSPatch tmpp(this, dir, p, oldkv.GetNCP());
1904 const int size = oldp.SetLoopDirection(dir);
1905 if (size != tmpp.SetLoopDirection(dir))
1911 for (int k = 0; k < oldp.nd; ++k)
1913 for (int ll = 0; ll < size; ll++)
1915 tmpp.slice(k,ll) = oldp.slice(k,ll);
1920 const int s = multiplicity;
1928 Array2D<real_t> temp(last + ntimes + 1, size);
1930 for (int t=0; t<ntimes; ++t)
1932 int off = first - 1; // Difference in index between temp and P.
1934 for (int ll = 0; ll < size; ll++)
1936 temp(0, ll) = oldp.slice(off, ll);
1937 temp(last + 1 - off, ll) = oldp.slice(last + 1, ll);
1941 int jj = last - off;
1945 // Compute new control points for one removal step
1946 const real_t a_i = (knot - oldkv[i]) / (oldkv[i+p+1+t] - oldkv[i]);
1947 const real_t a_j = (knot - oldkv[j-t]) / (oldkv[j+p+1] - oldkv[j-t]);
1949 for (int ll = 0; ll < size; ll++)
1951 temp(ii,ll) = (1.0 / a_i) * oldp.slice(i,ll) -
1952 ((1.0/a_i) - 1.0) * temp(ii - 1, ll);
1954 temp(jj,ll) = (1.0 / (1.0 - a_j)) * (oldp.slice(j,ll) -
1955 (a_j * temp(jj + 1, ll)));
1962 // Check whether knot is removable
1966 for (int ll = 0; ll < size; ll++)
1968 diff[ll] = temp(ii-1, ll) - temp(jj+1, ll);
1973 const real_t a_i = (knot - oldkv[i]) / (oldkv[i+p+1+t] - oldkv[i]);
1974 for (int ll = 0; ll < size; ll++)
1975 diff[ll] = oldp.slice(i,ll) - (a_i * temp(ii+t+1, ll))
1976 - ((1.0 - a_i) * temp(ii-1, ll));
1979 const real_t dist = diff.Norml2();
1982 // Removal failed. Return the number of successful removals.
1983 mfem::out << "Knot removal failed after
" << t
1984 << " successful removals
" << endl;
1988 // Note that the new weights may not be positive.
1990 // Save new control points
1996 for (int ll = 0; ll < size; ll++)
1998 tmpp.slice(i,ll) = temp(i - off,ll);
1999 tmpp.slice(j,ll) = temp(j - off,ll);
2007 } // End of loop (t) over ntimes.
2009 const int fout = ((2*r) - s - p) / 2; // First control point out
2013 for (int k=1; k<ntimes; ++k)
2025 NURBSPatch *newpatch = new NURBSPatch(this, dir, p,
2026 oldkv.GetNCP() - ntimes);
2027 NURBSPatch &newp = *newpatch;
2028 if (size != newp.SetLoopDirection(dir))
2033 for (int k = 0; k < fout; ++k)
2035 for (int ll = 0; ll < size; ll++)
2037 newp.slice(k,ll) = oldp.slice(k,ll); // Copy old data
2041 for (int k = i+1; k < oldp.nd; ++k)
2043 for (int ll = 0; ll < size; ll++)
2045 newp.slice(j,ll) = tmpp.slice(k,ll); // Shift
2051 KnotVector &newkv = *newp.GetKV(dir);
2052 MFEM_VERIFY(newkv.Size() == oldkv.Size() - ntimes, "");
2054 newkv.spacing = oldkv.spacing;
2055 newkv.coarse = oldkv.coarse;
2057 for (int k = 0; k < r - ntimes + 1; k++)
2059 newkv[k] = oldkv[k];
2061 for (int k = r + 1; k < oldkv.Size(); k++)
2063 newkv[k - ntimes] = oldkv[k];
2066 newkv.GetElements();
2073void NURBSPatch::DegreeElevate(int t)
2075 for (int dir = 0; dir < kv.Size(); dir++)
2077 DegreeElevate(dir, t);
2081// Routine from "The NURBS Book
" - 2nd ed - Piegl and Tiller
2082void NURBSPatch::DegreeElevate(int dir, int t)
2084 if (dir >= kv.Size() || dir < 0)
2089 MFEM_ASSERT(t >= 0, "DegreeElevate cannot decrease the degree.
");
2091 int i, j, k, kj, mpi, mul, mh, kind, cind, first, last;
2092 int r, a, b, oldr, save, s, tr, lbz, rbz, l;
2093 real_t inv, ua, ub, numer, alf, den, bet, gam;
2095 NURBSPatch &oldp = *this;
2096 KnotVector &oldkv = *kv[dir];
2097 oldkv.GetElements();
2099 auto *newpatch = new NURBSPatch(this, dir, oldkv.GetOrder() + t,
2100 oldkv.GetNCP() + oldkv.GetNE()*t);
2101 NURBSPatch &newp = *newpatch;
2102 KnotVector &newkv = *newp.GetKV(dir);
2104 if (oldkv.spacing) { newkv.spacing = oldkv.spacing; }
2106 int size = oldp.SetLoopDirection(dir);
2107 if (size != newp.SetLoopDirection(dir))
2112 int p = oldkv.GetOrder();
2113 int n = oldkv.GetNCP()-1;
2115 DenseMatrix bezalfs (p+t+1, p+1);
2116 DenseMatrix bpts (p+1, size);
2117 DenseMatrix ebpts (p+t+1, size);
2118 DenseMatrix nextbpts(p-1, size);
2119 Vector alphas (p-1);
2126 Array2D<int> binom(ph+1, ph+1);
2127 for (i = 0; i <= ph; i++)
2129 binom(i,0) = binom(i,i) = 1;
2130 for (j = 1; j < i; j++)
2132 binom(i,j) = binom(i-1,j) + binom(i-1,j-1);
2137 bezalfs(ph,p) = 1.0;
2139 for (i = 1; i <= ph2; i++)
2141 inv = 1.0/binom(ph,i);
2143 for (j = max(0,i-t); j <= mpi; j++)
2145 bezalfs(i,j) = inv*binom(p,j)*binom(t,i-j);
2150 for (i = ph2+1; i < ph; i++)
2153 for (j = max(0,i-t); j <= mpi; j++)
2155 bezalfs(i,j) = bezalfs(ph-i,p-j);
2166 for (l = 0; l < size; l++)
2168 newp.slice(0,l) = oldp.slice(0,l);
2170 for (i = 0; i <= ph; i++)
2175 for (i = 0; i <= p; i++)
2177 for (l = 0; l < size; l++)
2179 bpts(i,l) = oldp.slice(i,l);
2186 while (b < m && oldkv[b] == oldkv[b+1]) { b++; }
2194 if (oldr > 0) { lbz = (oldr+2)/2; }
2197 if (r > 0) { rbz = ph-(r+1)/2; }
2203 for (k = p ; k > mul; k--)
2205 alphas[k-mul-1] = numer/(oldkv[a+k]-ua);
2208 for (j = 1; j <= r; j++)
2212 for (k = p; k >= s; k--)
2214 for (l = 0; l < size; l++)
2215 bpts(k,l) = (alphas[k-s]*bpts(k,l) +
2216 (1.0-alphas[k-s])*bpts(k-1,l));
2218 for (l = 0; l < size; l++)
2220 nextbpts(save,l) = bpts(p,l);
2225 for (i = lbz; i <= ph; i++)
2227 for (l = 0; l < size; l++)
2232 for (j = max(0,i-t); j <= mpi; j++)
2234 for (l = 0; l < size; l++)
2236 ebpts(i,l) += bezalfs(i,j)*bpts(j,l);
2246 bet = (ub-newkv[kind-1])/den;
2248 for (tr = 1; tr < oldr; tr++)
2257 alf = (ub-newkv[i])/(ua-newkv[i]);
2258 for (l = 0; l < size; l++)
2260 newp.slice(i,l) = alf*newp.slice(i,l)-(1.0-alf)*newp.slice(i-1,l);
2265 if ((j-tr) <= (kind-ph+oldr))
2267 gam = (ub-newkv[j-tr])/den;
2268 for (l = 0; l < size; l++)
2270 ebpts(kj,l) = gam*ebpts(kj,l) + (1.0-gam)*ebpts(kj+1,l);
2275 for (l = 0; l < size; l++)
2277 ebpts(kj,l) = bet*ebpts(kj,l) + (1.0-bet)*ebpts(kj+1,l);
2292 for (i = 0; i < (ph-oldr); i++)
2298 for (j = lbz; j <= rbz; j++)
2300 for (l = 0; l < size; l++)
2302 newp.slice(cind,l) = ebpts(j,l);
2309 for (j = 0; j <r; j++)
2310 for (l = 0; l < size; l++)
2312 bpts(j,l) = nextbpts(j,l);
2315 for (j = r; j <= p; j++)
2316 for (l = 0; l < size; l++)
2318 bpts(j,l) = oldp.slice(b-p+j,l);
2327 for (i = 0; i <= ph; i++)
2333 newkv.GetElements();
2338void NURBSPatch::FlipDirection(int dir)
2340 int size = SetLoopDirection(dir);
2342 for (int id = 0; id < nd/2; id++)
2343 for (int i = 0; i < size; i++)
2345 Swap<real_t>((*this).slice(id,i), (*this).slice(nd-1-id,i));
2350void NURBSPatch::SwapDirections(int dir1, int dir2)
2352 if (abs(dir1-dir2) == 2)
2355 " directions 0 and 2 are not supported!
");
2358 Array<const KnotVector *> nkv(kv);
2360 Swap<const KnotVector *>(nkv[dir1], nkv[dir2]);
2361 NURBSPatch *newpatch = new NURBSPatch(nkv, Dim);
2363 int size = SetLoopDirection(dir1);
2364 newpatch->SetLoopDirection(dir2);
2366 for (int id = 0; id < nd; id++)
2367 for (int i = 0; i < size; i++)
2369 (*newpatch).slice(id,i) = (*this).slice(id,i);
2375void NURBSPatch::Rotate(real_t angle, real_t n[])
2385 mfem_error("NURBSPatch::Rotate : Specify an angle for
a 3D rotation.
");
2392void NURBSPatch::Get2DRotationMatrix(real_t angle, DenseMatrix &T)
2394 real_t s = sin(angle);
2395 real_t c = cos(angle);
2404void NURBSPatch::Rotate2D(real_t angle)
2412 Vector x(2), y(NULL, 2);
2414 Get2DRotationMatrix(angle, T);
2417 for (int i = 0; i < kv.Size(); i++)
2419 size *= kv[i]->GetNCP();
2422 for (int i = 0; i < size; i++)
2424 y.SetData(data + i*Dim);
2430void NURBSPatch::Get3DRotationMatrix(real_t n[], real_t angle, real_t r,
2434 const real_t l2 = n[0]*n[0] + n[1]*n[1] + n[2]*n[2];
2435 const real_t l = sqrt(l2);
2437 MFEM_ASSERT(l2 > 0.0, "3D rotation axis is undefined
");
2439 if (fabs(angle) == (real_t)(M_PI_2))
2441 s = r*copysign(1., angle);
2445 else if (fabs(angle) == (real_t)(M_PI))
2460 T(0,0) = (n[0]*n[0] + (n[1]*n[1] + n[2]*n[2])*c)/l2;
2461 T(0,1) = -(n[0]*n[1]*c1)/l2 - (n[2]*s)/l;
2462 T(0,2) = -(n[0]*n[2]*c1)/l2 + (n[1]*s)/l;
2463 T(1,0) = -(n[0]*n[1]*c1)/l2 + (n[2]*s)/l;
2464 T(1,1) = (n[1]*n[1] + (n[0]*n[0] + n[2]*n[2])*c)/l2;
2465 T(1,2) = -(n[1]*n[2]*c1)/l2 - (n[0]*s)/l;
2466 T(2,0) = -(n[0]*n[2]*c1)/l2 - (n[1]*s)/l;
2467 T(2,1) = -(n[1]*n[2]*c1)/l2 + (n[0]*s)/l;
2468 T(2,2) = (n[2]*n[2] + (n[0]*n[0] + n[1]*n[1])*c)/l2;
2471void NURBSPatch::Rotate3D(real_t n[], real_t angle)
2479 Vector x(3), y(NULL, 3);
2481 Get3DRotationMatrix(n, angle, 1., T);
2484 for (int i = 0; i < kv.Size(); i++)
2486 size *= kv[i]->GetNCP();
2489 for (int i = 0; i < size; i++)
2491 y.SetData(data + i*Dim);
2497int NURBSPatch::MakeUniformDegree(int degree)
2503 for (int dir = 0; dir < kv.Size(); dir++)
2505 maxd = std::max(maxd, kv[dir]->GetOrder());
2509 for (int dir = 0; dir < kv.Size(); dir++)
2511 if (maxd > kv[dir]->GetOrder())
2513 DegreeElevate(dir, maxd - kv[dir]->GetOrder());
2520NURBSPatch *Interpolate(NURBSPatch &p1, NURBSPatch &p2)
2522 if (p1.kv.Size() != p2.kv.Size() || p1.Dim != p2.Dim)
2527 int size = 1, dim = p1.Dim;
2528 Array<const KnotVector *> kv(p1.kv.Size() + 1);
2530 for (int i = 0; i < p1.kv.Size(); i++)
2532 if (p1.kv[i]->GetOrder() < p2.kv[i]->GetOrder())
2534 p1.KnotInsert(i, *p2.kv[i]);
2535 p2.KnotInsert(i, *p1.kv[i]);
2539 p2.KnotInsert(i, *p1.kv[i]);
2540 p1.KnotInsert(i, *p2.kv[i]);
2543 size *= kv[i]->GetNCP();
2546 KnotVector &nkv = *(new KnotVector(1, 2));
2547 nkv[0] = nkv[1] = 0.0;
2548 nkv[2] = nkv[3] = 1.0;
2552 NURBSPatch *patch = new NURBSPatch(kv, dim);
2555 for (int i = 0; i < size; i++)
2557 for (int d = 0; d < dim; d++)
2559 patch->data[i*dim+d] = p1.data[i*dim+d];
2560 patch->data[(i+size)*dim+d] = p2.data[i*dim+d];
2567NURBSPatch *Revolve3D(NURBSPatch &patch, real_t n[], real_t ang, int times)
2575 Array<const KnotVector *> nkv(patch.kv.Size() + 1);
2577 for (int i = 0; i < patch.kv.Size(); i++)
2579 nkv[i] = patch.kv[i];
2580 size *= nkv[i]->GetNCP();
2583 KnotVector &lkv = *(new KnotVector(2, ns));
2585 lkv[0] = lkv[1] = lkv[2] = 0.0;
2586 for (int i = 1; i < times; i++)
2588 lkv[2*i+1] = lkv[2*i+2] = i;
2590 lkv[ns] = lkv[ns+1] = lkv[ns+2] = times;
2592 NURBSPatch *newpatch = new NURBSPatch(nkv, 4);
2595 DenseMatrix T(3), T2(3);
2596 Vector u(NULL, 3), v(NULL, 3);
2598 NURBSPatch::Get3DRotationMatrix(n, ang, 1., T);
2599 real_t c = cos(ang/2);
2600 NURBSPatch::Get3DRotationMatrix(n, ang/2, 1./c, T2);
2603 real_t *op = patch.data, *np;
2604 for (int i = 0; i < size; i++)
2606 np = newpatch->data + 4*i;
2607 for (int j = 0; j < 4; j++)
2611 for (int j = 0; j < times; j++)
2614 v.SetData(np += 4*size);
2617 v.SetData(np += 4*size);
2627void NURBSPatch::SetKnotVectorsCoarse(bool c)
2629 for (int i=0; i<kv.Size(); ++i) { kv[i]->coarse = c; }
2632void NURBSPatch::FullyCoarsen(const Array2D<double> & cp, int ncp1D)
2634 // Remove interior knots
2635 Array<const KnotVector *> kvc(kv.Size());
2636 for (int dir = 0; dir < kv.Size(); dir++)
2638 kvc[dir] = kv[dir]->FullyCoarsen();
2642 NURBSPatch *newpatch = new NURBSPatch(kvc, Dim);
2643 NURBSPatch &newp = *newpatch;
2647 for (int i=0; i<ncp1D; ++i)
2648 for (int j=0; j<ncp1D; ++j)
2649 for (int k=0; k<ncp1D; ++k)
2651 const int dof = i + (ncp1D * (j + (ncp1D * k)));
2652 for (int l = 0; l < Dim - 1; ++l)
2654 newp(i,j,k,l) = cp(dof, l);
2655 newp(i,j,k,Dim-1) = 1.0; // Assuming unit weights
2659 else if (Dim == 3) // 2D
2661 for (int i=0; i<ncp1D; ++i)
2662 for (int j=0; j<ncp1D; ++j)
2664 const int dof = i + (ncp1D * j);
2665 for (int l=0; l<Dim - 1; ++l)
2667 newp(i,j,l) = cp(dof, l);
2668 newp(i,j,Dim-1) = 1.0; // Assuming unit weights
2680NURBSExtension::NURBSExtension(const NURBSExtension &orig)
2681 : mOrder(orig.mOrder), mOrders(orig.mOrders),
2682 NumOfKnotVectors(orig.NumOfKnotVectors),
2683 NumOfVertices(orig.NumOfVertices),
2684 NumOfElements(orig.NumOfElements),
2685 NumOfBdrElements(orig.NumOfBdrElements),
2686 NumOfDofs(orig.NumOfDofs),
2687 NumOfActiveVertices(orig.NumOfActiveVertices),
2688 NumOfActiveElems(orig.NumOfActiveElems),
2689 NumOfActiveBdrElems(orig.NumOfActiveBdrElems),
2690 NumOfActiveDofs(orig.NumOfActiveDofs),
2691 activeVert(orig.activeVert),
2692 activeElem(orig.activeElem),
2693 activeBdrElem(orig.activeBdrElem),
2694 activeDof(orig.activeDof),
2695 patchTopo(new Mesh(*orig.patchTopo)),
2697 edge_to_ukv(orig.edge_to_ukv),
2698 knotVectors(orig.knotVectors.Size()), // knotVectors are copied in the body
2699 knotVectorsCompr(orig.knotVectorsCompr.Size()),
2700 weights(orig.weights),
2701 d_to_d(orig.d_to_d),
2702 master(orig.master),
2704 v_meshOffsets(orig.v_meshOffsets),
2705 e_meshOffsets(orig.e_meshOffsets),
2706 f_meshOffsets(orig.f_meshOffsets),
2707 p_meshOffsets(orig.p_meshOffsets),
2708 v_spaceOffsets(orig.v_spaceOffsets),
2709 e_spaceOffsets(orig.e_spaceOffsets),
2710 f_spaceOffsets(orig.f_spaceOffsets),
2711 p_spaceOffsets(orig.p_spaceOffsets),
2712 el_dof(orig.el_dof ? new Table(*orig.el_dof) : NULL),
2713 bel_dof(orig.bel_dof ? new Table(*orig.bel_dof) : NULL),
2714 el_to_patch(orig.el_to_patch),
2715 bel_to_patch(orig.bel_to_patch),
2716 el_to_IJK(orig.el_to_IJK),
2717 bel_to_IJK(orig.bel_to_IJK),
2718 patches(orig.patches.Size()), // patches are copied in the body
2719 num_structured_patches(orig.num_structured_patches),
2720 patchCP(orig.patchCP),
2722 kvf_coarse(orig.kvf_coarse),
2723 dof2patch(orig.dof2patch)
2725 // Copy the knot vectors:
2726 for (int i = 0; i < knotVectors.Size(); i++)
2728 knotVectors[i] = new KnotVector(*orig.knotVectors[i]);
2730 CreateComprehensiveKV();
2732 // Copy the patches:
2733 for (int p = 0; p < patches.Size(); p++)
2735 patches[p] = new NURBSPatch(*orig.patches[p]);
2739NURBSExtension::NURBSExtension(std::istream &input, bool spacing)
2742 patchTopo = new Mesh;
2743 patchTopo->LoadPatchTopo(input, edge_to_ukv);
2745 Load(input, spacing);
2748void NURBSExtension::Load(std::istream &input, bool spacing)
2752 MFEM_VERIFY(CheckPatches(),
2754 "\n Inconsistent edge-to-knotvector mapping!
");
2756 skip_comment_lines(input, '#');
2758 // Read knotvectors or patches
2760 input >> ws >> ident; // 'knotvectors' or 'patches'
2761 if (ident == "knotvectors
")
2763 input >> NumOfKnotVectors;
2764 knotVectors.SetSize(NumOfKnotVectors);
2765 for (int i = 0; i < NumOfKnotVectors; i++)
2767 knotVectors[i] = new KnotVector(input);
2770 if (spacing) // Read spacing formulas for knotvectors
2772 input >> ws >> ident; // 'spacing' or 'refinements'
2774 if (ident == "refinements
")
2776 ref_factors.SetSize(Dimension());
2777 for (int i=0; i<Dimension(); ++i)
2779 input >> ref_factors[i];
2782 input >> ws >> ident; // 'spacing'
2785 if (ident == "knotvector_refinements
")
2787 kvf.resize(NumOfKnotVectors);
2788 for (int i=0; i<NumOfKnotVectors; ++i)
2793 for (int j=0; j<nf; ++j)
2799 input >> ws >> ident; // 'spacing'
2802 MFEM_VERIFY(ident == "spacing",
2803 "Spacing formula section missing from NURBS mesh file
");
2806 input >> numSpacing;
2807 for (int j = 0; j < numSpacing; j++)
2809 int ki, spacingType, numIntParam, numRealParam;
2810 input >> ki >> spacingType >> numIntParam >> numRealParam;
2812 MFEM_VERIFY(0 <= ki && ki < NumOfKnotVectors,
2813 "Invalid knotvector
index");
2814 MFEM_VERIFY(numIntParam >= 0 && numRealParam >= 0,
2815 "Invalid number of parameters in
KnotVector");
2817 Array<int> ipar(numIntParam);
2818 Vector dpar(numRealParam);
2820 for (int i=0; i<numIntParam; ++i)
2825 for (int i=0; i<numRealParam; ++i)
2830 const SpacingType s = (SpacingType) spacingType;
2831 knotVectors[ki]->spacing = GetSpacingFunction(s, ipar, dpar);
2835 else if (ident == "patches
")
2837 patches.SetSize(GetNP());
2838 for (int p = 0; p < patches.Size(); p++)
2840 skip_comment_lines(input, '#');
2841 patches[p] = new NURBSPatch(input);
2844 // Determine the number of unique KnotVectors from the edge-to-unique-KV
2845 // mapping. In 1D, edge indices correspond to patch indices.
2846 NumOfKnotVectors = 0;
2847 for (int i = 0; i < edge_to_ukv.Size(); i++)
2849 NumOfKnotVectors = std::max(NumOfKnotVectors, KnotInd(i));
2852 knotVectors.SetSize(NumOfKnotVectors);
2853 knotVectors.operator=(nullptr);
2855 const int dim = Dimension();
2856 Array<int> edges, kvdir;
2857 for (int p = 0; p < patches.Size(); p++)
2859 GetPatchDirectionEdges(p, edges);
2860 CheckKVDirection(p, kvdir);
2862 for (int d = 0; d < dim; d++)
2864 const int edge = edges[d];
2865 const int kv = KnotInd(edge);
2866 if (knotVectors[kv] != nullptr) { continue; }
2868 knotVectors[kv] = new KnotVector(*patches[p]->GetKV(d));
2870 // Store the unique KnotVector in the canonical orientation; the
2871 // per-patch orientation is encoded in edge_to_ukv.
2874 knotVectors[kv]->Flip();
2881 MFEM_ABORT("invalid section:
" << ident);
2884 CreateComprehensiveKV();
2886 SetOrdersFromKnotVectors();
2891 // NumOfVertices, NumOfElements, NumOfBdrElements, NumOfDofs
2893 skip_comment_lines(input, '#');
2895 // Check for a list of mesh elements
2896 if (patches.Size() == 0)
2898 input >> ws >> ident;
2900 if (patches.Size() == 0 && ident == "mesh_elements
")
2902 input >> NumOfActiveElems;
2903 activeElem.SetSize(GetGNE());
2906 for (int i = 0; i < NumOfActiveElems; i++)
2909 activeElem[glob_elem] = true;
2912 skip_comment_lines(input, '#');
2913 input >> ws >> ident;
2917 NumOfActiveElems = NumOfElements;
2918 activeElem.SetSize(NumOfElements);
2922 GenerateActiveVertices();
2924 GenerateElementDofTable();
2925 GenerateActiveBdrElems();
2926 GenerateBdrElementDofTable();
2929 if (ident == "periodic
")
2934 skip_comment_lines(input, '#');
2935 input >> ws >> ident;
2938 if (patches.Size() == 0)
2941 if (ident == "weights
")
2943 weights.Load(input, GetNDof());
2945 else // e.g. ident = "unitweights
" or "autoweights
"
2947 weights.SetSize(GetNDof());
2953 ConnectBoundaries();
2956NURBSExtension::NURBSExtension(NURBSExtension *parent, int newOrder)
2958 patchTopo = parent->patchTopo;
2961 parent->edge_to_ukv.Copy(edge_to_ukv);
2963 NumOfKnotVectors = parent->GetNKV();
2964 knotVectors.SetSize(NumOfKnotVectors);
2965 knotVectorsCompr.SetSize(parent->GetNP()*parent->Dimension());
2966 const Array<int> &pOrders = parent->GetOrders();
2967 for (int i = 0; i < NumOfKnotVectors; i++)
2969 if (newOrder > pOrders[i])
2972 parent->GetKnotVector(i)->DegreeElevate(newOrder - pOrders[i]);
2976 knotVectors[i] = new KnotVector(*parent->GetKnotVector(i));
2979 CreateComprehensiveKV();
2981 // copy some data from parent
2982 NumOfElements = parent->NumOfElements;
2983 NumOfBdrElements = parent->NumOfBdrElements;
2985 SetOrdersFromKnotVectors();
2987 GenerateOffsets(); // dof offsets will be different from parent
2989 NumOfActiveVertices = parent->NumOfActiveVertices;
2990 NumOfActiveElems = parent->NumOfActiveElems;
2991 NumOfActiveBdrElems = parent->NumOfActiveBdrElems;
2992 parent->activeVert.Copy(activeVert);
2994 parent->activeElem.Copy(activeElem);
2995 parent->activeBdrElem.Copy(activeBdrElem);
2997 GenerateElementDofTable();
2998 GenerateBdrElementDofTable();
3000 weights.SetSize(GetNDof());
3004 parent->master.Copy(master);
3005 parent->slave.Copy(slave);
3006 ConnectBoundaries();
3009NURBSExtension::NURBSExtension(NURBSExtension *parent,
3010 const Array<int> &newOrders, Mode mode)
3013 newOrders.Copy(mOrders);
3014 SetOrderFromOrders();
3016 patchTopo = parent->patchTopo;
3019 parent->edge_to_ukv.Copy(edge_to_ukv);
3021 NumOfKnotVectors = parent->GetNKV();
3022 MFEM_VERIFY(mOrders.Size() == NumOfKnotVectors, "invalid newOrders array
");
3023 knotVectors.SetSize(NumOfKnotVectors);
3024 const Array<int> &pOrders = parent->GetOrders();
3026 for (int i = 0; i < NumOfKnotVectors; i++)
3028 if (mOrders[i] > pOrders[i])
3031 parent->GetKnotVector(i)->DegreeElevate(mOrders[i] - pOrders[i]);
3035 knotVectors[i] = new KnotVector(*parent->GetKnotVector(i));
3038 CreateComprehensiveKV();
3040 // copy some data from parent
3041 NumOfElements = parent->NumOfElements;
3042 NumOfBdrElements = parent->NumOfBdrElements;
3044 GenerateOffsets(); // dof offsets will be different from parent
3046 NumOfActiveVertices = parent->NumOfActiveVertices;
3047 NumOfActiveElems = parent->NumOfActiveElems;
3048 NumOfActiveBdrElems = parent->NumOfActiveBdrElems;
3049 parent->activeVert.Copy(activeVert);
3051 parent->activeElem.Copy(activeElem);
3052 parent->activeBdrElem.Copy(activeBdrElem);
3054 GenerateElementDofTable();
3055 GenerateBdrElementDofTable();
3057 weights.SetSize(GetNDof());
3060 parent->master.Copy(master);
3061 parent->slave.Copy(slave);
3062 ConnectBoundaries();
3065NURBSExtension::NURBSExtension(Mesh *mesh_array[], int num_pieces)
3067 NURBSExtension *parent = mesh_array[0]->NURBSext;
3069 if (!parent->own_topo)
3072 " parent does not own the patch topology!
");
3074 patchTopo = parent->patchTopo;
3076 parent->own_topo = false;
3078 parent->edge_to_ukv.Copy(edge_to_ukv);
3080 parent->GetOrders().Copy(mOrders);
3081 mOrder = parent->GetOrder();
3083 NumOfKnotVectors = parent->GetNKV();
3084 knotVectors.SetSize(NumOfKnotVectors);
3085 for (int i = 0; i < NumOfKnotVectors; i++)
3087 knotVectors[i] = new KnotVector(*parent->GetKnotVector(i));
3089 CreateComprehensiveKV();
3095 // assuming the meshes define a partitioning of all the elements
3096 NumOfActiveElems = NumOfElements;
3097 activeElem.SetSize(NumOfElements);
3100 GenerateActiveVertices();
3102 GenerateElementDofTable();
3103 GenerateActiveBdrElems();
3104 GenerateBdrElementDofTable();
3106 weights.SetSize(GetNDof());
3107 MergeWeights(mesh_array, num_pieces);
3110NURBSExtension::NURBSExtension(const Mesh *patch_topology,
3111 const Array<const NURBSPatch*> &patches_)
3113 // Basic topology checks
3114 MFEM_VERIFY(patches_.Size() > 0, "Must have at least one patch
");
3115 MFEM_VERIFY(patches_.Size() == patch_topology->GetNE(),
3116 "Number of patches must equal number of elements in patch_topology
");
3118 // Copy patch_topology mesh and NURBSPatch(es)
3119 patchTopo = new Mesh( *patch_topology );
3120 patches.SetSize(patches_.Size());
3121 for (int p = 0; p < patches.Size(); p++)
3123 patches[p] = new NURBSPatch(*patches_[p]);
3126 Array<int> ukv_to_rpkv;
3127 patchTopo->GetEdgeToUniqueKnotvector(edge_to_ukv, ukv_to_rpkv);
3130 MFEM_VERIFY(CheckPatches(),
3132 "\n Inconsistent edge-to-knotvector mapping!
");
3134 // Set number of unique (not comprehensive) knot vectors
3135 NumOfKnotVectors = ukv_to_rpkv.Size();
3136 knotVectors.SetSize(NumOfKnotVectors);
3139 // Assign the unique knot vectors from patches
3140 for (int i = 0; i < NumOfKnotVectors; i++)
3142 // pkv = p*dim + d for an arbitrarily chosen patch p,
3143 // in its reference direction d
3144 const int pkv = ukv_to_rpkv[i];
3145 const int p = pkv / Dimension();
3146 const int d = pkv % Dimension();
3147 knotVectors[i] = new KnotVector(*patches[p]->GetKV(d));
3150 CreateComprehensiveKV();
3151 SetOrdersFromKnotVectors();
3157 NumOfActiveElems = NumOfElements;
3158 activeElem.SetSize(NumOfElements);
3161 GenerateActiveVertices();
3163 GenerateElementDofTable();
3164 GenerateActiveBdrElems();
3165 GenerateBdrElementDofTable();
3167 ConnectBoundaries();
3170NURBSExtension::~NURBSExtension()
3172 if (bel_dof) { delete bel_dof; }
3173 if (el_dof) { delete el_dof; }
3175 for (int i = 0; i < knotVectors.Size(); i++)
3177 delete knotVectors[i];
3180 for (int i = 0; i < knotVectorsCompr.Size(); i++)
3182 delete knotVectorsCompr[i];
3185 for (int i = 0; i < patches.Size(); i++)
3196void NURBSExtension::Print(std::ostream &os, const std::string &comments) const
3198 Array<int> kvSpacing;
3199 if (patches.Size() == 0)
3201 for (int i = 0; i < NumOfKnotVectors; i++)
3203 if (knotVectors[i]->spacing) { kvSpacing.Append(i); }
3207 bool writeSpacing = false;
3208 bool writeRefinements = false;
3209 if (patchTopo->ncmesh)
3211 // Writing MFEM NURBS NC-patch mesh v1.0
3212 patchTopo->ncmesh->Print(os, comments, true);
3213 patchTopo->PrintTopoEdges(os, edge_to_ukv, true);
3214 writeSpacing = true;
3215 writeRefinements = true;
3219 const int version = kvSpacing.Size() > 0 ? 11 : 10; // v1.0 or v1.1
3220 if (version == 11) { writeSpacing = true; }
3221 patchTopo->PrintTopo(os, edge_to_ukv, version, comments);
3224 if (patches.Size() == 0)
3226 os << "\nknotvectors\n
" << NumOfKnotVectors << '\n';
3227 for (int i = 0; i < NumOfKnotVectors; i++)
3229 knotVectors[i]->Print(os);
3232 if (writeRefinements && ref_factors.Size() > 0)
3234 os << "\nrefinements\n
";
3235 for (int i=0; i<ref_factors.Size(); ++i)
3237 os << ref_factors[i];
3238 if (i == ref_factors.Size() - 1) { os << '\n'; }
3245 MFEM_VERIFY(kvf.size() == (size_t) NumOfKnotVectors, "");
3246 os << "\nknotvector_refinements\n
";
3247 for (size_t i=0; i<kvf.size(); ++i)
3249 if (kvf_coarse.size() > 0)
3251 os << kvf_coarse[i].Size();
3252 for (int j=0; j<kvf_coarse[i].Size(); ++j)
3254 os << ' ' << kvf_coarse[i][j];
3259 os << kvf[i].Size();
3260 for (int j=0; j<kvf[i].Size(); ++j)
3262 os << ' ' << kvf[i][j];
3271 os << "\nspacing\n
" << kvSpacing.Size() << '\n';
3272 for (auto kv : kvSpacing)
3275 knotVectors[kv]->spacing->Print(os);
3279 if (NumOfActiveElems < NumOfElements)
3281 os << "\nmesh_elements\n
" << NumOfActiveElems << '\n';
3282 for (int i = 0; i < NumOfElements; i++)
3289 os << "\nweights\n
";
3290 weights.Print(os, 1);
3294 os << "\npatches\n
";
3295 for (int p = 0; p < patches.Size(); p++)
3297 os << "\n# patch
" << p << "\n\n
";
3298 patches[p]->Print(os);
3303void NURBSExtension::PrintCharacteristics(std::ostream &os) const
3306 "NURBS
Mesh entity sizes:\n
"
3307 "Dimension =
" << Dimension() << "\n
"
3309 Array<int> unique_orders(mOrders);
3310 unique_orders.Sort();
3311 unique_orders.Unique();
3312 unique_orders.Print(os, unique_orders.Size());
3314 "NumOfKnotVectors =
" << GetNKV() << "\n
"
3315 "NumOfPatches =
" << GetNP() << "\n
"
3316 "NumOfBdrPatches =
" << GetNBP() << "\n
"
3317 "NumOfVertices =
" << GetGNV() << "\n
"
3319 "NumOfBdrElements =
" << GetGNBE() << "\n
"
3320 "NumOfDofs =
" << GetNTotalDof() << "\n
"
3321 "NumOfActiveVertices =
" << GetNV() << "\n
"
3322 "NumOfActiveElems =
" << GetNE() << "\n
"
3323 "NumOfActiveBdrElems =
" << GetNBE() << "\n
"
3324 "NumOfActiveDofs =
" << GetNDof() << '\n';
3325 for (int i = 0; i < NumOfKnotVectors; i++)
3327 os << ' ' << i + 1 << ")
";
3328 knotVectors[i]->Print(os);
3333void NURBSExtension::PrintFunctions(const char *basename, int samples) const
3336 for (int i = 0; i < NumOfKnotVectors; i++)
3338 std::ostringstream filename;
3339 filename << basename << "_
" << i << ".dat
";
3340 os.open(filename.str().c_str());
3341 knotVectors[i]->PrintFunctions(os,samples);
3346void NURBSExtension::InitDofMap()
3353void NURBSExtension::ConnectBoundaries(Array<int> &bnds0, Array<int> &bnds1)
3357 ConnectBoundaries();
3360void NURBSExtension::ConnectBoundaries()
3362 if (master.Size() != slave.Size())
3364 mfem_error("NURBSExtension::ConnectBoundaries() boundary lists not of equal size
");
3366 if (master.Size() == 0 ) { return; }
3368 // Initialize d_to_d
3369 d_to_d.SetSize(NumOfDofs);
3370 for (int i = 0; i < NumOfDofs; i++) { d_to_d[i] = i; }
3373 for (int i = 0; i < master.Size(); i++)
3375 int bnd0 = -1, bnd1 = -1;
3376 for (int b = 0; b < GetNBP(); b++)
3378 if (master[i] == patchTopo->GetBdrAttribute(b)) { bnd0 = b; }
3379 if (slave[i]== patchTopo->GetBdrAttribute(b)) { bnd1 = b; }
3381 MFEM_VERIFY(bnd0 != -1,"Bdr 0 not found
");
3382 MFEM_VERIFY(bnd1 != -1,"Bdr 1 not found
");
3384 if (Dimension() == 1)
3386 ConnectBoundaries1D(bnd0, bnd1);
3388 else if (Dimension() == 2)
3390 ConnectBoundaries2D(bnd0, bnd1);
3394 ConnectBoundaries3D(bnd0, bnd1);
3399 Array<int> tmp(d_to_d.Size()+1);
3402 for (int i = 0; i < d_to_d.Size(); i++)
3408 for (int i = 0; i < tmp.Size(); i++)
3410 if (tmp[i] == 1) { tmp[i] = cnt++; }
3414 for (int i = 0; i < d_to_d.Size(); i++)
3416 d_to_d[i] = tmp[d_to_d[i]];
3420 if (el_dof) { delete el_dof; }
3421 if (bel_dof) { delete bel_dof; }
3422 GenerateElementDofTable();
3423 GenerateBdrElementDofTable();
3426void NURBSExtension::ConnectBoundaries1D(int bnd0, int bnd1)
3428 NURBSPatchMap p2g0(this);
3429 NURBSPatchMap p2g1(this);
3431 int okv0[1],okv1[1];
3432 const KnotVector *kv0[1],*kv1[1];
3434 p2g0.SetBdrPatchDofMap(bnd0, kv0, okv0);
3435 p2g1.SetBdrPatchDofMap(bnd1, kv1, okv1);
3437 d_to_d[p2g0(0)] = d_to_d[p2g1(0)];
3440void NURBSExtension::ConnectBoundaries2D(int bnd0, int bnd1)
3442 NURBSPatchMap p2g0(this);
3443 NURBSPatchMap p2g1(this);
3445 int okv0[1],okv1[1];
3446 const KnotVector *kv0[1],*kv1[1];
3448 p2g0.SetBdrPatchDofMap(bnd0, kv0, okv0);
3449 p2g1.SetBdrPatchDofMap(bnd1, kv1, okv1);
3452 int nks0 = kv0[0]->GetNKS();
3455 bool compatible = true;
3456 if (p2g0.nx() != p2g1.nx()) { compatible = false; }
3457 if (kv0[0]->GetNKS() != kv1[0]->GetNKS()) { compatible = false; }
3458 if (kv0[0]->GetOrder() != kv1[0]->GetOrder()) { compatible = false; }
3462 mfem::out<<p2g0.nx()<<" "<<p2g1.nx()<<endl;
3463 mfem::out<<kv0[0]->GetNKS()<<" "<<kv1[0]->GetNKS()<<endl;
3464 mfem::out<<kv0[0]->GetOrder()<<" "<<kv1[0]->GetOrder()<<endl;
3465 mfem_error("NURBS boundaries not compatible
");
3469 for (int i = 0; i < nks0; i++)
3471 if (kv0[0]->isElement(i))
3473 if (!kv1[0]->isElement(i)) { mfem_error("isElement does not match
"); }
3474 for (int ii = 0; ii <= kv0[0]->GetOrder(); ii++)
3476 int ii0 = (okv0[0] >= 0) ? (i+ii) : (nx-i-ii);
3477 int ii1 = (okv1[0] >= 0) ? (i+ii) : (nx-i-ii);
3479 d_to_d[p2g0(ii0)] = d_to_d[p2g1(ii1)];
3486void NURBSExtension::ConnectBoundaries3D(int bnd0, int bnd1)
3488 NURBSPatchMap p2g0(this);
3489 NURBSPatchMap p2g1(this);
3491 int okv0[2],okv1[2];
3492 const KnotVector *kv0[2],*kv1[2];
3494 p2g0.SetBdrPatchDofMap(bnd0, kv0, okv0);
3495 p2g1.SetBdrPatchDofMap(bnd1, kv1, okv1);
3500 int nks0 = kv0[0]->GetNKS();
3501 int nks1 = kv0[1]->GetNKS();
3504 bool compatible = true;
3505 if (p2g0.nx() != p2g1.nx()) { compatible = false; }
3506 if (p2g0.ny() != p2g1.ny()) { compatible = false; }
3508 if (kv0[0]->GetNKS() != kv1[0]->GetNKS()) { compatible = false; }
3509 if (kv0[1]->GetNKS() != kv1[1]->GetNKS()) { compatible = false; }
3511 if (kv0[0]->GetOrder() != kv1[0]->GetOrder()) { compatible = false; }
3512 if (kv0[1]->GetOrder() != kv1[1]->GetOrder()) { compatible = false; }
3516 mfem::out<<p2g0.nx()<<" "<<p2g1.nx()<<endl;
3517 mfem::out<<p2g0.ny()<<" "<<p2g1.ny()<<endl;
3519 mfem::out<<kv0[0]->GetNKS()<<" "<<kv1[0]->GetNKS()<<endl;
3520 mfem::out<<kv0[1]->GetNKS()<<" "<<kv1[1]->GetNKS()<<endl;
3522 mfem::out<<kv0[0]->GetOrder()<<" "<<kv1[0]->GetOrder()<<endl;
3523 mfem::out<<kv0[1]->GetOrder()<<" "<<kv1[1]->GetOrder()<<endl;
3524 mfem_error("NURBS boundaries not compatible
");
3528 for (int j = 0; j < nks1; j++)
3530 if (kv0[1]->isElement(j))
3532 if (!kv1[1]->isElement(j)) { mfem_error("isElement does not match #1
"); }
3533 for (int i = 0; i < nks0; i++)
3535 if (kv0[0]->isElement(i))
3537 if (!kv1[0]->isElement(i)) { mfem_error("isElement does not match #0
"); }
3538 for (int jj = 0; jj <= kv0[1]->GetOrder(); jj++)
3540 int jj0 = (okv0[1] >= 0) ? (j+jj) : (ny-j-jj);
3541 int jj1 = (okv1[1] >= 0) ? (j+jj) : (ny-j-jj);
3543 for (int ii = 0; ii <= kv0[0]->GetOrder(); ii++)
3545 int ii0 = (okv0[0] >= 0) ? (i+ii) : (nx-i-ii);
3546 int ii1 = (okv1[0] >= 0) ? (i+ii) : (nx-i-ii);
3548 d_to_d[p2g0(ii0,jj0)] = d_to_d[p2g1(ii1,jj1)];
3557void NURBSExtension::GenerateActiveVertices()
3559 int vert[8], nv, g_el, nx, ny, nz, dim = Dimension();
3561 NURBSPatchMap p2g(this);
3562 const KnotVector *kv[3];
3565 activeVert.SetSize(GetGNV());
3567 for (int p = 0; p < GetNP(); p++)
3569 p2g.SetPatchVertexMap(p, kv);
3572 ny = (dim >= 2) ? p2g.ny() : 1;
3573 nz = (dim == 3) ? p2g.nz() : 1;
3575 for (int k = 0; k < nz; k++)
3577 for (int j = 0; j < ny; j++)
3579 for (int i = 0; i < nx; i++)
3581 if (activeElem[g_el])
3591 vert[0] = p2g(i, j );
3592 vert[1] = p2g(i+1,j );
3593 vert[2] = p2g(i+1,j+1);
3594 vert[3] = p2g(i, j+1);
3599 vert[0] = p2g(i, j, k);
3600 vert[1] = p2g(i+1,j, k);
3601 vert[2] = p2g(i+1,j+1,k);
3602 vert[3] = p2g(i, j+1,k);
3604 vert[4] = p2g(i, j, k+1);
3605 vert[5] = p2g(i+1,j, k+1);
3606 vert[6] = p2g(i+1,j+1,k+1);
3607 vert[7] = p2g(i, j+1,k+1);
3611 for (int v = 0; v < nv; v++)
3613 activeVert[vert[v]] = 1;
3622 NumOfActiveVertices = 0;
3623 for (int i = 0; i < GetGNV(); i++)
3624 if (activeVert[i] == 1)
3626 activeVert[i] = NumOfActiveVertices++;
3630void NURBSExtension::GenerateActiveBdrElems()
3632 int dim = Dimension();
3633 Array<KnotVector *> kv(dim);
3635 activeBdrElem.SetSize(GetGNBE());
3636 if (GetGNE() == GetNE())
3638 activeBdrElem = true;
3639 NumOfActiveBdrElems = GetGNBE();
3642 activeBdrElem = false;
3643 NumOfActiveBdrElems = 0;
3644 // the mesh will generate the actual boundary including boundary
3645 // elements that are not on boundary patches. we use this for
3646 // visualization of processor boundaries
3648 // TODO: generate actual boundary?
3652void NURBSExtension::MergeWeights(Mesh *mesh_array[], int num_pieces)
3654 Array<int> lelem_elem;
3656 for (int i = 0; i < num_pieces; i++)
3658 NURBSExtension *lext = mesh_array[i]->NURBSext;
3660 lext->GetElementLocalToGlobal(lelem_elem);
3662 for (int lel = 0; lel < lext->GetNE(); lel++)
3664 int gel = lelem_elem[lel];
3666 int nd = el_dof->RowSize(gel);
3667 int *gdofs = el_dof->GetRow(gel);
3668 int *ldofs = lext->el_dof->GetRow(lel);
3669 for (int j = 0; j < nd; j++)
3671 weights(gdofs[j]) = lext->weights(ldofs[j]);
3677void NURBSExtension::MergeGridFunctions(
3678 GridFunction *gf_array[], int num_pieces, GridFunction &merged)
3680 FiniteElementSpace *gfes = merged.FESpace();
3681 Array<int> lelem_elem, dofs;
3684 for (int i = 0; i < num_pieces; i++)
3686 FiniteElementSpace *lfes = gf_array[i]->FESpace();
3687 NURBSExtension *lext = lfes->GetMesh()->NURBSext;
3689 lext->GetElementLocalToGlobal(lelem_elem);
3691 for (int lel = 0; lel < lext->GetNE(); lel++)
3693 lfes->GetElementVDofs(lel, dofs);
3694 gf_array[i]->GetSubVector(dofs, lvec);
3696 gfes->GetElementVDofs(lelem_elem[lel], dofs);
3697 merged.SetSubVector(dofs, lvec);
3702bool NURBSExtension::CheckPatches()
3704 const int dim = Dimension();
3706 // If the patch topology has an explicit `edges` section, require it to be
3707 // consistent with edge_to_ukv, otherwise, check for consistency with the number of elements
3708 const int expected_size = patchTopo->GetNEdges() > 0
3709 ? patchTopo->GetNEdges()
3710 : patchTopo->GetNE();
3711 if ( edge_to_ukv.Size() != expected_size)
3716 // Done w/ 1D checks; in 2D and 3D we need to check orientation consistency
3722 Array<int> edges, oedge;
3724 for (int p = 0; p < GetNP(); p++)
3726 patchTopo->GetElementEdges(p, edges, oedge);
3728 // Convert to ukv and apply sign-flip
3729 for (int i = 0; i < edges.Size(); i++)
3731 edges[i] = edge_to_ukv[edges[i]];
3732 if (oedge[i] < 0) { edges[i] = FlipIndexSign(edges[i]); }
3735 // In 2d - opposite edges must be same knotvector with opposite sign.
3736 // In 3d - opposite edges must be same knotvector with same sign.
3737 // This logic is the result of Mesh::GetElementEdges setting orientation
3738 // for edges based on ascending vertex indices, using reference vertex
3740 // {0, 1}, {1, 2}, {2, 3}, {3, 0} for Geometry::SQUARE in 2D
3742 // {0, 1}, {1, 2}, {3, 2}, {0, 3}, {4, 5}, {5, 6},
3743 // {7, 6}, {4, 7}, {0, 4}, {1, 5}, {2, 6}, {3, 7} for Geometry::CUBE in 3D
3744 // See fem/geom.cpp for these definitions.
3746 (edges[0] != FlipIndexSign(edges[2]) || edges[1] != FlipIndexSign(edges[3]))) ||
3749 (edges[0] != edges[2] || edges[0] != edges[4] ||
3750 edges[0] != edges[6] || edges[1] != edges[3] ||
3751 edges[1] != edges[5] || edges[1] != edges[7] ||
3752 edges[8] != edges[9] || edges[8] != edges[10] ||
3753 edges[8] != edges[11])))
3761void NURBSExtension::CheckBdrPatches()
3766 for (int p = 0; p < GetNBP(); p++)
3768 patchTopo->GetBdrElementEdges(p, edges, oedge);
3770 for (int i = 0; i < edges.Size(); i++)
3772 edges[i] = edge_to_ukv[edges[i]];
3775 edges[i] = FlipIndexSign(edges[i]);
3779 if ((Dimension() == 2 && (edges[0] < 0)) ||
3780 (Dimension() == 3 && (edges[0] < 0 || edges[1] < 0)))
3783 << p << ") : Bad orientation!\n
";
3789void NURBSExtension::GetPatchDirectionEdges(int p, Array<int> &edges)
3791 const int dim = Dimension();
3794 Array<int> all_edges, orient;
3795 patchTopo->GetElementEdges(p, all_edges, orient);
3796 MFEM_VERIFY(all_edges.Size() > 0, "");
3797 MFEM_VERIFY(dim >= 1 && dim <=3, "Invalid NURBS
dimension.
");
3799 edges[0] = all_edges[0];
3802 edges[1] = all_edges[1];
3806 edges[1] = all_edges[3];
3807 edges[2] = all_edges[8];
3811void NURBSExtension::CheckKVDirection(int p, Array <int> &kvdir)
3813 const int dim = Dimension();
3820 GetPatchDirectionEdges(p, edges);
3821 // In 1D, the sign of edge_to_ukv encodes the per-patch orientation.
3822 kvdir[0] = KnotSign(edges[0]);
3826 Array<int> patchvert, edges, orient, edgevert;
3828 patchTopo->GetElementVertices(p, patchvert);
3830 patchTopo->GetElementEdges(p, edges, orient);
3832 // Compare the vertices of the patches with the vertices of the knotvectors of knot2dge
3833 // Based on the match the orientation will be a 1 or a -1
3834 // -1: direction is flipped
3835 // 1: direction is not flipped
3837 for (int i = 0; i < edges.Size(); i++)
3840 patchTopo->GetEdgeVertices(edges[i], edgevert);
3841 const int ks = KnotSign(edges[i]);
3842 if (edgevert[0] == patchvert[0] && edgevert[1] == patchvert[1])
3847 if (edgevert[0] == patchvert[1] && edgevert[1] == patchvert[0])
3853 if (edgevert[0] == patchvert[0] && edgevert[1] == patchvert[3])
3858 if (edgevert[0] == patchvert[3] && edgevert[1] == patchvert[0])
3864 if (Dimension() == 3)
3867 for (int i = 0; i < edges.Size(); i++)
3869 patchTopo->GetEdgeVertices(edges[i], edgevert);
3870 const int ks = KnotSign(edges[i]);
3872 if (edgevert[0] == patchvert[0] && edgevert[1] == patchvert[4])
3877 if (edgevert[0] == patchvert[4] && edgevert[1] == patchvert[0])
3884 MFEM_VERIFY(kvdir.Find(0) == -1, "Could not find
direction of knotvector.
");
3887void NURBSExtension::CreateComprehensiveKV()
3889 const int dim = Dimension();
3890 Array<int> edges, kvdir;
3892 knotVectorsCompr.SetSize(GetNP()*dim);
3894 for (int p = 0; p < GetNP(); p++)
3896 GetPatchDirectionEdges(p, edges);
3897 CheckKVDirection(p, kvdir);
3899 for (int d = 0; d < dim; d++)
3901 // Indices in unique and comprehensive sets of the KnotVector
3902 const int iun = edges[d];
3903 const int icomp = dim*p + d;
3904 knotVectorsCompr[icomp] = new KnotVector(*(KnotVec(iun)));
3905 if (kvdir[d] == -1) { knotVectorsCompr[icomp]->Flip(); }
3909 MFEM_VERIFY(ConsistentKVSets(), "Mismatch in KnotVectors
");
3912void NURBSExtension::UpdateUniqueKV()
3914 const int dim = Dimension();
3915 Array<int> edges, kvdir;
3916 for (int p = 0; p < GetNP(); p++)
3918 GetPatchDirectionEdges(p, edges);
3919 CheckKVDirection(p, kvdir);
3921 for (int d = 0; d < dim; d++)
3923 const bool flip = (kvdir[d] == -1);
3925 // Indices in unique and comprehensive sets of the KnotVector
3926 const int iun = edges[d];
3927 const int icomp = dim*p + d;
3929 // Check if difference in order/element count
3930 const int o1 = KnotVec(iun)->GetOrder();
3931 const int o2 = knotVectorsCompr[icomp]->GetOrder();
3932 const int diffo = abs(o1 - o2);
3934 const int ne1 = KnotVec(iun)->GetNE();
3935 const int ne2 = knotVectorsCompr[icomp]->GetNE();
3937 if (diffo || ne1 != ne2)
3939 // Update reduced set of knotvectors
3940 *(KnotVec(iun)) = *(knotVectorsCompr[icomp]);
3942 // Give correct direction to unique knotvector.
3943 if (flip) { KnotVec(iun)->Flip(); }
3946 // Check if difference between knots
3949 if (flip) { knotVectorsCompr[icomp]->Flip(); }
3951 KnotVec(iun)->Difference(*(knotVectorsCompr[icomp]), diffknot);
3953 if (flip) { knotVectorsCompr[icomp]->Flip(); }
3955 if (diffknot.Size() > 0)
3957 // Update reduced set of knotvectors
3958 *(KnotVec(iun)) = *(knotVectorsCompr[icomp]);
3960 // Give correct direction to unique knotvector.
3961 if (flip) {KnotVec(iun)->Flip();}
3966 MFEM_VERIFY(ConsistentKVSets(), "Mismatch in KnotVectors
");
3969bool NURBSExtension::ConsistentKVSets()
3971 const int dim = Dimension();
3972 Array<int> edges, kvdir;
3975 for (int p = 0; p < GetNP(); p++)
3977 GetPatchDirectionEdges(p, edges);
3978 CheckKVDirection(p, kvdir);
3980 for (int d = 0; d < dim; d++)
3982 const bool flip = (kvdir[d] == -1);
3984 // Indices in unique and comprehensive sets of the KnotVector
3985 const int iun = edges[d];
3986 const int icomp = dim*p + d;
3988 // Check if KnotVectors are of equal order
3989 const int o1 = KnotVec(iun)->GetOrder();
3990 const int o2 = knotVectorsCompr[icomp]->GetOrder();
3991 const int diffo = abs(o1 - o2);
3994 mfem::out << "\norder of knotVectorsCompr
" << d << " of patch
" << p;
3995 mfem::out << " does not agree with knotVectors
" << KnotInd(iun) << "\n
";
3999 // Check if KnotVectors have the same knots. The comprehensive set is
4000 // stored in the per-patch orientation, while the unique set uses the
4001 // canonical orientation encoded in edge_to_ukv.
4002 if (flip) { knotVectorsCompr[icomp]->Flip(); }
4003 KnotVec(iun)->Difference(*(knotVectorsCompr[icomp]), diff);
4004 if (flip) { knotVectorsCompr[icomp]->Flip(); }
4006 if (diff.Size() > 0)
4008 mfem::out << "\nknotVectorsCompr
" << d << " of patch
" << p;
4009 mfem::out << " does not agree with knotVectors
" << KnotInd(iun) << "\n
";
4017void NURBSExtension::GetPatchKnotVectors(int p, Array<KnotVector *> &kv)
4019 Array<int> edges, orient;
4021 kv.SetSize(Dimension());
4023 if (Dimension() == 1)
4025 kv[0] = knotVectorsCompr[Dimension()*p];
4027 else if (Dimension() == 2)
4029 kv[0] = knotVectorsCompr[Dimension()*p];
4030 kv[1] = knotVectorsCompr[Dimension()*p + 1];
4034 kv[0] = knotVectorsCompr[Dimension()*p];
4035 kv[1] = knotVectorsCompr[Dimension()*p + 1];
4036 kv[2] = knotVectorsCompr[Dimension()*p + 2];
4040void NURBSExtension::GetPatchKnotVectors(int p, Array<const KnotVector *> &kv)
4043 kv.SetSize(Dimension());
4045 if (Dimension() == 1)
4047 kv[0] = knotVectorsCompr[Dimension()*p];
4049 else if (Dimension() == 2)
4051 kv[0] = knotVectorsCompr[Dimension()*p];
4052 kv[1] = knotVectorsCompr[Dimension()*p + 1];
4056 kv[0] = knotVectorsCompr[Dimension()*p];
4057 kv[1] = knotVectorsCompr[Dimension()*p + 1];
4058 kv[2] = knotVectorsCompr[Dimension()*p + 2];
4062void NURBSExtension::GetBdrPatchKnotVectors(int bp, Array<KnotVector *> &kv)
4067 kv.SetSize(Dimension() - 1);
4069 if (Dimension() == 2)
4071 patchTopo->GetBdrElementEdges(bp, edges, orient);
4072 kv[0] = KnotVec(edges[0]);
4074 else if (Dimension() == 3)
4076 patchTopo->GetBdrElementEdges(bp, edges, orient);
4077 kv[0] = KnotVec(edges[0]);
4078 kv[1] = KnotVec(edges[1]);
4082void NURBSExtension::GetBdrPatchKnotVectors(
4083 int bp, Array<const KnotVector *> &kv) const
4088 kv.SetSize(Dimension() - 1);
4090 if (Dimension() == 2)
4092 patchTopo->GetBdrElementEdges(bp, edges, orient);
4093 kv[0] = KnotVec(edges[0]);
4095 else if (Dimension() == 3)
4097 patchTopo->GetBdrElementEdges(bp, edges, orient);
4098 kv[0] = KnotVec(edges[0]);
4099 kv[1] = KnotVec(edges[1]);
4103void NURBSExtension::SetOrderFromOrders()
4105 MFEM_VERIFY(mOrders.Size() > 0, "");
4106 mOrder = mOrders[0];
4107 for (int i = 1; i < mOrders.Size(); i++)
4109 if (mOrders[i] != mOrder)
4111 mOrder = NURBSFECollection::VariableOrder;
4117void NURBSExtension::SetOrdersFromKnotVectors()
4119 mOrders.SetSize(NumOfKnotVectors);
4120 for (int i = 0; i < NumOfKnotVectors; i++)
4122 mOrders[i] = knotVectors[i]->GetOrder();
4124 SetOrderFromOrders();
4127void NURBSExtension::GenerateOffsets()
4129 const int nv = patchTopo->GetNV();
4130 const int ne = patchTopo->GetNEdges();
4131 const int nf = patchTopo->GetNFaces();
4132 const int np = patchTopo->GetNE();
4133 int meshCounter, spaceCounter;
4135 Array<int> edges, orient;
4137 v_meshOffsets.SetSize(nv);
4138 e_meshOffsets.SetSize(ne);
4139 f_meshOffsets.SetSize(nf);
4140 p_meshOffsets.SetSize(np);
4142 v_spaceOffsets.SetSize(nv);
4143 e_spaceOffsets.SetSize(ne);
4144 f_spaceOffsets.SetSize(nf);
4145 p_spaceOffsets.SetSize(np);
4147 // Get vertex offsets
4148 for (meshCounter = 0; meshCounter < nv; meshCounter++)
4150 v_meshOffsets[meshCounter] = meshCounter;
4151 v_spaceOffsets[meshCounter] = meshCounter;
4153 spaceCounter = meshCounter;
4156 for (int e = 0; e < ne; e++)
4158 e_meshOffsets[e] = meshCounter;
4159 e_spaceOffsets[e] = spaceCounter;
4160 meshCounter += KnotVec(e)->GetNE() - 1;
4161 spaceCounter += KnotVec(e)->GetNCP() - 2;
4165 for (int f = 0; f < nf; f++)
4167 f_meshOffsets[f] = meshCounter;
4168 f_spaceOffsets[f] = spaceCounter;
4170 patchTopo->GetFaceEdges(f, edges, orient);
4173 (KnotVec(edges[0])->GetNE() - 1) *
4174 (KnotVec(edges[1])->GetNE() - 1);
4176 (KnotVec(edges[0])->GetNCP() - 2) *
4177 (KnotVec(edges[1])->GetNCP() - 2);
4180 // Get patch offsets
4181 GetPatchOffsets(meshCounter, spaceCounter);
4183 NumOfVertices = meshCounter;
4184 NumOfDofs = spaceCounter;
4187void NURBSExtension::GetPatchOffsets(int &meshCounter, int &spaceCounter)
4189 const int np = patchTopo->GetNE();
4190 const int dim = Dimension();
4191 Array<int> edges, orient;
4192 for (int p = 0; p < np; p++)
4194 p_meshOffsets[p] = meshCounter;
4195 p_spaceOffsets[p] = spaceCounter;
4199 meshCounter += KnotVec(p)->GetNE() - 1;
4200 spaceCounter += KnotVec(p)->GetNCP() - 2;
4204 patchTopo->GetElementEdges(p, edges, orient);
4206 (KnotVec(edges[0])->GetNE() - 1) *
4207 (KnotVec(edges[1])->GetNE() - 1);
4209 (KnotVec(edges[0])->GetNCP() - 2) *
4210 (KnotVec(edges[1])->GetNCP() - 2);
4214 patchTopo->GetElementEdges(p, edges, orient);
4216 (KnotVec(edges[0])->GetNE() - 1) *
4217 (KnotVec(edges[3])->GetNE() - 1) *
4218 (KnotVec(edges[8])->GetNE() - 1);
4220 (KnotVec(edges[0])->GetNCP() - 2) *
4221 (KnotVec(edges[3])->GetNCP() - 2) *
4222 (KnotVec(edges[8])->GetNCP() - 2);
4227void NURBSExtension::CountElements()
4229 int dim = Dimension();
4230 Array<const KnotVector *> kv(dim);
4233 for (int p = 0; p < GetNP(); p++)
4235 GetPatchKnotVectors(p, kv);
4237 int ne = kv[0]->GetNE();
4238 for (int d = 1; d < dim; d++)
4240 ne *= kv[d]->GetNE();
4243 NumOfElements += ne;
4247void NURBSExtension::CountBdrElements()
4249 int dim = Dimension() - 1;
4250 Array<KnotVector *> kv(dim);
4252 NumOfBdrElements = 0;
4253 for (int p = 0; p < GetNBP(); p++)
4255 GetBdrPatchKnotVectors(p, kv);
4258 for (int d = 0; d < dim; d++)
4260 ne *= kv[d]->GetNE();
4263 NumOfBdrElements += ne;
4267void NURBSExtension::GetElementTopo(Array<Element *> &elements) const
4269 elements.SetSize(GetNE());
4271 if (Dimension() == 1)
4273 Get1DElementTopo(elements);
4275 else if (Dimension() == 2)
4277 Get2DElementTopo(elements);
4281 Get3DElementTopo(elements);
4285void NURBSExtension::Get1DElementTopo(Array<Element *> &elements) const
4290 NURBSPatchMap p2g(this);
4291 const KnotVector *kv[1];
4293 for (int p = 0; p < GetNP(); p++)
4295 p2g.SetPatchVertexMap(p, kv);
4298 int patch_attr = patchTopo->GetAttribute(p);
4300 for (int i = 0; i < nx; i++)
4304 ind[0] = activeVert[p2g(i)];
4305 ind[1] = activeVert[p2g(i+1)];
4307 elements[el] = new Segment(ind, patch_attr);
4315void NURBSExtension::Get2DElementTopo(Array<Element *> &elements) const
4320 NURBSPatchMap p2g(this);
4321 const KnotVector *kv[2];
4323 for (int p = 0; p < GetNP(); p++)
4325 p2g.SetPatchVertexMap(p, kv);
4329 int patch_attr = patchTopo->GetAttribute(p);
4331 for (int j = 0; j < ny; j++)
4333 for (int i = 0; i < nx; i++)
4337 ind[0] = activeVert[p2g(i, j )];
4338 ind[1] = activeVert[p2g(i+1,j )];
4339 ind[2] = activeVert[p2g(i+1,j+1)];
4340 ind[3] = activeVert[p2g(i, j+1)];
4342 elements[el] = new Quadrilateral(ind, patch_attr);
4351void NURBSExtension::Get3DElementTopo(Array<Element *> &elements) const
4356 NURBSPatchMap p2g(this);
4357 const KnotVector *kv[3];
4359 for (int p = 0; p < GetNP(); p++)
4361 p2g.SetPatchVertexMap(p, kv);
4366 int patch_attr = patchTopo->GetAttribute(p);
4368 for (int k = 0; k < nz; k++)
4370 for (int j = 0; j < ny; j++)
4372 for (int i = 0; i < nx; i++)
4376 ind[0] = activeVert[p2g(i, j, k)];
4377 ind[1] = activeVert[p2g(i+1,j, k)];
4378 ind[2] = activeVert[p2g(i+1,j+1,k)];
4379 ind[3] = activeVert[p2g(i, j+1,k)];
4381 ind[4] = activeVert[p2g(i, j, k+1)];
4382 ind[5] = activeVert[p2g(i+1,j, k+1)];
4383 ind[6] = activeVert[p2g(i+1,j+1,k+1)];
4384 ind[7] = activeVert[p2g(i, j+1,k+1)];
4386 elements[el] = new Hexahedron(ind, patch_attr);
4396void NURBSExtension::GetBdrElementTopo(Array<Element *> &boundary) const
4398 boundary.SetSize(GetNBE());
4400 if (Dimension() == 1)
4402 Get1DBdrElementTopo(boundary);
4404 else if (Dimension() == 2)
4406 Get2DBdrElementTopo(boundary);
4410 Get3DBdrElementTopo(boundary);
4414void NURBSExtension::Get1DBdrElementTopo(Array<Element *> &boundary) const
4418 NURBSPatchMap p2g(this);
4419 const KnotVector *kv[1];
4422 for (int b = 0; b < GetNBP(); b++)
4424 p2g.SetBdrPatchVertexMap(b, kv, okv);
4425 int bdr_patch_attr = patchTopo->GetBdrAttribute(b);
4427 if (activeBdrElem[g_be])
4429 ind[0] = activeVert[p2g[0]];
4430 boundary[l_be] = new Point(ind, bdr_patch_attr);
4437void NURBSExtension::Get2DBdrElementTopo(Array<Element *> &boundary) const
4441 NURBSPatchMap p2g(this);
4442 const KnotVector *kv[1];
4445 for (int b = 0; b < GetNBP(); b++)
4447 p2g.SetBdrPatchVertexMap(b, kv, okv);
4450 int bdr_patch_attr = patchTopo->GetBdrAttribute(b);
4452 for (int i = 0; i < nx; i++)
4454 if (activeBdrElem[g_be])
4456 int i_ = (okv[0] >= 0) ? i : (nx - 1 - i);
4457 ind[0] = activeVert[p2g[i_ ]];
4458 ind[1] = activeVert[p2g[i_+1]];
4460 boundary[l_be] = new Segment(ind, bdr_patch_attr);
4468void NURBSExtension::Get3DBdrElementTopo(Array<Element *> &boundary) const
4472 NURBSPatchMap p2g(this);
4473 const KnotVector *kv[2];
4476 for (int b = 0; b < GetNBP(); b++)
4478 p2g.SetBdrPatchVertexMap(b, kv, okv);
4482 int bdr_patch_attr = patchTopo->GetBdrAttribute(b);
4484 for (int j = 0; j < ny; j++)
4486 int j_ = (okv[1] >= 0) ? j : (ny - 1 - j);
4487 for (int i = 0; i < nx; i++)
4489 if (activeBdrElem[g_be])
4491 int i_ = (okv[0] >= 0) ? i : (nx - 1 - i);
4492 ind[0] = activeVert[p2g(i_, j_ )];
4493 ind[1] = activeVert[p2g(i_+1,j_ )];
4494 ind[2] = activeVert[p2g(i_+1,j_+1)];
4495 ind[3] = activeVert[p2g(i_, j_+1)];
4497 boundary[l_be] = new Quadrilateral(ind, bdr_patch_attr);
4506void NURBSExtension::GenerateElementDofTable()
4508 activeDof.SetSize(GetNTotalDof());
4511 if (Dimension() == 1)
4513 Generate1DElementDofTable();
4515 else if (Dimension() == 2)
4517 Generate2DElementDofTable();
4521 Generate3DElementDofTable();
4524 SetPatchToElements();
4526 NumOfActiveDofs = 0;
4527 for (int d = 0; d < GetNTotalDof(); d++)
4531 activeDof[d] = NumOfActiveDofs;
4534 int *dof = el_dof->GetJ();
4535 int ndof = el_dof->Size_of_connections();
4536 for (int i = 0; i < ndof; i++)
4538 dof[i] = activeDof[dof[i]] - 1;
4542void NURBSExtension::Generate1DElementDofTable()
4546 const KnotVector *kv[2];
4547 NURBSPatchMap p2g(this);
4549 Array<Connection> el_dof_list;
4550 el_to_patch.SetSize(NumOfActiveElems);
4551 el_to_IJK.SetSize(NumOfActiveElems, 2);
4553 for (int p = 0; p < GetNP(); p++)
4555 p2g.SetPatchDofMap(p, kv);
4558 const int ord0 = kv[0]->GetOrder();
4559 for (int i = 0; i < kv[0]->GetNKS(); i++)
4561 if (kv[0]->isElement(i))
4565 Connection conn(el,0);
4566 for (int ii = 0; ii <= ord0; ii++)
4568 conn.to = DofMap(p2g(i+ii));
4569 activeDof[conn.to] = 1;
4570 el_dof_list.Append(conn);
4572 el_to_patch[el] = p;
4573 el_to_IJK(el,0) = i;
4581 // We must NOT sort el_dof_list in this case.
4582 el_dof = new Table(NumOfActiveElems, el_dof_list);
4585void NURBSExtension::Generate2DElementDofTable()
4589 const KnotVector *kv[2];
4590 NURBSPatchMap p2g(this);
4592 Array<Connection> el_dof_list;
4593 el_to_patch.SetSize(NumOfActiveElems);
4594 el_to_IJK.SetSize(NumOfActiveElems, 2);
4596 for (int p = 0; p < GetNP(); p++)
4598 p2g.SetPatchDofMap(p, kv);
4601 const int ord0 = kv[0]->GetOrder();
4602 const int ord1 = kv[1]->GetOrder();
4603 for (int j = 0; j < kv[1]->GetNKS(); j++)
4605 if (kv[1]->isElement(j))
4607 for (int i = 0; i < kv[0]->GetNKS(); i++)
4609 if (kv[0]->isElement(i))
4613 Connection conn(el,0);
4614 for (int jj = 0; jj <= ord1; jj++)
4616 for (int ii = 0; ii <= ord0; ii++)
4618 conn.to = DofMap(p2g(i+ii,j+jj));
4619 activeDof[conn.to] = 1;
4620 el_dof_list.Append(conn);
4623 el_to_patch[el] = p;
4624 el_to_IJK(el,0) = i;
4625 el_to_IJK(el,1) = j;
4635 // We must NOT sort el_dof_list in this case.
4636 el_dof = new Table(NumOfActiveElems, el_dof_list);
4639void NURBSExtension::Generate3DElementDofTable()
4643 const KnotVector *kv[3];
4644 NURBSPatchMap p2g(this);
4646 Array<Connection> el_dof_list;
4647 el_to_patch.SetSize(NumOfActiveElems);
4648 el_to_IJK.SetSize(NumOfActiveElems, 3);
4650 for (int p = 0; p < GetNP(); p++)
4652 p2g.SetPatchDofMap(p, kv);
4655 const int ord0 = kv[0]->GetOrder();
4656 const int ord1 = kv[1]->GetOrder();
4657 const int ord2 = kv[2]->GetOrder();
4658 for (int k = 0; k < kv[2]->GetNKS(); k++)
4660 if (kv[2]->isElement(k))
4662 for (int j = 0; j < kv[1]->GetNKS(); j++)
4664 if (kv[1]->isElement(j))
4666 for (int i = 0; i < kv[0]->GetNKS(); i++)
4668 if (kv[0]->isElement(i))
4672 Connection conn(el,0);
4673 for (int kk = 0; kk <= ord2; kk++)
4675 for (int jj = 0; jj <= ord1; jj++)
4677 for (int ii = 0; ii <= ord0; ii++)
4679 conn.to = DofMap(p2g(i+ii, j+jj, k+kk));
4680 activeDof[conn.to] = 1;
4681 el_dof_list.Append(conn);
4686 el_to_patch[el] = p;
4687 el_to_IJK(el,0) = i;
4688 el_to_IJK(el,1) = j;
4689 el_to_IJK(el,2) = k;
4701 // We must NOT sort el_dof_list in this case.
4702 el_dof = new Table(NumOfActiveElems, el_dof_list);
4705void NURBSExtension::GetPatchDofs(const int patch, Array<int> &dofs)
4707 const KnotVector *kv[3];
4708 NURBSPatchMap p2g(this);
4710 p2g.SetPatchDofMap(patch, kv);
4712 if (Dimension() == 1)
4714 const int nx = kv[0]->GetNCP();
4717 for (int i=0; i<nx; ++i)
4719 dofs[i] = DofMap(p2g(i));
4722 else if (Dimension() == 2)
4724 const int nx = kv[0]->GetNCP();
4725 const int ny = kv[1]->GetNCP();
4726 dofs.SetSize(nx * ny);
4728 for (int j=0; j<ny; ++j)
4729 for (int i=0; i<nx; ++i)
4731 dofs[i + (nx * j)] = DofMap(p2g(i, j));
4734 else if (Dimension() == 3)
4736 const int nx = kv[0]->GetNCP();
4737 const int ny = kv[1]->GetNCP();
4738 const int nz = kv[2]->GetNCP();
4739 dofs.SetSize(nx * ny * nz);
4741 for (int k=0; k<nz; ++k)
4742 for (int j=0; j<ny; ++j)
4743 for (int i=0; i<nx; ++i)
4745 dofs[i + (nx * (j + (k * ny)))] = DofMap(p2g(i, j, k));
4750 MFEM_ABORT("Only 1D/2D/3D supported currently in
NURBSExtension::GetPatchDofs
");
4754void NURBSExtension::GenerateBdrElementDofTable()
4756 if (Dimension() == 1)
4758 Generate1DBdrElementDofTable();
4760 else if (Dimension() == 2)
4762 Generate2DBdrElementDofTable();
4766 Generate3DBdrElementDofTable();
4769 SetPatchToBdrElements();
4771 int *dof = bel_dof->GetJ();
4772 const int ndof = bel_dof->Size_of_connections();
4773 for (int i = 0; i < ndof; i++)
4775 const int idx = dof[i];
4778 dof[i] = -activeDof[FlipIndexSign(idx)];
4782 dof[i] = activeDof[idx] - 1;
4787void NURBSExtension::Generate1DBdrElementDofTable()
4790 int lbe = 0, okv[1];
4791 const KnotVector *kv[1];
4792 NURBSPatchMap p2g(this);
4794 Array<Connection> bel_dof_list;
4795 bel_to_patch.SetSize(NumOfActiveBdrElems);
4796 bel_to_IJK.SetSize(NumOfActiveBdrElems, 1);
4798 for (int b = 0; b < GetNBP(); b++)
4800 p2g.SetBdrPatchDofMap(b, kv, okv);
4802 if (activeBdrElem[gbe])
4804 Connection conn(lbe,0);
4805 conn.to = DofMap(p2g[0]);
4806 bel_dof_list.Append(conn);
4807 bel_to_patch[lbe] = b;
4808 bel_to_IJK(lbe,0) = 0;
4813 // We must NOT sort bel_dof_list in this case.
4814 bel_dof = new Table(NumOfActiveBdrElems, bel_dof_list);
4817void NURBSExtension::Generate2DBdrElementDofTable()
4820 int lbe = 0, okv[1];
4821 const KnotVector *kv[1];
4822 NURBSPatchMap p2g(this);
4824 Array<Connection> bel_dof_list;
4825 bel_to_patch.SetSize(NumOfActiveBdrElems);
4826 bel_to_IJK.SetSize(NumOfActiveBdrElems, 1);
4828 for (int b = 0; b < GetNBP(); b++)
4830 p2g.SetBdrPatchDofMap(b, kv, okv);
4831 const int nx = p2g.nx(); // NCP-1
4833 const int nks0 = kv[0]->GetNKS();
4834 const int ord0 = kv[0]->GetOrder();
4836 bool add_dofs = true;
4839 if (mode == Mode::H_DIV)
4841 int fn = patchTopo->GetBdrElementFaceIndex(b);
4842 if (ord0 == mOrders.Max()) { add_dofs = false; }
4843 if (fn == 0) { s = -1; }
4844 if (fn == 2) { s = -1; }
4846 else if (mode == Mode::H_CURL)
4848 if (ord0 == mOrders.Max()) { add_dofs = false; }
4851 for (int i = 0; i < nks0; i++)
4853 if (kv[0]->isElement(i))
4855 if (activeBdrElem[gbe])
4857 Connection conn(lbe,0);
4860 for (int ii = 0; ii <= ord0; ii++)
4862 conn.to = DofMap(p2g[(okv[0] >= 0) ? (i+ii) : (nx-i-ii)]);
4863 if (s == -1) { conn.to = FlipIndexSign(conn.to); }
4864 bel_dof_list.Append(conn);
4867 bel_to_patch[lbe] = b;
4868 bel_to_IJK(lbe,0) = (okv[0] >= 0) ? i : FlipIndexSign(i);
4875 // We must NOT sort bel_dof_list in this case.
4876 bel_dof = new Table(NumOfActiveBdrElems, bel_dof_list);
4880void NURBSExtension::Generate3DBdrElementDofTable()
4883 int lbe = 0, okv[2];
4884 const KnotVector *kv[2];
4885 NURBSPatchMap p2g(this);
4887 Array<Connection> bel_dof_list;
4888 bel_to_patch.SetSize(NumOfActiveBdrElems);
4889 bel_to_IJK.SetSize(NumOfActiveBdrElems, 2);
4891 for (int b = 0; b < GetNBP(); b++)
4893 p2g.SetBdrPatchDofMap(b, kv, okv);
4894 const int nx = p2g.nx(); // NCP0-1
4895 const int ny = p2g.ny(); // NCP1-1
4898 const int nks0 = kv[0]->GetNKS();
4899 const int ord0 = kv[0]->GetOrder();
4900 const int nks1 = kv[1]->GetNKS();
4901 const int ord1 = kv[1]->GetOrder();
4903 // Check if dofs are actually defined on boundary
4904 bool add_dofs = true;
4907 if (mode == Mode::H_DIV)
4909 int fn = patchTopo->GetBdrElementFaceIndex(b);
4910 if (ord0 != ord1) { add_dofs = false; }
4911 if (fn == 4) { s = -1; }
4912 if (fn == 1) { s = -1; }
4913 if (fn == 0) { s = -1; }
4915 else if (mode == Mode::H_CURL)
4917 if (ord0 == ord1) { add_dofs = false; }
4921 for (int j = 0; j < nks1; j++)
4923 if (kv[1]->isElement(j))
4925 for (int i = 0; i < nks0; i++)
4927 if (kv[0]->isElement(i))
4929 if (activeBdrElem[gbe])
4931 Connection conn(lbe,0);
4934 for (int jj = 0; jj <= ord1; jj++)
4936 const int jj_ = (okv[1] >= 0) ? (j+jj) : (ny-j-jj);
4937 for (int ii = 0; ii <= ord0; ii++)
4939 const int ii_ = (okv[0] >= 0) ? (i+ii) : (nx-i-ii);
4940 conn.to = DofMap(p2g(ii_, jj_));
4941 if (s == -1) { conn.to = FlipIndexSign(conn.to); }
4942 bel_dof_list.Append(conn);
4946 bel_to_patch[lbe] = b;
4947 bel_to_IJK(lbe,0) = (okv[0] >= 0) ? i : FlipIndexSign(i);
4948 bel_to_IJK(lbe,1) = (okv[1] >= 0) ? j : FlipIndexSign(j);
4957 // We must NOT sort bel_dof_list in this case.
4958 bel_dof = new Table(NumOfActiveBdrElems, bel_dof_list);
4961void NURBSExtension::GetVertexLocalToGlobal(Array<int> &lvert_vert)
4963 lvert_vert.SetSize(GetNV());
4964 for (int gv = 0; gv < GetGNV(); gv++)
4965 if (activeVert[gv] >= 0)
4967 lvert_vert[activeVert[gv]] = gv;
4971void NURBSExtension::GetElementLocalToGlobal(Array<int> &lelem_elem)
4973 lelem_elem.SetSize(GetNE());
4974 for (int le = 0, ge = 0; ge < GetGNE(); ge++)
4977 lelem_elem[le++] = ge;
4981void NURBSExtension::LoadFE(int i, const FiniteElement *FE) const
4983 const NURBSFiniteElement *NURBSFE =
4984 dynamic_cast<const NURBSFiniteElement *>(FE);
4986 if (NURBSFE->GetElement() != i)
4989 NURBSFE->SetIJK(el_to_IJK.GetRow(i));
4990 if (el_to_patch[i] != NURBSFE->GetPatch())
4992 GetPatchKnotVectors(el_to_patch[i], NURBSFE->KnotVectors());
4993 NURBSFE->SetPatch(el_to_patch[i]);
4994 NURBSFE->SetOrder();
4996 el_dof->GetRow(i, dofs);
4997 weights.GetSubVector(dofs, NURBSFE->Weights());
4998 NURBSFE->SetElement(i);
5002void NURBSExtension::LoadBE(int i, const FiniteElement *BE) const
5004 if (Dimension() == 1) { return; }
5006 const NURBSFiniteElement *NURBSFE =
5007 dynamic_cast<const NURBSFiniteElement *>(BE);
5009 if (NURBSFE->GetElement() != i)
5012 NURBSFE->SetIJK(bel_to_IJK.GetRow(i));
5013 if (bel_to_patch[i] != NURBSFE->GetPatch())
5015 GetBdrPatchKnotVectors(bel_to_patch[i], NURBSFE->KnotVectors());
5016 NURBSFE->SetPatch(bel_to_patch[i]);
5017 NURBSFE->SetOrder();
5019 bel_dof->GetRow(i, dofs);
5020 weights.GetSubVector(dofs, NURBSFE->Weights());
5021 NURBSFE->SetElement(i);
5025void NURBSExtension::ConvertToPatches(const Vector &Nodes)
5030 if (patches.Size() == 0)
5032 // Determine the physical vector dimension from the coordinate vector and
5033 // the number of DOFs. This is needed in particular for curves/surfaces
5034 // embedded in higher-dimensional physical spaces.
5035 MFEM_VERIFY(GetNDof() > 0,
5037 MFEM_VERIFY(Nodes.Size() % GetNDof() == 0,
5038 "NURBSExtension::ConvertToPatches: coordinate size not divisible by DOFs.
");
5039 const int phys_vdim = Nodes.Size() / GetNDof();
5040 GetPatchNets(Nodes, phys_vdim);
5044void NURBSExtension::SetCoordsFromPatches(Vector &Nodes, int vdim)
5046 if (patches.Size() == 0) { return; }
5048 SetSolutionVector(Nodes, vdim);
5052void NURBSExtension::SetKnotsFromPatches()
5054 if (patches.Size() == 0)
5057 " No patches available!
");
5060 Array<KnotVector *> kv;
5062 for (int p = 0; p < patches.Size(); p++)
5064 GetPatchKnotVectors(p, kv);
5066 for (int i = 0; i < kv.Size(); i++)
5068 *kv[i] = *patches[p]->GetKV(i);
5073 SetOrdersFromKnotVectors();
5079 // all elements must be active
5080 NumOfActiveElems = NumOfElements;
5081 activeElem.SetSize(NumOfElements);
5084 GenerateActiveVertices();
5086 GenerateElementDofTable();
5087 GenerateActiveBdrElems();
5088 GenerateBdrElementDofTable();
5090 ConnectBoundaries();
5093void NURBSExtension::LoadSolution(std::istream &input, GridFunction &sol) const
5095 const FiniteElementSpace *fes = sol.FESpace();
5096 MFEM_VERIFY(fes->GetNURBSext() == this, "");
5098 sol.SetSize(fes->GetVSize());
5100 Array<const KnotVector *> kv(Dimension());
5101 NURBSPatchMap p2g(this);
5102 const int vdim = fes->GetVDim();
5104 for (int p = 0; p < GetNP(); p++)
5106 skip_comment_lines(input, '#');
5108 p2g.SetPatchDofMap(p, kv);
5109 const int nx = kv[0]->GetNCP();
5110 const int ny = kv[1]->GetNCP();
5111 const int nz = (kv.Size() == 2) ? 1 : kv[2]->GetNCP();
5112 for (int k = 0; k < nz; k++)
5114 for (int j = 0; j < ny; j++)
5116 for (int i = 0; i < nx; i++)
5118 const int ll = (kv.Size() == 2) ? p2g(i,j) : p2g(i,j,k);
5119 const int l = DofMap(ll);
5120 for (int vd = 0; vd < vdim; vd++)
5122 input >> sol(fes->DofToVDof(l,vd));
5130void NURBSExtension::PrintSolution(const GridFunction &sol, std::ostream &os)
5133 const FiniteElementSpace *fes = sol.FESpace();
5134 MFEM_VERIFY(fes->GetNURBSext() == this, "");
5136 Array<const KnotVector *> kv(Dimension());
5137 NURBSPatchMap p2g(this);
5138 const int vdim = fes->GetVDim();
5140 for (int p = 0; p < GetNP(); p++)
5142 os << "\n# patch
" << p << "\n\n
";
5144 p2g.SetPatchDofMap(p, kv);
5145 const int nx = kv[0]->GetNCP();
5146 const int ny = kv[1]->GetNCP();
5147 const int nz = (kv.Size() == 2) ? 1 : kv[2]->GetNCP();
5148 for (int k = 0; k < nz; k++)
5150 for (int j = 0; j < ny; j++)
5152 for (int i = 0; i < nx; i++)
5154 const int ll = (kv.Size() == 2) ? p2g(i,j) : p2g(i,j,k);
5155 const int l = DofMap(ll);
5156 os << sol(fes->DofToVDof(l,0));
5157 for (int vd = 1; vd < vdim; vd++)
5159 os << ' ' << sol(fes->DofToVDof(l,vd));
5168void NURBSExtension::DegreeElevate(int rel_degree, int degree)
5170 for (int p = 0; p < patches.Size(); p++)
5172 for (int dir = 0; dir < patches[p]->GetNKV(); dir++)
5174 int oldd = patches[p]->GetKV(dir)->GetOrder();
5175 int newd = std::min(oldd + rel_degree, degree);
5178 patches[p]->DegreeElevate(dir, newd - oldd);
5184NURBSExtension* NURBSExtension::GetDivExtension(int component)
5190 "only works for single patch NURBS meshes
");
5193 Array<int> newOrders = GetOrders();
5194 newOrders[component] += 1;
5196 return new NURBSExtension(this, newOrders, Mode::H_DIV);
5199NURBSExtension* NURBSExtension::GetCurlExtension(int component)
5205 "only works for single patch NURBS meshes
");
5208 Array<int> newOrders = GetOrders();
5209 for (int c = 0; c < newOrders.Size(); c++) { newOrders[c]++; }
5210 newOrders[component] -= 1;
5212 return new NURBSExtension(this, newOrders, Mode::H_CURL);
5215void NURBSExtension::UniformRefinement(const Array<int> &rf)
5217 for (int p = 0; p < patches.Size(); p++)
5219 patches[p]->UniformRefinement(rf);
5223void NURBSExtension::UniformRefinement(int rf)
5225 Array<int> rf_array(Dimension());
5227 UniformRefinement(rf_array);
5230void NURBSExtension::Coarsen(const Array<int> &cf, real_t tol)
5232 // First, mark all knot vectors on all patches as not coarse. This prevents
5233 // coarsening the same knot vector twice.
5234 for (int p = 0; p < patches.Size(); p++)
5236 patches[p]->SetKnotVectorsCoarse(false);
5239 for (int p = 0; p < patches.Size(); p++)
5241 patches[p]->Coarsen(cf, tol);
5244 if (ref_factors.Size() > 0)
5246 MFEM_VERIFY(cf.Size() == ref_factors.Size(), "");
5247 for (int i=0; i<cf.Size(); ++i) { ref_factors[i] /= cf[i]; }
5251void NURBSExtension::FullyCoarsen()
5253 // First, mark all knot vectors on all patches as not coarse. This prevents
5254 // coarsening the same knot vector twice.
5255 for (int p = 0; p < patches.Size(); p++)
5257 patches[p]->SetKnotVectorsCoarse(false);
5260 const int maxOrder = mOrders.Max();
5262 // For degree maxOrder, there are 2*(maxOrder + 1) knots for a single element,
5263 // and the number of control points in each dimension is
5264 // 2*(maxOrder + 1) - maxOrder - 1
5265 const int ncp1D = maxOrder + 1;
5266 const int ncp = static_cast<int>(pow(ncp1D, Dimension()));
5268 for (int p = 0; p < patches.Size(); p++)
5270 if (p < num_structured_patches)
5272 // Use data from patchCP
5273 Array2D<double> pcp(ncp, Dimension());
5274 for (int i=0; i<ncp; ++i)
5276 for (int j=0; j<Dimension(); ++j) { pcp(i, j) = patchCP(p, i, j); }
5279 patches[p]->FullyCoarsen(pcp, ncp1D);
5284void NURBSExtension::Coarsen(int cf, real_t tol)
5286 Array<int> cf_array(Dimension());
5288 Coarsen(cf_array, tol);
5291void NURBSExtension::GetCoarseningFactors(Array<int> & f) const
5294 for (auto patch : patches)
5297 patch->GetCoarseningFactors(pf);
5300 f = pf; // Initialize
5304 MFEM_VERIFY(f.Size() == pf.Size(), "");
5305 for (int i=0; i<f.Size(); ++i)
5307 if (nonconformingPT)
5309 if ((f[i] == 1 && pf[i] != 1) || (pf[i] < f[i] && pf[i] != 1))
5316 MFEM_VERIFY(f[i] == pf[i] || f[i] == 1 || pf[i] == 1,
5317 "Inconsistent patch coarsening factors
");
5318 if (f[i] == 1 && pf[i] != 1)
5328void NURBSExtension::KnotInsert(Array<KnotVector *> &kv)
5330 Array<int> edges, kvdir;
5332 Array<KnotVector *> pkv(Dimension());
5334 for (int p = 0; p < patches.Size(); p++)
5336 GetPatchDirectionEdges(p, edges);
5337 for (int d = 0; d < Dimension(); d++)
5339 pkv[d] = kv[KnotInd(edges[d])];
5342 // Check whether inserted knots should be flipped before inserting.
5343 // Knotvectors are stored in a different array pkvc such that the original
5344 // knots which are inserted are not changed.
5345 // We need those knots for multiple patches so they have to remain original
5346 CheckKVDirection(p, kvdir);
5348 Array<KnotVector *> pkvc(Dimension());
5349 for (int d = 0; d < Dimension(); d++)
5351 pkvc[d] = new KnotVector(*(pkv[d]));
5359 patches[p]->KnotInsert(pkvc);
5360 for (int d = 0; d < Dimension(); d++) { delete pkvc[d]; }
5364void NURBSExtension::KnotInsert(Array<Vector *> &kv)
5366 Array<int> edges, kvdir;
5368 Array<Vector *> pkv(Dimension());
5370 for (int p = 0; p < patches.Size(); p++)
5372 GetPatchDirectionEdges(p, edges);
5373 for (int d = 0; d < Dimension(); d++)
5375 pkv[d] = kv[KnotInd(edges[d])];
5378 // Check whether inserted knots should be flipped before inserting.
5379 // Knotvectors are stored in a different array pkvc such that the original
5380 // knots which are inserted are not changed.
5381 CheckKVDirection(p, kvdir);
5383 Array<Vector *> pkvc(Dimension());
5384 for (int d = 0; d < Dimension(); d++)
5386 pkvc[d] = new Vector(*(pkv[d]));
5390 // Find flip point, for knotvectors that do not have the domain [0:1]
5391 KnotVector *kva = knotVectorsCompr[Dimension()*p+d];
5392 real_t apb = (*kva)[0] + (*kva)[kva->Size()-1];
5395 int size = pkvc[d]->Size();
5396 int ns = static_cast<int>(ceil(size/2.0));
5397 for (int j = 0; j < ns; j++)
5399 real_t tmp = apb - pkvc[d]->Elem(j);
5400 pkvc[d]->Elem(j) = apb - pkvc[d]->Elem(size-1-j);
5401 pkvc[d]->Elem(size-1-j) = tmp;
5406 patches[p]->KnotInsert(pkvc);
5408 for (int i = 0; i < Dimension(); i++) { delete pkvc[i]; }
5412void NURBSExtension::KnotRemove(Array<Vector *> &kv, real_t tol)
5414 Array<int> edges, kvdir;
5416 Array<Vector *> pkv(Dimension());
5418 for (int p = 0; p < patches.Size(); p++)
5420 GetPatchDirectionEdges(p, edges);
5421 for (int d = 0; d < Dimension(); d++)
5423 pkv[d] = kv[KnotInd(edges[d])];
5426 // Check whether knots should be flipped before removing.
5427 CheckKVDirection(p, kvdir);
5429 Array<Vector *> pkvc(Dimension());
5430 for (int d = 0; d < Dimension(); d++)
5432 pkvc[d] = new Vector(*(pkv[d]));
5436 // Find flip point, for knotvectors that do not have the domain [0:1]
5437 KnotVector *kva = knotVectorsCompr[Dimension()*p+d];
5438 real_t apb = (*kva)[0] + (*kva)[kva->Size()-1];
5441 int size = pkvc[d]->Size();
5442 int ns = static_cast<int>(ceil(size/2.0));
5443 for (int j = 0; j < ns; j++)
5445 real_t tmp = apb - pkvc[d]->Elem(j);
5446 pkvc[d]->Elem(j) = apb - pkvc[d]->Elem(size-1-j);
5447 pkvc[d]->Elem(size-1-j) = tmp;
5452 patches[p]->KnotRemove(pkvc, tol);
5454 for (int i = 0; i < Dimension(); i++) { delete pkvc[i]; }
5458void NURBSExtension::GetPatchNets(const Vector &coords, int vdim)
5460 if (Dimension() == 1)
5462 Get1DPatchNets(coords, vdim);
5464 else if (Dimension() == 2)
5466 Get2DPatchNets(coords, vdim);
5470 Get3DPatchNets(coords, vdim);
5474void NURBSExtension::Get1DPatchNets(const Vector &coords, int vdim)
5476 Array<const KnotVector *> kv(1);
5477 NURBSPatchMap p2g(this);
5479 patches.SetSize(GetNP());
5480 for (int p = 0; p < GetNP(); p++)
5482 p2g.SetPatchDofMap(p, kv);
5483 patches[p] = new NURBSPatch(kv, vdim+1);
5484 NURBSPatch &Patch = *patches[p];
5486 for (int i = 0; i < kv[0]->GetNCP(); i++)
5488 const int l = DofMap(p2g(i));
5489 for (int d = 0; d < vdim; d++)
5491 Patch(i,d) = coords(l*vdim + d)*weights(l);
5493 Patch(i,vdim) = weights(l);
5498void NURBSExtension::Get2DPatchNets(const Vector &coords, int vdim)
5500 Array<const KnotVector *> kv(2);
5501 NURBSPatchMap p2g(this);
5503 patches.SetSize(GetNP());
5504 for (int p = 0; p < GetNP(); p++)
5506 p2g.SetPatchDofMap(p, kv);
5507 patches[p] = new NURBSPatch(kv, vdim+1);
5508 NURBSPatch &Patch = *patches[p];
5510 for (int j = 0; j < kv[1]->GetNCP(); j++)
5512 for (int i = 0; i < kv[0]->GetNCP(); i++)
5514 const int l = DofMap(p2g(i,j));
5515 for (int d = 0; d < vdim; d++)
5517 Patch(i,j,d) = coords(l*vdim + d)*weights(l);
5519 Patch(i,j,vdim) = weights(l);
5525void NURBSExtension::Get3DPatchNets(const Vector &coords, int vdim)
5527 Array<const KnotVector *> kv(3);
5528 NURBSPatchMap p2g(this);
5530 patches.SetSize(GetNP());
5531 for (int p = 0; p < GetNP(); p++)
5533 p2g.SetPatchDofMap(p, kv);
5534 patches[p] = new NURBSPatch(kv, vdim+1);
5535 NURBSPatch &Patch = *patches[p];
5537 for (int k = 0; k < kv[2]->GetNCP(); k++)
5539 for (int j = 0; j < kv[1]->GetNCP(); j++)
5541 for (int i = 0; i < kv[0]->GetNCP(); i++)
5543 const int l = DofMap(p2g(i,j,k));
5544 for (int d = 0; d < vdim; d++)
5546 Patch(i,j,k,d) = coords(l*vdim + d)*weights(l);
5548 Patch(i,j,k,vdim) = weights(l);
5555void NURBSExtension::SetSolutionVector(Vector &coords, int vdim)
5557 if (Dimension() == 1)
5559 Set1DSolutionVector(coords, vdim);
5561 else if (Dimension() == 2)
5563 Set2DSolutionVector(coords, vdim);
5567 Set3DSolutionVector(coords, vdim);
5571void NURBSExtension::Set1DSolutionVector(Vector &coords, int vdim)
5573 Array<const KnotVector *> kv(1);
5574 NURBSPatchMap p2g(this);
5576 weights.SetSize(GetNDof());
5577 for (int p = 0; p < GetNP(); p++)
5579 p2g.SetPatchDofMap(p, kv);
5580 NURBSPatch &patch = *patches[p];
5581 MFEM_ASSERT(vdim+1 == patch.GetNC(), "");
5583 for (int i = 0; i < kv[0]->GetNCP(); i++)
5585 const int l = p2g(i);
5586 for (int d = 0; d < vdim; d++)
5588 coords(l*vdim + d) = patch(i,d)/patch(i,vdim);
5590 weights(l) = patch(i,vdim);
5597void NURBSExtension::Set2DSolutionVector(Vector &coords, int vdim)
5599 Array<const KnotVector *> kv(2);
5600 NURBSPatchMap p2g(this);
5602 const bool d2p = dof2patch.Size() > 0;
5604 weights.SetSize(GetNDof());
5605 for (int p = 0; p < GetNP(); p++)
5607 p2g.SetPatchDofMap(p, kv);
5608 NURBSPatch &patch = *patches[p];
5609 MFEM_ASSERT(vdim+1 == patch.GetNC(), "");
5611 for (int j = 0; j < kv[1]->GetNCP(); j++)
5613 for (int i = 0; i < kv[0]->GetNCP(); i++)
5615 const int l = p2g(i,j);
5616 if (d2p && dof2patch[l] >= 0 && dof2patch[l] != p) { continue; }
5618 for (int d = 0; d < vdim; d++)
5620 coords(l*vdim + d) = patch(i,j,d)/patch(i,j,vdim);
5622 weights(l) = patch(i,j,vdim);
5629void NURBSExtension::Set3DSolutionVector(Vector &coords, int vdim)
5631 Array<const KnotVector *> kv(3);
5632 NURBSPatchMap p2g(this);
5634 const bool d2p = dof2patch.Size() > 0;
5636 weights.SetSize(GetNDof());
5637 for (int p = 0; p < GetNP(); p++)
5639 p2g.SetPatchDofMap(p, kv);
5640 NURBSPatch &patch = *patches[p];
5641 MFEM_ASSERT(vdim+1 == patch.GetNC(), "");
5643 for (int k = 0; k < kv[2]->GetNCP(); k++)
5645 for (int j = 0; j < kv[1]->GetNCP(); j++)
5647 for (int i = 0; i < kv[0]->GetNCP(); i++)
5649 const int l = p2g(i,j,k);
5650 if (d2p && dof2patch[l] >= 0 && dof2patch[l] != p) { continue; }
5652 for (int d = 0; d < vdim; d++)
5654 coords(l*vdim + d) = patch(i,j,k,d)/patch(i,j,k,vdim);
5656 weights(l) = patch(i,j,k,vdim);
5664void NURBSExtension::GetElementIJK(int elem, Array<int> & ijk)
5666 MFEM_VERIFY(ijk.Size() == el_to_IJK.NumCols(), "");
5667 el_to_IJK.GetRow(elem, ijk);
5670void NURBSExtension::GetPatches(Array<NURBSPatch*> &patches_copy)
5672 const int NP = patches.Size();
5673 patches_copy.SetSize(NP);
5674 for (int p = 0; p < NP; p++)
5676 patches_copy[p] = new NURBSPatch(*GetPatch(p));
5680int NURBSExtension::GetPatchSpaceDimension() const
5682 MFEM_VERIFY(patches.Size() > 0, "NURBS extension has no patches.
");
5684 // Patch dimension includes the weight coordinate.
5685 return patches[0]->GetNC() - 1;
5688void NURBSExtension::SetPatchToElements()
5690 const int np = GetNP();
5691 patch_to_el.resize(np);
5693 for (int e=0; e<el_to_patch.Size(); ++e)
5695 patch_to_el[el_to_patch[e]].Append(e);
5699void NURBSExtension::SetPatchToBdrElements()
5701 const int nbp = GetNBP();
5702 patch_to_bel.resize(nbp);
5704 for (int e=0; e<bel_to_patch.Size(); ++e)
5706 patch_to_bel[bel_to_patch[e]].Append(e);
5710const Array<int>& NURBSExtension::GetPatchElements(int patch)
5712 MFEM_ASSERT(patch_to_el.size() > 0, "patch_to_el not set
");
5714 return patch_to_el[patch];
5717const Array<int>& NURBSExtension::GetPatchBdrElements(int patch)
5719 MFEM_ASSERT(patch_to_bel.size() > 0, "patch_to_bel not set
");
5721 return patch_to_bel[patch];
5724void NURBSExtension::GetVertexDofs(int vertex, Array<int> &dofs) const
5726 MFEM_ASSERT(vertex < v_spaceOffsets.Size(), "");
5728 const int os = v_spaceOffsets[vertex];
5729 const int os1 = vertex + 1 == v_spaceOffsets.Size() ? e_spaceOffsets[0] :
5730 v_spaceOffsets[vertex + 1];
5733 dofs.Reserve(os1 - os);
5735 for (int i=os; i<os1; ++i) { dofs.Append(i); }
5738void NURBSExtension::GetEdgeDofs(int edge, Array<int> &dofs) const
5740 MFEM_ASSERT(edge < e_spaceOffsets.Size(), "");
5742 const int os = e_spaceOffsets[edge];
5743 const int os_upper = f_spaceOffsets.Size() > 0 ? f_spaceOffsets[0] :
5745 const int os1 = edge + 1 == e_spaceOffsets.Size() ? os_upper :
5746 v_spaceOffsets[edge + 1];
5749 // Reserve 2 for the two vertices and os1 - os for the interior edge DOFs.
5750 dofs.Reserve(2 + os1 - os);
5752 // First get the DOFs for the vertices of the edge.
5755 patchTopo->GetEdgeVertices(edge, vert);
5760 GetVertexDofs(v, vdofs);
5764 // Now get the interior edge DOFs.
5765 for (int i=os; i<os1; ++i) { dofs.Append(i); }
5768void NURBSExtension::ReadCoarsePatchCP(std::istream &input)
5773void NURBSExtension::PrintCoarsePatches(std::ostream &os)
5775 const int patchCP_size1 = patchCP.GetSize1();
5776 MFEM_VERIFY(patchCP_size1 == num_structured_patches || patchCP_size1 == 0,
5779 if (patchCP_size1 == 0) { return; }
5784int NURBSExtension::VertexPairToEdge(const std::pair<int, int> &vertices) const
5790void NURBSExtension::GetMasterEdgeDofs(bool dof, int me, Array<int> &dofs) const
5795void NURBSExtension::GetMasterFaceDofs(bool dof, int mf,
5796 Array2D<int> &dofs) const
5801void NURBSExtension::RefineWithKVFactors(int rf,
5802 const std::string &kvf_filename,
5808NURBSPatch::NURBSPatch(const KnotVector *kv0, const KnotVector *kv1, int dim_,
5809 const real_t* control_points)
5812 kv[0] = new KnotVector(*kv0);
5813 kv[1] = new KnotVector(*kv1);
5815 memcpy(data, control_points, sizeof (real_t) * ni * nj * dim_);
5818NURBSPatch::NURBSPatch(const KnotVector *kv0, const KnotVector *kv1,
5819 const KnotVector *kv2, int dim_,
5820 const real_t* control_points)
5823 kv[0] = new KnotVector(*kv0);
5824 kv[1] = new KnotVector(*kv1);
5825 kv[2] = new KnotVector(*kv2);
5827 memcpy(data, control_points, sizeof (real_t) * ni * nj * nk * dim_);
5830NURBSPatch::NURBSPatch(Array<const KnotVector *> &kv_, int dim_,
5831 const real_t* control_points)
5833 kv.SetSize(kv_.Size());
5835 for (int i = 0; i < kv.Size(); i++)
5837 kv[i] = new KnotVector(*kv_[i]);
5838 n *= kv[i]->GetNCP();
5841 memcpy(data, control_points, sizeof(real_t)*n);
5845ParNURBSExtension::ParNURBSExtension(const ParNURBSExtension &orig)
5846 : NURBSExtension(orig),
5847 partitioning(orig.partitioning),
5849 ldof_group(orig.ldof_group)
5853ParNURBSExtension::ParNURBSExtension(MPI_Comm comm, NURBSExtension *parent,
5854 const int *partitioning_,
5855 const Array<bool> &active_bel)
5858 if (parent->NumOfActiveElems < parent->NumOfElements)
5860 // SetActive (BuildGroups?) and the way the weights are copied
5861 // do not support this case
5863 " all elements in the parent must be active!
");
5866 patchTopo = parent->patchTopo;
5867 // steal ownership of patchTopo from the 'parent' NURBS extension
5868 if (!parent->own_topo)
5871 " parent does not own the patch topology!
");
5874 parent->own_topo = false;
5876 parent->edge_to_ukv.Copy(edge_to_ukv);
5878 parent->GetOrders().Copy(mOrders);
5879 mOrder = parent->GetOrder();
5881 NumOfKnotVectors = parent->GetNKV();
5882 knotVectors.SetSize(NumOfKnotVectors);
5883 for (int i = 0; i < NumOfKnotVectors; i++)
5885 knotVectors[i] = new KnotVector(*parent->GetKnotVector(i));
5887 CreateComprehensiveKV();
5893 // copy 'partitioning_' to 'partitioning'
5894 partitioning.SetSize(GetGNE());
5895 for (int i = 0; i < GetGNE(); i++)
5897 partitioning[i] = partitioning_[i];
5899 SetActive(partitioning, active_bel);
5901 GenerateActiveVertices();
5902 GenerateElementDofTable();
5903 // GenerateActiveBdrElems(); // done by SetActive for now
5904 GenerateBdrElementDofTable();
5906 Table *serial_elem_dof = parent->GetElementDofTable();
5907 BuildGroups(partitioning, *serial_elem_dof);
5909 weights.SetSize(GetNDof());
5910 // copy weights from parent
5911 for (int gel = 0, lel = 0; gel < GetGNE(); gel++)
5913 if (activeElem[gel])
5915 int ndofs = el_dof->RowSize(lel);
5916 int *ldofs = el_dof->GetRow(lel);
5917 int *gdofs = serial_elem_dof->GetRow(gel);
5918 for (int i = 0; i < ndofs; i++)
5920 weights(ldofs[i]) = parent->weights(gdofs[i]);
5927ParNURBSExtension::ParNURBSExtension(NURBSExtension *parent,
5928 const ParNURBSExtension *par_parent)
5929 : gtopo(par_parent->gtopo.GetComm())
5931 // steal all data from parent
5932 mOrder = parent->mOrder;
5933 Swap(mOrders, parent->mOrders);
5935 patchTopo = parent->patchTopo;
5936 own_topo = parent->own_topo;
5937 parent->own_topo = false;
5939 Swap(edge_to_ukv, parent->edge_to_ukv);
5941 NumOfKnotVectors = parent->NumOfKnotVectors;
5942 Swap(knotVectors, parent->knotVectors);
5943 Swap(knotVectorsCompr, parent->knotVectorsCompr);
5945 NumOfVertices = parent->NumOfVertices;
5946 NumOfElements = parent->NumOfElements;
5947 NumOfBdrElements = parent->NumOfBdrElements;
5948 NumOfDofs = parent->NumOfDofs;
5950 Swap(v_meshOffsets, parent->v_meshOffsets);
5951 Swap(e_meshOffsets, parent->e_meshOffsets);
5952 Swap(f_meshOffsets, parent->f_meshOffsets);
5953 Swap(p_meshOffsets, parent->p_meshOffsets);
5955 Swap(v_spaceOffsets, parent->v_spaceOffsets);
5956 Swap(e_spaceOffsets, parent->e_spaceOffsets);
5957 Swap(f_spaceOffsets, parent->f_spaceOffsets);
5958 Swap(p_spaceOffsets, parent->p_spaceOffsets);
5960 Swap(d_to_d, parent->d_to_d);
5961 Swap(master, parent->master);
5962 Swap(slave, parent->slave);
5964 NumOfActiveVertices = parent->NumOfActiveVertices;
5965 NumOfActiveElems = parent->NumOfActiveElems;
5966 NumOfActiveBdrElems = parent->NumOfActiveBdrElems;
5967 NumOfActiveDofs = parent->NumOfActiveDofs;
5969 Swap(activeVert, parent->activeVert);
5970 Swap(activeElem, parent->activeElem);
5971 Swap(activeBdrElem, parent->activeBdrElem);
5972 Swap(activeDof, parent->activeDof);
5974 el_dof = parent->el_dof;
5975 bel_dof = parent->bel_dof;
5976 parent->el_dof = parent->bel_dof = NULL;
5978 Swap(el_to_patch, parent->el_to_patch);
5979 Swap(bel_to_patch, parent->bel_to_patch);
5980 Swap(el_to_IJK, parent->el_to_IJK);
5981 Swap(bel_to_IJK, parent->bel_to_IJK);
5983 Swap(weights, parent->weights);
5984 MFEM_VERIFY(!parent->HavePatches(), "");
5988 MFEM_VERIFY(par_parent->partitioning,
5991 // Support for the case when 'parent' is not a local NURBSExtension, i.e.
5992 // NumOfActiveElems is not the same as in 'par_parent'. In that case, we
5993 // assume 'parent' is a global NURBSExtension, i.e. all elements are active.
5994 bool extract_weights = false;
5995 if (NumOfActiveElems != par_parent->NumOfActiveElems)
5997 MFEM_ASSERT(NumOfActiveElems == NumOfElements, "internal error
");
5999 SetActive(par_parent->partitioning, par_parent->activeBdrElem);
6000 GenerateActiveVertices();
6002 el_to_patch.DeleteAll();
6003 el_to_IJK.DeleteAll();
6004 GenerateElementDofTable();
6005 // GenerateActiveBdrElems(); // done by SetActive for now
6007 bel_to_patch.DeleteAll();
6008 bel_to_IJK.DeleteAll();
6009 GenerateBdrElementDofTable();
6010 extract_weights = true;
6013 Table *glob_elem_dof = GetGlobalElementDofTable();
6014 BuildGroups(par_parent->partitioning, *glob_elem_dof);
6015 if (extract_weights)
6017 Vector glob_weights;
6018 Swap(weights, glob_weights);
6019 weights.SetSize(GetNDof());
6020 // Copy the local 'weights' from the 'glob_weights'.
6021 // Assumption: the local element ids follow the global ordering.
6022 for (int gel = 0, lel = 0; gel < GetGNE(); gel++)
6024 if (activeElem[gel])
6026 int ndofs = el_dof->RowSize(lel);
6027 int *ldofs = el_dof->GetRow(lel);
6028 int *gdofs = glob_elem_dof->GetRow(gel);
6029 for (int i = 0; i < ndofs; i++)
6031 weights(ldofs[i]) = glob_weights(gdofs[i]);
6037 delete glob_elem_dof;
6040Table *ParNURBSExtension::GetGlobalElementDofTable()
6042 if (Dimension() == 1)
6044 return Get1DGlobalElementDofTable();
6046 else if (Dimension() == 2)
6048 return Get2DGlobalElementDofTable();
6052 return Get3DGlobalElementDofTable();
6056Table *ParNURBSExtension::Get1DGlobalElementDofTable()
6059 const KnotVector *kv[1];
6060 NURBSPatchMap p2g(this);
6061 Array<Connection> gel_dof_list;
6063 for (int p = 0; p < GetNP(); p++)
6065 p2g.SetPatchDofMap(p, kv);
6068 const int ord0 = kv[0]->GetOrder();
6070 for (int i = 0; i < kv[0]->GetNKS(); i++)
6072 if (kv[0]->isElement(i))
6074 Connection conn(el,0);
6075 for (int ii = 0; ii <= ord0; ii++)
6077 conn.to = DofMap(p2g(i+ii));
6078 gel_dof_list.Append(conn);
6084 // We must NOT sort gel_dof_list in this case.
6085 return (new Table(GetGNE(), gel_dof_list));
6088Table *ParNURBSExtension::Get2DGlobalElementDofTable()
6091 const KnotVector *kv[2];
6092 NURBSPatchMap p2g(this);
6093 Array<Connection> gel_dof_list;
6095 for (int p = 0; p < GetNP(); p++)
6097 p2g.SetPatchDofMap(p, kv);
6100 const int ord0 = kv[0]->GetOrder();
6101 const int ord1 = kv[1]->GetOrder();
6102 for (int j = 0; j < kv[1]->GetNKS(); j++)
6104 if (kv[1]->isElement(j))
6106 for (int i = 0; i < kv[0]->GetNKS(); i++)
6108 if (kv[0]->isElement(i))
6110 Connection conn(el,0);
6111 for (int jj = 0; jj <= ord1; jj++)
6113 for (int ii = 0; ii <= ord0; ii++)
6115 conn.to = DofMap(p2g(i+ii,j+jj));
6116 gel_dof_list.Append(conn);
6125 // We must NOT sort gel_dof_list in this case.
6126 return (new Table(GetGNE(), gel_dof_list));
6129Table *ParNURBSExtension::Get3DGlobalElementDofTable()
6132 const KnotVector *kv[3];
6133 NURBSPatchMap p2g(this);
6134 Array<Connection> gel_dof_list;
6136 for (int p = 0; p < GetNP(); p++)
6138 p2g.SetPatchDofMap(p, kv);
6141 const int ord0 = kv[0]->GetOrder();
6142 const int ord1 = kv[1]->GetOrder();
6143 const int ord2 = kv[2]->GetOrder();
6144 for (int k = 0; k < kv[2]->GetNKS(); k++)
6146 if (kv[2]->isElement(k))
6148 for (int j = 0; j < kv[1]->GetNKS(); j++)
6150 if (kv[1]->isElement(j))
6152 for (int i = 0; i < kv[0]->GetNKS(); i++)
6154 if (kv[0]->isElement(i))
6156 Connection conn(el,0);
6157 for (int kk = 0; kk <= ord2; kk++)
6159 for (int jj = 0; jj <= ord1; jj++)
6161 for (int ii = 0; ii <= ord0; ii++)
6163 conn.to = DofMap(p2g(i+ii,j+jj,k+kk));
6164 gel_dof_list.Append(conn);
6176 // We must NOT sort gel_dof_list in this case.
6177 return (new Table(GetGNE(), gel_dof_list));
6180void ParNURBSExtension::SetActive(const int *partition,
6181 const Array<bool> &active_bel)
6183 activeElem.SetSize(GetGNE());
6185 NumOfActiveElems = 0;
6186 const int MyRank = gtopo.MyRank();
6187 for (int i = 0; i < GetGNE(); i++)
6188 if (partition[i] == MyRank)
6190 activeElem[i] = true;
6194 active_bel.Copy(activeBdrElem);
6195 NumOfActiveBdrElems = 0;
6196 for (int i = 0; i < GetGNBE(); i++)
6197 if (activeBdrElem[i])
6199 NumOfActiveBdrElems++;
6203void ParNURBSExtension::BuildGroups(const int *partition,
6204 const Table &elem_dof)
6208 ListOfIntegerSets groups;
6211 Transpose(elem_dof, dof_proc); // dof_proc is dof_elem
6213 // convert elements to processors
6214 for (int i = 0; i < dof_proc.Size_of_connections(); i++)
6216 dof_proc.GetJ()[i] = partition[dof_proc.GetJ()[i]];
6219 // the first group is the local one
6220 int MyRank = gtopo.MyRank();
6221 group.Recreate(1, &MyRank);
6222 groups.Insert(group);
6225 ldof_group.SetSize(GetNDof());
6226 for (int d = 0; d < GetNTotalDof(); d++)
6229 group.Recreate(dof_proc.RowSize(d), dof_proc.GetRow(d));
6230 ldof_group[dof] = groups.Insert(group);
6235 gtopo.Create(groups, 1822);
6237#endif // MFEM_USE_MPI
6240void NURBSPatchMap::GetPatchKnotVectors(int p, const KnotVector *kv[])
6242 Ext->patchTopo->GetElementVertices(p, verts);
6244 if (Ext->Dimension() == 1)
6246 kv[0] = Ext->knotVectorsCompr[Ext->Dimension()*p];
6248 else if (Ext->Dimension() == 2)
6250 Ext->patchTopo->GetElementEdges(p, edges, oedge);
6252 kv[0] = Ext->knotVectorsCompr[Ext->Dimension()*p];
6253 kv[1] = Ext->knotVectorsCompr[Ext->Dimension()*p + 1];
6255 else if (Ext->Dimension() == 3)
6257 Ext->patchTopo->GetElementEdges(p, edges, oedge);
6258 Ext->patchTopo->GetElementFaces(p, faces, oface);
6260 kv[0] = Ext->knotVectorsCompr[Ext->Dimension()*p];
6261 kv[1] = Ext->knotVectorsCompr[Ext->Dimension()*p + 1];
6262 kv[2] = Ext->knotVectorsCompr[Ext->Dimension()*p + 2];
6267void NURBSPatchMap::GetBdrPatchKnotVectors(int p, const KnotVector *kv[],
6270 Ext->patchTopo->GetBdrElementVertices(p, verts);
6272 if (Ext->Dimension() == 2)
6274 Ext->patchTopo->GetBdrElementEdges(p, edges, oedge);
6275 kv[0] = Ext->KnotVec(edges[0], oedge[0], &okv[0]);
6278 else if (Ext->Dimension() == 3)
6281 Ext->patchTopo->GetBdrElementEdges(p, edges, oedge);
6282 Ext->patchTopo->GetBdrElementFace(p, &faces[0], &opatch);
6284 kv[0] = Ext->KnotVec(edges[0], oedge[0], &okv[0]);
6285 kv[1] = Ext->KnotVec(edges[1], oedge[1], &okv[1]);
6289void NURBSPatchMap::SetPatchVertexMap(int p, const KnotVector *kv[])
6291 GetPatchKnotVectors(p, kv);
6293 I = kv[0]->GetNE() - 1;
6295 for (int i = 0; i < verts.Size(); i++)
6297 verts[i] = Ext->v_meshOffsets[verts[i]];
6300 if (Ext->Dimension() >= 2)
6302 J = kv[1]->GetNE() - 1;
6303 SetMasterEdges(false, kv);
6304 for (int i = 0; i < edges.Size(); i++)
6306 edges[i] = Ext->e_meshOffsets[edges[i]];
6309 if (Ext->Dimension() == 3)
6311 K = kv[2]->GetNE() - 1;
6312 SetMasterFaces(false);
6313 for (int i = 0; i < faces.Size(); i++)
6315 faces[i] = Ext->f_meshOffsets[faces[i]];
6319 pOffset = Ext->p_meshOffsets[p];
6322void NURBSPatchMap::SetPatchDofMap(int p, const KnotVector *kv[])
6324 GetPatchKnotVectors(p, kv);
6326 I = kv[0]->GetNCP() - 2;
6328 for (int i = 0; i < verts.Size(); i++)
6330 verts[i] = Ext->v_spaceOffsets[verts[i]];
6332 if (Ext->Dimension() >= 2)
6334 J = kv[1]->GetNCP() - 2;
6335 SetMasterEdges(true);
6337 if (Ext->NonconformingPatches() && Ext->patchTopo->ncmesh
6338 && Ext->patchTopo->ncmesh->GetVertexToKnotSpan().Size() > 0)
6340 for (int i = 0; i < edges.Size(); i++)
6342 // Find the patchTopo->ncmesh edge corresponding to edges[i].
6344 Ext->patchTopo->GetEdgeVertices(edges[i], vert);
6345 const std::pair<int, int> vpair(vert[0], vert[1]);
6346 const int ncedge = Ext->VertexPairToEdge(vpair);
6347 edges[i] = Ext->e_spaceOffsets[ncedge];
6352 for (int i = 0; i < edges.Size(); i++)
6354 edges[i] = Ext->e_spaceOffsets[edges[i]];
6358 if (Ext->Dimension() == 3)
6360 K = kv[2]->GetNCP() - 2;
6361 SetMasterFaces(true);
6362 for (int i = 0; i < faces.Size(); i++)
6364 faces[i] = Ext->f_spaceOffsets[faces[i]];
6368 pOffset = Ext->p_spaceOffsets[p];
6371void NURBSPatchMap::SetBdrPatchVertexMap(int p, const KnotVector *kv[],
6374 GetBdrPatchKnotVectors(p, kv, okv);
6376 for (int i = 0; i < verts.Size(); i++)
6378 verts[i] = Ext->v_meshOffsets[verts[i]];
6381 if (Ext->Dimension() == 1)
6385 else if (Ext->Dimension() == 2)
6387 I = kv[0]->GetNE() - 1;
6388 pOffset = Ext->e_meshOffsets[edges[0]];
6389 SetMasterEdges(false);
6391 else if (Ext->Dimension() == 3)
6393 I = kv[0]->GetNE() - 1;
6394 J = kv[1]->GetNE() - 1;
6396 SetMasterEdges(false);
6397 SetMasterFaces(false);
6398 for (int i = 0; i < edges.Size(); i++)
6400 edges[i] = Ext->e_meshOffsets[edges[i]];
6403 pOffset = Ext->f_meshOffsets[faces[0]];
6407void NURBSPatchMap::SetBdrPatchDofMap(int p, const KnotVector *kv[], int *okv)
6409 GetBdrPatchKnotVectors(p, kv, okv);
6411 for (int i = 0; i < verts.Size(); i++)
6413 verts[i] = Ext->v_spaceOffsets[verts[i]];
6416 if (Ext->Dimension() == 1)
6420 else if (Ext->Dimension() == 2)
6422 I = kv[0]->GetNCP() - 2;
6423 pOffset = Ext->e_spaceOffsets[edges[0]];
6425 SetMasterEdges(true);
6427 else if (Ext->Dimension() == 3)
6429 I = kv[0]->GetNCP() - 2;
6430 J = kv[1]->GetNCP() - 2;
6432 SetMasterEdges(true);
6433 for (int i = 0; i < edges.Size(); i++)
6435 edges[i] = Ext->e_spaceOffsets[edges[i]];
6438 pOffset = Ext->f_spaceOffsets[faces[0]];
int Size() const
Return the logical size of the array.
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.
std::shared_ptr< SpacingFunction > spacing
Function to define the distribution of knots for any number of knot spans.
void GetInterpolant(Array< Vector * > &x, const Vector &u, bool reuse_inverse=false) const
Global curve interpolation through the points x (overwritten) at the knot location u....
void PrintFunctions(std::ostream &os, int samples=11) const
Prints the non-zero shape functions and their first and second derivatives associated with the KnotVe...
real_t GetRefPoint(real_t u, int ni) const
Return the reference coordinate in [0,1] for parameter u in the element beginning at knot ni.
void PrintFunction(std::ostream &os, const Vector &a, int samples=11) const
int NumOfElements
Number of elements, defined by distinct knots.
void CalcDnShape(Vector &gradn, int n, int i, real_t xi) const
Calculate n-th derivatives (order n) of the nonvanishing shape function values in grad for the elemen...
int Order
Order of the B-spline basis functions.
KnotVector & operator=(const KnotVector &kv)
bool isElement(int i) const
Return whether the knot index Order plus i is the beginning of an element.
real_t GetBotella(int i) const
real_t GetDemko(int i) const
void CalcShape(Vector &shape, int i, real_t xi) const
Calculate the nonvanishing shape function values in shape for the element corresponding to knot index...
void UniformRefinement(Vector &new_knots, int rf) const
Uniformly refine by factor rf, by inserting knots in each span.
real_t GetKnotLocation(real_t xi, int ni) const
Return the knot location for element reference coordinate xi in [0,1], for the element beginning at k...
Vector knot
Stores the values of all knots.
KnotVector()=default
Collocation matrix inverse.
int GetNKS() const
Return the number of control points minus the order. This is not the number of knot spans,...
KnotVector * FullyCoarsen()
Coarsen to a single element.
void GetElements()
Count the number of elements.
void ComputeDemko() const
Compute all the Demko points.
real_t GetGreville(int i) const
KnotVector * DegreeElevate(int t) const
Return a new KnotVector with elevated degree by repeating the endpoints of the KnotVector.
static const int MaxOrder
void CalcD2Shape(Vector &grad2, int i, real_t xi) const
Calculate second-order shape function derivatives, using CalcDnShape.
int GetNCP() const
Return the number of control points.
int NumOfControlPoints
Number of control points.
void CalcDShape(Vector &grad, int i, real_t xi) const
Calculate derivatives of the nonvanishing shape function values in grad for the element corresponding...
int Size() const
Return the number of knots, including multiplicities.
bool coarse
Flag to indicate whether the KnotVector has been coarsened, which means it is ready for non-nested re...
void Flip()
Reverse the knots.
void Difference(const KnotVector &kv, Vector &diff) const
int GetSpan(real_t u) const
Return the index of the knot span containing parameter u.
int GetCoarseningFactor() const
Vector GetFineKnots(const int cf) const
int GetNE() const
Return the number of elements, defined by distinct knots.
void Refinement(Vector &new_knots, int rf) const
Refine with refinement factor rf.
void Print(std::ostream &os) const
Print the order, number of control points, and knots.
NCNURBSExtension extends NURBSExtension to support NC-patch NURBS meshes.
NURBSExtension generally contains multiple NURBSPatch objects spanning an entire Mesh....
A NURBS patch can be 1D, 2D, or 3D, and is defined as a tensor product of KnotVectors.
Parallel version of NURBSExtension.
void Print(std::ostream &out=mfem::out, int width=8) const
Prints vector to stream out.
void Load(std::istream **in, int np, int *dim)
Reads a vector from multiple files.
int Size() const
Returns the size of the vector.
void SetSize(int s)
Resize the vector to size s.
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)
real_t weight(const Vector &x)
real_t u(const Vector &xvec)
void mfem_error(const char *msg)
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
NURBSPatch * Interpolate(NURBSPatch &p1, NURBSPatch &p2)
NURBSPatch * Revolve3D(NURBSPatch &patch, real_t n[], real_t ang, int times)
real_t p(const Vector &x, real_t t)