23#if defined(_MSC_VER) && (_MSC_VER < 1800)
25#define copysign _copysign
60 MFEM_ASSERT(continuity.
Size() == (intervals.
Size() + 1),
61 "Incompatible sizes of continuity and intervals.");
63 const int num_knots =
Order * continuity.
Size() - continuity.
Sum();
66 MFEM_ASSERT(num_knots >= 0,
"Invalid continuity vector for order.");
71 for (
int i = 0; i < continuity.
Size(); ++i)
73 const int multiplicity =
Order - continuity[i];
74 MFEM_ASSERT(multiplicity >= 1 && multiplicity <=
Order+1,
75 "Invalid knot multiplicity for order.");
76 for (
int j = 0; j < multiplicity; ++j)
81 if (i < intervals.
Size()) { accum += intervals[i]; }
86 "Insufficient number of knots to define NURBS.");
89 for (
int i = 0; i <
GetNKS(); ++i)
116 " Parent KnotVector order higher than child");
119 const int nOrder =
Order + t;
122 for (
int i = 0; i <= nOrder; i++)
124 (*newkv)[i] =
knot(0);
126 for (
int i = nOrder + 1; i < newkv->
GetNCP(); i++)
128 (*newkv)[i] =
knot(i - t);
130 for (
int i = 0; i <= nOrder; i++)
142 MFEM_VERIFY(rf > 1,
"Refinement factor must be at least 2.");
148 for (
int i = 0; i <
knot.
Size()-1; i++)
152 for (
int m = 1; m < rf; ++m)
154 new_knots(j) = ((1.0 - (m * h)) *
knot(i)) + (m * h *
knot(i+1));
183 if (cf < 2) {
return fine; }
186 MFEM_VERIFY(cne > 0 && cne * cf ==
NumOfElements,
"Invalid coarsening factor");
194 for (
int c=0; c<cne; ++c)
200 if (
knot(i) != kprev)
206 if (fcnt == 0) { ifine0 = i; }
207 fine[fcnt] =
knot(i);
214 MFEM_VERIFY(fcnt == fine.
Size(),
"");
220 for (
int j=ifine0+1, ifine=0; j<
knot.
Size(); ++j)
222 if (
knot(j) == fine(ifine))
229 if (ifine == fine.
Size()) {
break; }
235 MFEM_VERIFY(mlt.
Sum() == fine.
Size() * mlt[0],
"");
237 for (i=0; i<fine.
Size(); ++i)
239 for (
int j=0; j<mlt[0]; ++j)
241 mfine[(fine.
Size() * j) + i] = fine[i];
250 MFEM_VERIFY(rf > 1,
"Refinement factor must be at least 2.");
269 for (
int i = 0; i <
knot.
Size() - 1; i++)
278 MFEM_VERIFY(j ==
NumOfElements + 1,
"Incorrect number of knot spans");
296 for (j = 0; j < rf - 1; ++j)
299 new_knots(os1 + j) = ((1.0 - s0) * k0) + (s0 * k1);
330 for (
int i = 1; i <= ns; i++)
348 MFEM_VERIFY(
GetNE(),
"Elements not counted. Use GetElements().");
358 for (
int e = 0; e <
GetNE(); e++, cnt++)
363 for (
int j = 0; j <samples; j++)
369 for (
int d = 0; d <
Order+1; d++) { os<<
"\t"<<shape[d]; }
372 for (
int d = 0; d <
Order+1; d++) { os<<
"\t"<<shape[d]; }
375 for (
int d = 0; d <
Order+1; d++) { os<<
"\t"<<shape[d]; }
388 int ip = (i >= 0) ? (i + p) : (-1 - i + p);
389 real_t u = getKnotLocation((i >= 0) ? xi : 1. - xi, ip), saved, tmp;
390 real_t left[MaxOrder+1], right[MaxOrder+1];
393 for (int j = 1; j <= p; ++j)
395 left[j] = u - knot(ip+1-j);
396 right[j] = knot(ip+j) - u;
398 for (int r = 0; r < j; ++r)
400 tmp = shape(r)/(right[r+1] + left[j-r]);
401 shape(r) = saved + right[r+1]*tmp;
402 saved = left[j-r]*tmp;
408// Routine from "The NURBS Book
" - 2nd ed - Piegl and Tiller
409// Algorithm A2.3 p. 72
410void KnotVector::CalcDShape(Vector &grad, int i, real_t xi) const
412 int p = Order, rk, pk;
413 int ip = (i >= 0) ? (i + p) : (-1 - i + p);
414 real_t u = getKnotLocation((i >= 0) ? xi : 1. - xi, ip), temp, saved, d;
415 real_t ndu[MaxOrder+1][MaxOrder+1], left[MaxOrder+1], right[MaxOrder+1];
425 for (int j = 1; j <= p; j++)
427 left[j] = u - knot(ip-j+1);
428 right[j] = knot(ip+j) - u;
430 for (int r = 0; r < j; r++)
432 ndu[j][r] = right[r+1] + left[j-r];
433 temp = ndu[r][j-1]/ndu[j][r];
434 ndu[r][j] = saved + right[r+1]*temp;
435 saved = left[j-r]*temp;
440 for (int r = 0; r <= p; ++r)
447 d = ndu[rk][pk]/ndu[p][rk];
451 d -= ndu[r][pk]/ndu[p][r];
458 grad *= p*(knot(ip+1) - knot(ip));
462 grad *= p*(knot(ip) - knot(ip+1));
466// Routine from "The NURBS Book
" - 2nd ed - Piegl and Tiller
467// Algorithm A2.3 p. 72
468void KnotVector::CalcDnShape(Vector &gradn, int n, int i, real_t xi) const
470 int p = Order, rk, pk, j1, j2,r,j,k;
471 int ip = (i >= 0) ? (i + p) : (-1 - i + p);
472 real_t u = getKnotLocation((i >= 0) ? xi : 1. - xi, ip);
473 real_t temp, saved, d;
474 real_t a[2][MaxOrder+1],ndu[MaxOrder+1][MaxOrder+1], left[MaxOrder+1],
485 for (j = 1; j <= p; j++)
487 left[j] = u - knot(ip-j+1);
488 right[j] = knot(ip+j)- u;
491 for (r = 0; r < j; r++)
493 ndu[j][r] = right[r+1] + left[j-r];
494 temp = ndu[r][j-1]/ndu[j][r];
495 ndu[r][j] = saved + right[r+1]*temp;
496 saved = left[j-r]*temp;
501 for (r = 0; r <= p; r++)
506 for (k = 1; k <= n; k++)
513 a[s2][0] = a[s1][0]/ndu[pk+1][rk];
514 d = a[s2][0]*ndu[rk][pk];
535 for (j = j1; j <= j2; j++)
537 a[s2][j] = (a[s1][j] - a[s1][j-1])/ndu[pk+1][rk+j];
538 d += a[s2][j]*ndu[rk+j][pk];
543 a[s2][k] = - a[s1][k-1]/ndu[pk+1][r];
544 d += a[s2][j]*ndu[rk+j][pk];
555 u = (knot(ip+1) - knot(ip));
559 u = (knot(ip) - knot(ip+1));
563 for (k = 1; k <= n-1; k++) { temp *= (p-k)*u; }
565 for (j = 0; j <= p; j++) { gradn[j] *= temp; }
569void KnotVector::FindMaxima(Array<int> &ks, Vector &xi, Vector &u) const
571 Vector shape(Order+1);
572 Vector maxima(GetNCP());
573 real_t arg1, arg2, arg, max1, max2, max;
575 xi.SetSize(GetNCP());
577 ks.SetSize(GetNCP());
578 for (int j = 0; j < GetNCP(); j++)
581 for (int d = 0; d < Order+1; d++)
586 arg1 = std::numeric_limits<real_t>::epsilon() / 2_r;
587 CalcShape(shape, i, arg1);
591 CalcShape(shape, i, arg2);
594 arg = (arg1 + arg2)/2;
595 CalcShape(shape, i, arg);
598 while ( ( max > max1 ) || (max > max2) )
611 arg = (arg1 + arg2)/2;
612 CalcShape(shape, i, arg);
621 u[j] = getKnotLocation(arg, i+Order);
628// Routine from "The NURBS Book
" - 2nd ed - Piegl and Tiller
629// Algorithm A9.1 p. 369
630void KnotVector::FindInterpolant(Array<Vector*> &x, bool reuse_inverse)
632 int order = GetOrder();
635 // Find interpolation points
636 Vector xi_args, u_args;
638 FindMaxima(i_args, xi_args, u_args);
640 // Assemble collocation matrix
641#ifdef MFEM_USE_LAPACK
642 // If using LAPACK, we use banded matrix storage (order + 1 nonzeros per row).
643 // Find banded structure of matrix.
644 int KL = 0; // Number of subdiagonals
645 int KU = 0; // Number of superdiagonals
646 for (int i = 0; i < ncp; i++)
648 for (int p = 0; p < order+1; p++)
650 const int col = i_args[i] + p;
653 KL = std::max(KL, i - col);
657 KU = std::max(KU, col - i);
662 const int LDAB = (2*KL) + KU + 1;
665 fact_AB.SetSize(LDAB, N);
667 // Without LAPACK, we store and invert a DenseMatrix (inefficient).
670 A_coll_inv.SetSize(ncp, ncp);
675 Vector shape(order+1);
677 if (!reuse_inverse) // Set collocation matrix entries
679 for (int i = 0; i < ncp; i++)
681 CalcShape(shape, i_args[i], xi_args[i]);
682 for (int p = 0; p < order+1; p++)
684 const int j = i_args[i] + p;
685#ifdef MFEM_USE_LAPACK
686 fact_AB(KL+KU+i-j,j) = shape[p];
688 A_coll_inv(i,j) = shape[p];
695#ifdef MFEM_USE_LAPACK
696 const int NRHS = x.Size();
697 DenseMatrix B(N, NRHS);
698 for (int j=0; j<NRHS; ++j)
700 for (int i=0; i<N; ++i) { B(i, j) = (*x[j])[i]; }
705 BandedFactorizedSolve(KL, KU, fact_AB, B, false, fact_ipiv);
709 BandedSolve(KL, KU, fact_AB, B, fact_ipiv);
712 for (int j=0; j<NRHS; ++j)
714 for (int i=0; i<N; ++i) { (*x[j])[i] = B(i, j); }
717 if (!reuse_inverse) { A_coll_inv.Invert(); }
719 for (int i = 0; i < x.Size(); i++)
722 A_coll_inv.Mult(tmp, *x[i]);
727int KnotVector::findKnotSpan(real_t u) const
731 if (u == knot(NumOfControlPoints+Order))
733 mid = NumOfControlPoints;
738 high = NumOfControlPoints + 1;
739 mid = (low + high)/2;
740 while ( (u < knot(mid-1)) || (u > knot(mid)) )
750 mid = (low + high)/2;
756void KnotVector::Difference(const KnotVector &kv, Vector &diff) const
758 if (Order != kv.GetOrder())
761 " Can not compare
knot vectors with different orders!
");
764 int s = kv.Size() - Size();
767 kv.Difference(*this, diff);
773 if (s == 0) { return; }
777 for (int j = 0; j < kv.Size(); j++)
779 if (abs(knot(i) - kv[j]) < 2 * std::numeric_limits<real_t>::epsilon())
791KnotVector* KnotVector::FullyCoarsen()
793 KnotVector *kvc = new KnotVector(Order, Order + 1);
794 MFEM_VERIFY(kvc->Size() == 2 * (Order + 1), "");
795 for (int i=0; i<Order+1; ++i)
798 (*kvc)[i + Order + 1] = 1.0;
804 kvc->spacing = spacing->Clone();
805 kvc->spacing->FullyCoarsen();
811void NURBSPatch::init(int dim)
813 MFEM_ASSERT(dim > 1, "NURBS patch
dimension (including weight) must be
"
820 ni = kv[0]->GetNCP();
825 data = new real_t[ni*Dim];
828 for (int i = 0; i < ni*Dim; i++)
834 else if (kv.Size() == 2)
836 ni = kv[0]->GetNCP();
837 nj = kv[1]->GetNCP();
838 MFEM_ASSERT(ni > 0 && nj > 0, "Invalid
knot vector dimensions.
");
841 data = new real_t[ni*nj*Dim];
844 for (int i = 0; i < ni*nj*Dim; i++)
850 else if (kv.Size() == 3)
852 ni = kv[0]->GetNCP();
853 nj = kv[1]->GetNCP();
854 nk = kv[2]->GetNCP();
855 MFEM_ASSERT(ni > 0 && nj > 0 && nk > 0,
856 "Invalid
knot vector dimensions.
");
858 data = new real_t[ni*nj*nk*Dim];
861 for (int i = 0; i < ni*nj*nk*Dim; i++)
873NURBSPatch::NURBSPatch(const NURBSPatch &orig)
874 : ni(orig.ni), nj(orig.nj), nk(orig.nk), Dim(orig.Dim),
875 data(NULL), kv(orig.kv.Size()), nd(orig.nd), ls(orig.ls), sd(orig.sd)
877 // Allocate and copy data:
878 const int data_size = Dim*ni*nj*((kv.Size() == 2) ? 1 : nk);
879 data = new real_t[data_size];
880 std::memcpy(data, orig.data, data_size*sizeof(real_t));
882 // Copy the knot vectors:
883 for (int i = 0; i < kv.Size(); i++)
885 kv[i] = new KnotVector(*orig.kv[i]);
889NURBSPatch::NURBSPatch(std::istream &input)
891 int pdim, dim, size = 1;
894 input >> ws >> ident >> pdim; // knotvectors
896 for (int i = 0; i < pdim; i++)
898 kv[i] = new KnotVector(input);
899 size *= kv[i]->GetNCP();
902 input >> ws >> ident >> dim; // dimension
905 input >> ws >> ident; // controlpoints (homogeneous coordinates)
906 if (ident == "controlpoints
" || ident == "controlpoints_homogeneous
")
908 for (int j = 0, i = 0; i < size; i++)
909 for (int d = 0; d <= dim; d++, j++)
914 else // "controlpoints_cartesian
" (Cartesian coordinates with weight)
916 for (int j = 0, i = 0; i < size; i++)
918 for (int d = 0; d <= dim; d++)
922 for (int d = 0; d < dim; d++)
924 data[j+d] *= data[j+dim];
931NURBSPatch::NURBSPatch(const KnotVector *kv0, const KnotVector *kv1, int dim)
934 kv[0] = new KnotVector(*kv0);
935 kv[1] = new KnotVector(*kv1);
939NURBSPatch::NURBSPatch(const KnotVector *kv0, const KnotVector *kv1,
940 const KnotVector *kv2, int dim)
943 kv[0] = new KnotVector(*kv0);
944 kv[1] = new KnotVector(*kv1);
945 kv[2] = new KnotVector(*kv2);
949NURBSPatch::NURBSPatch(Array<const KnotVector *> &kvs, int dim)
951 kv.SetSize(kvs.Size());
952 for (int i = 0; i < kv.Size(); i++)
954 kv[i] = new KnotVector(*kvs[i]);
959NURBSPatch::NURBSPatch(NURBSPatch *parent, int dir, int Order, int NCP)
961 kv.SetSize(parent->kv.Size());
962 for (int i = 0; i < kv.Size(); i++)
965 kv[i] = new KnotVector(*parent->kv[i]);
969 kv[i] = new KnotVector(Order, NCP);
974void NURBSPatch::swap(NURBSPatch *np)
981 for (int i = 0; i < kv.Size(); i++)
983 if (kv[i]) { delete kv[i]; }
1000NURBSPatch::~NURBSPatch()
1007 for (int i = 0; i < kv.Size(); i++)
1009 if (kv[i]) { delete kv[i]; }
1013void NURBSPatch::Print(std::ostream &os) const
1017 os << "knotvectors\n
" << kv.Size() << '\n';
1018 for (int i = 0; i < kv.Size(); i++)
1021 size *= kv[i]->GetNCP();
1024 os << "\ndimension\n
" << Dim - 1
1025 << "\n\ncontrolpoints\n
";
1026 for (int j = 0, i = 0; i < size; i++)
1029 for (int d = 1; d < Dim; d++)
1031 os << ' ' << data[j++];
1037int NURBSPatch::SetLoopDirection(int dir)
1039 if (nj == -1) // 1D case
1050 mfem::err << "NURBSPatch::SetLoopDirection :\n
"
1051 " Direction error in 1D patch, dir =
" << dir << '\n';
1055 else if (nk == -1) // 2D case
1073 mfem::err << "NURBSPatch::SetLoopDirection :\n
"
1074 " Direction error in 2D patch, dir =
" << dir << '\n';
1103 mfem::err << "NURBSPatch::SetLoopDirection :\n
"
1104 " Direction error in 3D patch, dir =
" << dir << '\n';
1112void NURBSPatch::UniformRefinement(Array<int> const& rf, int multiplicity)
1115 for (int dir = 0; dir < kv.Size(); dir++)
1119 kv[dir]->Refinement(new_knots, rf[dir]);
1120 for (int i=0; i<multiplicity; ++i)
1122 KnotInsert(dir, new_knots);
1128void NURBSPatch::UniformRefinement(const std::vector<Array<int>> &rf,
1129 bool coarsened, int multiplicity)
1132 for (int dir = 0; dir < kv.Size(); dir++)
1136 const int f = rf[dir].Sum();
1137 if (f == 1) { continue; }
1138 kv[dir]->Refinement(new_knots, f);
1142 MFEM_VERIFY(rf[dir].IsConstant(), "");
1143 if (rf[dir][0] == 1) { continue; }
1144 kv[dir]->Refinement(new_knots, rf[dir][0]);
1147 for (int i=0; i<multiplicity; ++i)
1149 KnotInsert(dir, new_knots);
1154void NURBSPatch::UniformRefinement(int rf, int multiplicity)
1156 Array<int> rf_array(kv.Size());
1158 UniformRefinement(rf_array, multiplicity);
1161void NURBSPatch::UpdateSpacingPartitions(const Array<KnotVector*> &pkv)
1163 MFEM_VERIFY(pkv.Size() == kv.Size(), "");
1165 for (int dir = 0; dir < kv.Size(); dir++)
1167 if (kv[dir]->spacing && pkv[dir]->spacing)
1169 PiecewiseSpacingFunction *pws = dynamic_cast<PiecewiseSpacingFunction*>
1170 (kv[dir]->spacing.get());
1171 const PiecewiseSpacingFunction *upws =
1172 dynamic_cast<const PiecewiseSpacingFunction*>(pkv[dir]->spacing.get());
1174 MFEM_VERIFY((pws == nullptr) == (upws == nullptr), "");
1178 Array<int> s0 = pws->RelativePieceSizes();
1179 Array<int> s1 = upws->RelativePieceSizes();
1180 MFEM_ASSERT(s0.Size() == s1.Size(), "");
1182 Array<int> rf(s0.Size());
1183 for (int i=0; i<s0.Size(); ++i)
1185 const int f = s1[i] / s0[i];
1186 MFEM_ASSERT(f * s0[i] == s1[i], "Inconsistent spacings
");
1190 pws->ScalePartition(rf, false);
1196void NURBSPatch::Coarsen(Array<int> const& cf, real_t tol)
1198 for (int dir = 0; dir < kv.Size(); dir++)
1200 if (!kv[dir]->coarse)
1202 const int ne_fine = kv[dir]->GetNE();
1203 KnotRemove(dir, kv[dir]->GetFineKnots(cf[dir]), tol);
1204 kv[dir]->coarse = true;
1205 kv[dir]->GetElements();
1207 const int ne_coarse = kv[dir]->GetNE();
1208 MFEM_VERIFY(ne_fine == cf[dir] * ne_coarse, "");
1209 if (kv[dir]->spacing)
1211 kv[dir]->spacing->SetSize(ne_coarse);
1212 kv[dir]->spacing->ScaleParameters((real_t) cf[dir]);
1218void NURBSPatch::Coarsen(int cf, real_t tol)
1220 Array<int> cf_array(kv.Size());
1222 Coarsen(cf_array, tol);
1225void NURBSPatch::GetCoarseningFactors(Array<int> & f) const
1227 f.SetSize(kv.Size());
1228 for (int dir = 0; dir < kv.Size(); dir++)
1230 f[dir] = kv[dir]->GetCoarseningFactor();
1234void NURBSPatch::KnotInsert(Array<KnotVector *> &newkv)
1236 MFEM_ASSERT(newkv.Size() == kv.Size(), "Invalid input to KnotInsert
");
1237 for (int dir = 0; dir < kv.Size(); dir++)
1239 KnotInsert(dir, *newkv[dir]);
1243void NURBSPatch::KnotInsert(int dir, const KnotVector &newkv)
1245 if (dir >= kv.Size() || dir < 0)
1250 int t = newkv.GetOrder() - kv[dir]->GetOrder();
1254 DegreeElevate(dir, t);
1258 mfem_error("NURBSPatch::KnotInsert : Incorrect order!
");
1262 GetKV(dir)->Difference(newkv, diff);
1263 if (diff.Size() > 0)
1265 KnotInsert(dir, diff);
1269void NURBSPatch::KnotInsert(Array<Vector *> &newkv)
1271 MFEM_ASSERT(newkv.Size() == kv.Size(), "Invalid input to KnotInsert
");
1272 for (int dir = 0; dir < kv.Size(); dir++)
1274 KnotInsert(dir, *newkv[dir]);
1278void NURBSPatch::KnotRemove(Array<Vector *> &rmkv, real_t tol)
1280 for (int dir = 0; dir < kv.Size(); dir++)
1282 KnotRemove(dir, *rmkv[dir], tol);
1286void NURBSPatch::KnotRemove(int dir, const Vector &knot, real_t tol)
1288 // TODO: implement an efficient version of this!
1291 KnotRemove(dir, k, 1, tol);
1295// Algorithm A5.5 from "The NURBS Book
", 2nd ed, Piegl and Tiller, chapter 5.
1296void NURBSPatch::KnotInsert(int dir, const Vector &knot)
1298 if (knot.Size() == 0 ) { return; }
1300 if (dir >= kv.Size() || dir < 0)
1305 NURBSPatch &oldp = *this;
1306 KnotVector &oldkv = *kv[dir];
1308 NURBSPatch *newpatch = new NURBSPatch(this, dir, oldkv.GetOrder(),
1309 oldkv.GetNCP() + knot.Size());
1310 NURBSPatch &newp = *newpatch;
1311 KnotVector &newkv = *newp.GetKV(dir);
1313 newkv.spacing = oldkv.spacing;
1315 int size = oldp.SetLoopDirection(dir);
1316 if (size != newp.SetLoopDirection(dir))
1321 int rr = knot.Size() - 1;
1322 int a = oldkv.findKnotSpan(knot(0)) - 1;
1323 int b = oldkv.findKnotSpan(knot(rr)) - 1;
1324 int pl = oldkv.GetOrder();
1325 int ml = oldkv.GetNCP();
1327 for (int j = 0; j <= a; j++)
1329 newkv[j] = oldkv[j];
1331 for (int j = b+pl; j <= ml+pl; j++)
1333 newkv[j+rr+1] = oldkv[j];
1335 for (int k = 0; k <= (a-pl); k++)
1337 for (int ll = 0; ll < size; ll++)
1339 newp.slice(k,ll) = oldp.slice(k,ll);
1342 for (int k = (b-1); k < ml; k++)
1344 for (int ll = 0; ll < size; ll++)
1346 newp.slice(k+rr+1,ll) = oldp.slice(k,ll);
1353 for (int j = rr; j >= 0; j--)
1355 while ( (knot(j) <= oldkv[i]) && (i > a) )
1357 newkv[k] = oldkv[i];
1358 for (int ll = 0; ll < size; ll++)
1360 newp.slice(k-pl-1,ll) = oldp.slice(i-pl-1,ll);
1367 for (int ll = 0; ll < size; ll++)
1369 newp.slice(k-pl-1,ll) = newp.slice(k-pl,ll);
1372 for (int l = 1; l <= pl; l++)
1375 real_t alfa = newkv[k+l] - knot(j);
1376 if (fabs(alfa) == 0.0)
1378 for (int ll = 0; ll < size; ll++)
1380 newp.slice(ind-1,ll) = newp.slice(ind,ll);
1385 alfa = alfa/(newkv[k+l] - oldkv[i-pl+l]);
1386 for (int ll = 0; ll < size; ll++)
1388 newp.slice(ind-1,ll) = alfa*newp.slice(ind-1,ll) +
1389 (1.0-alfa)*newp.slice(ind,ll);
1398 newkv.GetElements();
1403// Algorithm A5.8 from "The NURBS Book
", 2nd ed, Piegl and Tiller, chapter 5.
1404int NURBSPatch::KnotRemove(int dir, real_t knot, int ntimes, real_t tol)
1406 if (dir >= kv.Size() || dir < 0)
1411 NURBSPatch &oldp = *this;
1412 KnotVector &oldkv = *kv[dir];
1414 // Find the index of the last occurrence of the knot.
1416 int multiplicity = 0;
1417 for (int i=0; i<oldkv.Size(); ++i)
1419 if (oldkv[i] == knot)
1426 MFEM_VERIFY(0 < id && id < oldkv.Size() - 1 && ntimes <= multiplicity,
1427 "Only interior knots of sufficient multiplicity may be removed.
");
1429 const int p = oldkv.GetOrder();
1431 NURBSPatch tmpp(this, dir, p, oldkv.GetNCP());
1433 const int size = oldp.SetLoopDirection(dir);
1434 if (size != tmpp.SetLoopDirection(dir))
1440 for (int k = 0; k < oldp.nd; ++k)
1442 for (int ll = 0; ll < size; ll++)
1444 tmpp.slice(k,ll) = oldp.slice(k,ll);
1449 const int s = multiplicity;
1457 Array2D<real_t> temp(last + ntimes + 1, size);
1459 for (int t=0; t<ntimes; ++t)
1461 int off = first - 1; // Difference in index between temp and P.
1463 for (int ll = 0; ll < size; ll++)
1465 temp(0, ll) = oldp.slice(off, ll);
1466 temp(last + 1 - off, ll) = oldp.slice(last + 1, ll);
1470 int jj = last - off;
1474 // Compute new control points for one removal step
1475 const real_t a_i = (knot - oldkv[i]) / (oldkv[i+p+1+t] - oldkv[i]);
1476 const real_t a_j = (knot - oldkv[j-t]) / (oldkv[j+p+1] - oldkv[j-t]);
1478 for (int ll = 0; ll < size; ll++)
1480 temp(ii,ll) = (1.0 / a_i) * oldp.slice(i,ll) -
1481 ((1.0/a_i) - 1.0) * temp(ii - 1, ll);
1483 temp(jj,ll) = (1.0 / (1.0 - a_j)) * (oldp.slice(j,ll) -
1484 (a_j * temp(jj + 1, ll)));
1491 // Check whether knot is removable
1495 for (int ll = 0; ll < size; ll++)
1497 diff[ll] = temp(ii-1, ll) - temp(jj+1, ll);
1502 const real_t a_i = (knot - oldkv[i]) / (oldkv[i+p+1+t] - oldkv[i]);
1503 for (int ll = 0; ll < size; ll++)
1504 diff[ll] = oldp.slice(i,ll) - (a_i * temp(ii+t+1, ll))
1505 - ((1.0 - a_i) * temp(ii-1, ll));
1508 const real_t dist = diff.Norml2();
1511 // Removal failed. Return the number of successful removals.
1512 mfem::out << "Knot removal failed after
" << t
1513 << " successful removals
" << endl;
1517 // Note that the new weights may not be positive.
1519 // Save new control points
1525 for (int ll = 0; ll < size; ll++)
1527 tmpp.slice(i,ll) = temp(i - off,ll);
1528 tmpp.slice(j,ll) = temp(j - off,ll);
1536 } // End of loop (t) over ntimes.
1538 const int fout = ((2*r) - s - p) / 2; // First control point out
1542 for (int k=1; k<ntimes; ++k)
1554 NURBSPatch *newpatch = new NURBSPatch(this, dir, p,
1555 oldkv.GetNCP() - ntimes);
1556 NURBSPatch &newp = *newpatch;
1557 if (size != newp.SetLoopDirection(dir))
1562 for (int k = 0; k < fout; ++k)
1564 for (int ll = 0; ll < size; ll++)
1566 newp.slice(k,ll) = oldp.slice(k,ll); // Copy old data
1570 for (int k = i+1; k < oldp.nd; ++k)
1572 for (int ll = 0; ll < size; ll++)
1574 newp.slice(j,ll) = tmpp.slice(k,ll); // Shift
1580 KnotVector &newkv = *newp.GetKV(dir);
1581 MFEM_VERIFY(newkv.Size() == oldkv.Size() - ntimes, "");
1583 newkv.spacing = oldkv.spacing;
1584 newkv.coarse = oldkv.coarse;
1586 for (int k = 0; k < r - ntimes + 1; k++)
1588 newkv[k] = oldkv[k];
1590 for (int k = r + 1; k < oldkv.Size(); k++)
1592 newkv[k - ntimes] = oldkv[k];
1595 newkv.GetElements();
1602void NURBSPatch::DegreeElevate(int t)
1604 for (int dir = 0; dir < kv.Size(); dir++)
1606 DegreeElevate(dir, t);
1610// Routine from "The NURBS Book
" - 2nd ed - Piegl and Tiller
1611void NURBSPatch::DegreeElevate(int dir, int t)
1613 if (dir >= kv.Size() || dir < 0)
1618 MFEM_ASSERT(t >= 0, "DegreeElevate cannot decrease the degree.
");
1620 int i, j, k, kj, mpi, mul, mh, kind, cind, first, last;
1621 int r, a, b, oldr, save, s, tr, lbz, rbz, l;
1622 real_t inv, ua, ub, numer, alf, den, bet, gam;
1624 NURBSPatch &oldp = *this;
1625 KnotVector &oldkv = *kv[dir];
1626 oldkv.GetElements();
1628 auto *newpatch = new NURBSPatch(this, dir, oldkv.GetOrder() + t,
1629 oldkv.GetNCP() + oldkv.GetNE()*t);
1630 NURBSPatch &newp = *newpatch;
1631 KnotVector &newkv = *newp.GetKV(dir);
1633 if (oldkv.spacing) { newkv.spacing = oldkv.spacing; }
1635 int size = oldp.SetLoopDirection(dir);
1636 if (size != newp.SetLoopDirection(dir))
1641 int p = oldkv.GetOrder();
1642 int n = oldkv.GetNCP()-1;
1644 DenseMatrix bezalfs (p+t+1, p+1);
1645 DenseMatrix bpts (p+1, size);
1646 DenseMatrix ebpts (p+t+1, size);
1647 DenseMatrix nextbpts(p-1, size);
1648 Vector alphas (p-1);
1655 Array2D<int> binom(ph+1, ph+1);
1656 for (i = 0; i <= ph; i++)
1658 binom(i,0) = binom(i,i) = 1;
1659 for (j = 1; j < i; j++)
1661 binom(i,j) = binom(i-1,j) + binom(i-1,j-1);
1666 bezalfs(ph,p) = 1.0;
1668 for (i = 1; i <= ph2; i++)
1670 inv = 1.0/binom(ph,i);
1672 for (j = max(0,i-t); j <= mpi; j++)
1674 bezalfs(i,j) = inv*binom(p,j)*binom(t,i-j);
1679 for (i = ph2+1; i < ph; i++)
1682 for (j = max(0,i-t); j <= mpi; j++)
1684 bezalfs(i,j) = bezalfs(ph-i,p-j);
1695 for (l = 0; l < size; l++)
1697 newp.slice(0,l) = oldp.slice(0,l);
1699 for (i = 0; i <= ph; i++)
1704 for (i = 0; i <= p; i++)
1706 for (l = 0; l < size; l++)
1708 bpts(i,l) = oldp.slice(i,l);
1715 while (b < m && oldkv[b] == oldkv[b+1]) { b++; }
1723 if (oldr > 0) { lbz = (oldr+2)/2; }
1726 if (r > 0) { rbz = ph-(r+1)/2; }
1732 for (k = p ; k > mul; k--)
1734 alphas[k-mul-1] = numer/(oldkv[a+k]-ua);
1737 for (j = 1; j <= r; j++)
1741 for (k = p; k >= s; k--)
1743 for (l = 0; l < size; l++)
1744 bpts(k,l) = (alphas[k-s]*bpts(k,l) +
1745 (1.0-alphas[k-s])*bpts(k-1,l));
1747 for (l = 0; l < size; l++)
1749 nextbpts(save,l) = bpts(p,l);
1754 for (i = lbz; i <= ph; i++)
1756 for (l = 0; l < size; l++)
1761 for (j = max(0,i-t); j <= mpi; j++)
1763 for (l = 0; l < size; l++)
1765 ebpts(i,l) += bezalfs(i,j)*bpts(j,l);
1775 bet = (ub-newkv[kind-1])/den;
1777 for (tr = 1; tr < oldr; tr++)
1786 alf = (ub-newkv[i])/(ua-newkv[i]);
1787 for (l = 0; l < size; l++)
1789 newp.slice(i,l) = alf*newp.slice(i,l)-(1.0-alf)*newp.slice(i-1,l);
1794 if ((j-tr) <= (kind-ph+oldr))
1796 gam = (ub-newkv[j-tr])/den;
1797 for (l = 0; l < size; l++)
1799 ebpts(kj,l) = gam*ebpts(kj,l) + (1.0-gam)*ebpts(kj+1,l);
1804 for (l = 0; l < size; l++)
1806 ebpts(kj,l) = bet*ebpts(kj,l) + (1.0-bet)*ebpts(kj+1,l);
1821 for (i = 0; i < (ph-oldr); i++)
1827 for (j = lbz; j <= rbz; j++)
1829 for (l = 0; l < size; l++)
1831 newp.slice(cind,l) = ebpts(j,l);
1838 for (j = 0; j <r; j++)
1839 for (l = 0; l < size; l++)
1841 bpts(j,l) = nextbpts(j,l);
1844 for (j = r; j <= p; j++)
1845 for (l = 0; l < size; l++)
1847 bpts(j,l) = oldp.slice(b-p+j,l);
1856 for (i = 0; i <= ph; i++)
1862 newkv.GetElements();
1867void NURBSPatch::FlipDirection(int dir)
1869 int size = SetLoopDirection(dir);
1871 for (int id = 0; id < nd/2; id++)
1872 for (int i = 0; i < size; i++)
1874 Swap<real_t>((*this).slice(id,i), (*this).slice(nd-1-id,i));
1879void NURBSPatch::SwapDirections(int dir1, int dir2)
1881 if (abs(dir1-dir2) == 2)
1884 " directions 0 and 2 are not supported!
");
1887 Array<const KnotVector *> nkv(kv);
1889 Swap<const KnotVector *>(nkv[dir1], nkv[dir2]);
1890 NURBSPatch *newpatch = new NURBSPatch(nkv, Dim);
1892 int size = SetLoopDirection(dir1);
1893 newpatch->SetLoopDirection(dir2);
1895 for (int id = 0; id < nd; id++)
1896 for (int i = 0; i < size; i++)
1898 (*newpatch).slice(id,i) = (*this).slice(id,i);
1904void NURBSPatch::Rotate(real_t angle, real_t n[])
1914 mfem_error("NURBSPatch::Rotate : Specify an angle for
a 3D rotation.
");
1921void NURBSPatch::Get2DRotationMatrix(real_t angle, DenseMatrix &T)
1923 real_t s = sin(angle);
1924 real_t c = cos(angle);
1933void NURBSPatch::Rotate2D(real_t angle)
1941 Vector x(2), y(NULL, 2);
1943 Get2DRotationMatrix(angle, T);
1946 for (int i = 0; i < kv.Size(); i++)
1948 size *= kv[i]->GetNCP();
1951 for (int i = 0; i < size; i++)
1953 y.SetData(data + i*Dim);
1959void NURBSPatch::Get3DRotationMatrix(real_t n[], real_t angle, real_t r,
1963 const real_t l2 = n[0]*n[0] + n[1]*n[1] + n[2]*n[2];
1964 const real_t l = sqrt(l2);
1966 MFEM_ASSERT(l2 > 0.0, "3D rotation axis is undefined
");
1968 if (fabs(angle) == (real_t)(M_PI_2))
1970 s = r*copysign(1., angle);
1974 else if (fabs(angle) == (real_t)(M_PI))
1989 T(0,0) = (n[0]*n[0] + (n[1]*n[1] + n[2]*n[2])*c)/l2;
1990 T(0,1) = -(n[0]*n[1]*c1)/l2 - (n[2]*s)/l;
1991 T(0,2) = -(n[0]*n[2]*c1)/l2 + (n[1]*s)/l;
1992 T(1,0) = -(n[0]*n[1]*c1)/l2 + (n[2]*s)/l;
1993 T(1,1) = (n[1]*n[1] + (n[0]*n[0] + n[2]*n[2])*c)/l2;
1994 T(1,2) = -(n[1]*n[2]*c1)/l2 - (n[0]*s)/l;
1995 T(2,0) = -(n[0]*n[2]*c1)/l2 - (n[1]*s)/l;
1996 T(2,1) = -(n[1]*n[2]*c1)/l2 + (n[0]*s)/l;
1997 T(2,2) = (n[2]*n[2] + (n[0]*n[0] + n[1]*n[1])*c)/l2;
2000void NURBSPatch::Rotate3D(real_t n[], real_t angle)
2008 Vector x(3), y(NULL, 3);
2010 Get3DRotationMatrix(n, angle, 1., T);
2013 for (int i = 0; i < kv.Size(); i++)
2015 size *= kv[i]->GetNCP();
2018 for (int i = 0; i < size; i++)
2020 y.SetData(data + i*Dim);
2026int NURBSPatch::MakeUniformDegree(int degree)
2032 for (int dir = 0; dir < kv.Size(); dir++)
2034 maxd = std::max(maxd, kv[dir]->GetOrder());
2038 for (int dir = 0; dir < kv.Size(); dir++)
2040 if (maxd > kv[dir]->GetOrder())
2042 DegreeElevate(dir, maxd - kv[dir]->GetOrder());
2049NURBSPatch *Interpolate(NURBSPatch &p1, NURBSPatch &p2)
2051 if (p1.kv.Size() != p2.kv.Size() || p1.Dim != p2.Dim)
2056 int size = 1, dim = p1.Dim;
2057 Array<const KnotVector *> kv(p1.kv.Size() + 1);
2059 for (int i = 0; i < p1.kv.Size(); i++)
2061 if (p1.kv[i]->GetOrder() < p2.kv[i]->GetOrder())
2063 p1.KnotInsert(i, *p2.kv[i]);
2064 p2.KnotInsert(i, *p1.kv[i]);
2068 p2.KnotInsert(i, *p1.kv[i]);
2069 p1.KnotInsert(i, *p2.kv[i]);
2072 size *= kv[i]->GetNCP();
2075 KnotVector &nkv = *(new KnotVector(1, 2));
2076 nkv[0] = nkv[1] = 0.0;
2077 nkv[2] = nkv[3] = 1.0;
2081 NURBSPatch *patch = new NURBSPatch(kv, dim);
2084 for (int i = 0; i < size; i++)
2086 for (int d = 0; d < dim; d++)
2088 patch->data[i*dim+d] = p1.data[i*dim+d];
2089 patch->data[(i+size)*dim+d] = p2.data[i*dim+d];
2096NURBSPatch *Revolve3D(NURBSPatch &patch, real_t n[], real_t ang, int times)
2104 Array<const KnotVector *> nkv(patch.kv.Size() + 1);
2106 for (int i = 0; i < patch.kv.Size(); i++)
2108 nkv[i] = patch.kv[i];
2109 size *= nkv[i]->GetNCP();
2112 KnotVector &lkv = *(new KnotVector(2, ns));
2114 lkv[0] = lkv[1] = lkv[2] = 0.0;
2115 for (int i = 1; i < times; i++)
2117 lkv[2*i+1] = lkv[2*i+2] = i;
2119 lkv[ns] = lkv[ns+1] = lkv[ns+2] = times;
2121 NURBSPatch *newpatch = new NURBSPatch(nkv, 4);
2124 DenseMatrix T(3), T2(3);
2125 Vector u(NULL, 3), v(NULL, 3);
2127 NURBSPatch::Get3DRotationMatrix(n, ang, 1., T);
2128 real_t c = cos(ang/2);
2129 NURBSPatch::Get3DRotationMatrix(n, ang/2, 1./c, T2);
2132 real_t *op = patch.data, *np;
2133 for (int i = 0; i < size; i++)
2135 np = newpatch->data + 4*i;
2136 for (int j = 0; j < 4; j++)
2140 for (int j = 0; j < times; j++)
2143 v.SetData(np += 4*size);
2146 v.SetData(np += 4*size);
2156void NURBSPatch::SetKnotVectorsCoarse(bool c)
2158 for (int i=0; i<kv.Size(); ++i) { kv[i]->coarse = c; }
2161void NURBSPatch::FullyCoarsen(const Array2D<double> & cp, int ncp1D)
2163 // Remove interior knots
2164 Array<const KnotVector *> kvc(kv.Size());
2165 for (int dir = 0; dir < kv.Size(); dir++)
2167 kvc[dir] = kv[dir]->FullyCoarsen();
2171 NURBSPatch *newpatch = new NURBSPatch(kvc, Dim);
2172 NURBSPatch &newp = *newpatch;
2176 for (int i=0; i<ncp1D; ++i)
2177 for (int j=0; j<ncp1D; ++j)
2178 for (int k=0; k<ncp1D; ++k)
2180 const int dof = i + (ncp1D * (j + (ncp1D * k)));
2181 for (int l = 0; l < Dim - 1; ++l)
2183 newp(i,j,k,l) = cp(dof, l);
2184 newp(i,j,k,Dim-1) = 1.0; // Assuming unit weights
2188 else if (Dim == 3) // 2D
2190 for (int i=0; i<ncp1D; ++i)
2191 for (int j=0; j<ncp1D; ++j)
2193 const int dof = i + (ncp1D * j);
2194 for (int l=0; l<Dim - 1; ++l)
2196 newp(i,j,l) = cp(dof, l);
2197 newp(i,j,Dim-1) = 1.0; // Assuming unit weights
2209NURBSExtension::NURBSExtension(const NURBSExtension &orig)
2210 : mOrder(orig.mOrder), mOrders(orig.mOrders),
2211 NumOfKnotVectors(orig.NumOfKnotVectors),
2212 NumOfVertices(orig.NumOfVertices),
2213 NumOfElements(orig.NumOfElements),
2214 NumOfBdrElements(orig.NumOfBdrElements),
2215 NumOfDofs(orig.NumOfDofs),
2216 NumOfActiveVertices(orig.NumOfActiveVertices),
2217 NumOfActiveElems(orig.NumOfActiveElems),
2218 NumOfActiveBdrElems(orig.NumOfActiveBdrElems),
2219 NumOfActiveDofs(orig.NumOfActiveDofs),
2220 activeVert(orig.activeVert),
2221 activeElem(orig.activeElem),
2222 activeBdrElem(orig.activeBdrElem),
2223 activeDof(orig.activeDof),
2224 patchTopo(new Mesh(*orig.patchTopo)),
2226 edge_to_ukv(orig.edge_to_ukv),
2227 knotVectors(orig.knotVectors.Size()), // knotVectors are copied in the body
2228 knotVectorsCompr(orig.knotVectorsCompr.Size()),
2229 weights(orig.weights),
2230 d_to_d(orig.d_to_d),
2231 master(orig.master),
2233 v_meshOffsets(orig.v_meshOffsets),
2234 e_meshOffsets(orig.e_meshOffsets),
2235 f_meshOffsets(orig.f_meshOffsets),
2236 p_meshOffsets(orig.p_meshOffsets),
2237 v_spaceOffsets(orig.v_spaceOffsets),
2238 e_spaceOffsets(orig.e_spaceOffsets),
2239 f_spaceOffsets(orig.f_spaceOffsets),
2240 p_spaceOffsets(orig.p_spaceOffsets),
2241 el_dof(orig.el_dof ? new Table(*orig.el_dof) : NULL),
2242 bel_dof(orig.bel_dof ? new Table(*orig.bel_dof) : NULL),
2243 el_to_patch(orig.el_to_patch),
2244 bel_to_patch(orig.bel_to_patch),
2245 el_to_IJK(orig.el_to_IJK),
2246 bel_to_IJK(orig.bel_to_IJK),
2247 patches(orig.patches.Size()), // patches are copied in the body
2248 num_structured_patches(orig.num_structured_patches),
2249 patchCP(orig.patchCP),
2251 kvf_coarse(orig.kvf_coarse),
2252 dof2patch(orig.dof2patch)
2254 // Copy the knot vectors:
2255 for (int i = 0; i < knotVectors.Size(); i++)
2257 knotVectors[i] = new KnotVector(*orig.knotVectors[i]);
2259 CreateComprehensiveKV();
2261 // Copy the patches:
2262 for (int p = 0; p < patches.Size(); p++)
2264 patches[p] = new NURBSPatch(*orig.patches[p]);
2268NURBSExtension::NURBSExtension(std::istream &input, bool spacing)
2271 patchTopo = new Mesh;
2272 patchTopo->LoadPatchTopo(input, edge_to_ukv);
2274 Load(input, spacing);
2277void NURBSExtension::Load(std::istream &input, bool spacing)
2282 // CheckBdrPatches();
2284 skip_comment_lines(input, '#');
2286 // Read knotvectors or patches
2288 input >> ws >> ident; // 'knotvectors' or 'patches'
2289 if (ident == "knotvectors
")
2291 input >> NumOfKnotVectors;
2292 knotVectors.SetSize(NumOfKnotVectors);
2293 for (int i = 0; i < NumOfKnotVectors; i++)
2295 knotVectors[i] = new KnotVector(input);
2298 if (spacing) // Read spacing formulas for knotvectors
2300 input >> ws >> ident; // 'spacing' or 'refinements'
2302 if (ident == "refinements
")
2304 ref_factors.SetSize(Dimension());
2305 for (int i=0; i<Dimension(); ++i)
2307 input >> ref_factors[i];
2310 input >> ws >> ident; // 'spacing'
2313 if (ident == "knotvector_refinements
")
2315 kvf.resize(NumOfKnotVectors);
2316 for (int i=0; i<NumOfKnotVectors; ++i)
2321 for (int j=0; j<nf; ++j)
2327 input >> ws >> ident; // 'spacing'
2330 MFEM_VERIFY(ident == "spacing",
2331 "Spacing formula section missing from NURBS mesh file
");
2334 input >> numSpacing;
2335 for (int j = 0; j < numSpacing; j++)
2337 int ki, spacingType, numIntParam, numRealParam;
2338 input >> ki >> spacingType >> numIntParam >> numRealParam;
2340 MFEM_VERIFY(0 <= ki && ki < NumOfKnotVectors,
2341 "Invalid knotvector
index");
2342 MFEM_VERIFY(numIntParam >= 0 && numRealParam >= 0,
2343 "Invalid number of parameters in
KnotVector");
2345 Array<int> ipar(numIntParam);
2346 Vector dpar(numRealParam);
2348 for (int i=0; i<numIntParam; ++i)
2353 for (int i=0; i<numRealParam; ++i)
2358 const SpacingType s = (SpacingType) spacingType;
2359 knotVectors[ki]->spacing = GetSpacingFunction(s, ipar, dpar);
2363 else if (ident == "patches
")
2365 patches.SetSize(GetNP());
2366 for (int p = 0; p < patches.Size(); p++)
2368 skip_comment_lines(input, '#');
2369 patches[p] = new NURBSPatch(input);
2372 NumOfKnotVectors = 0;
2373 for (int i = 0; i < patchTopo->GetNEdges(); i++)
2374 if (NumOfKnotVectors < KnotInd(i))
2376 NumOfKnotVectors = KnotInd(i);
2379 knotVectors.SetSize(NumOfKnotVectors);
2382 Array<int> edges, oedge;
2383 for (int p = 0; p < patches.Size(); p++)
2385 if (Dimension() == 1)
2387 if (knotVectors[KnotInd(p)] == NULL)
2389 knotVectors[KnotInd(p)] =
2390 new KnotVector(*patches[p]->GetKV(0));
2393 else if (Dimension() == 2)
2395 patchTopo->GetElementEdges(p, edges, oedge);
2396 if (knotVectors[KnotInd(edges[0])] == NULL)
2398 knotVectors[KnotInd(edges[0])] =
2399 new KnotVector(*patches[p]->GetKV(0));
2401 if (knotVectors[KnotInd(edges[1])] == NULL)
2403 knotVectors[KnotInd(edges[1])] =
2404 new KnotVector(*patches[p]->GetKV(1));
2407 else if (Dimension() == 3)
2409 patchTopo->GetElementEdges(p, edges, oedge);
2410 if (knotVectors[KnotInd(edges[0])] == NULL)
2412 knotVectors[KnotInd(edges[0])] =
2413 new KnotVector(*patches[p]->GetKV(0));
2415 if (knotVectors[KnotInd(edges[3])] == NULL)
2417 knotVectors[KnotInd(edges[3])] =
2418 new KnotVector(*patches[p]->GetKV(1));
2420 if (knotVectors[KnotInd(edges[8])] == NULL)
2422 knotVectors[KnotInd(edges[8])] =
2423 new KnotVector(*patches[p]->GetKV(2));
2430 MFEM_ABORT("invalid section:
" << ident);
2433 CreateComprehensiveKV();
2435 SetOrdersFromKnotVectors();
2440 // NumOfVertices, NumOfElements, NumOfBdrElements, NumOfDofs
2442 skip_comment_lines(input, '#');
2444 // Check for a list of mesh elements
2445 if (patches.Size() == 0)
2447 input >> ws >> ident;
2449 if (patches.Size() == 0 && ident == "mesh_elements
")
2451 input >> NumOfActiveElems;
2452 activeElem.SetSize(GetGNE());
2455 for (int i = 0; i < NumOfActiveElems; i++)
2458 activeElem[glob_elem] = true;
2461 skip_comment_lines(input, '#');
2462 input >> ws >> ident;
2466 NumOfActiveElems = NumOfElements;
2467 activeElem.SetSize(NumOfElements);
2471 GenerateActiveVertices();
2473 GenerateElementDofTable();
2474 GenerateActiveBdrElems();
2475 GenerateBdrElementDofTable();
2478 if (ident == "periodic
")
2483 skip_comment_lines(input, '#');
2484 input >> ws >> ident;
2487 if (patches.Size() == 0)
2490 if (ident == "weights
")
2492 weights.Load(input, GetNDof());
2494 else // e.g. ident = "unitweights
" or "autoweights
"
2496 weights.SetSize(GetNDof());
2502 ConnectBoundaries();
2505NURBSExtension::NURBSExtension(NURBSExtension *parent, int newOrder)
2507 patchTopo = parent->patchTopo;
2510 parent->edge_to_ukv.Copy(edge_to_ukv);
2512 NumOfKnotVectors = parent->GetNKV();
2513 knotVectors.SetSize(NumOfKnotVectors);
2514 knotVectorsCompr.SetSize(parent->GetNP()*parent->Dimension());
2515 const Array<int> &pOrders = parent->GetOrders();
2516 for (int i = 0; i < NumOfKnotVectors; i++)
2518 if (newOrder > pOrders[i])
2521 parent->GetKnotVector(i)->DegreeElevate(newOrder - pOrders[i]);
2525 knotVectors[i] = new KnotVector(*parent->GetKnotVector(i));
2528 CreateComprehensiveKV();
2530 // copy some data from parent
2531 NumOfElements = parent->NumOfElements;
2532 NumOfBdrElements = parent->NumOfBdrElements;
2534 SetOrdersFromKnotVectors();
2536 GenerateOffsets(); // dof offsets will be different from parent
2538 NumOfActiveVertices = parent->NumOfActiveVertices;
2539 NumOfActiveElems = parent->NumOfActiveElems;
2540 NumOfActiveBdrElems = parent->NumOfActiveBdrElems;
2541 parent->activeVert.Copy(activeVert);
2543 parent->activeElem.Copy(activeElem);
2544 parent->activeBdrElem.Copy(activeBdrElem);
2546 GenerateElementDofTable();
2547 GenerateBdrElementDofTable();
2549 weights.SetSize(GetNDof());
2553 parent->master.Copy(master);
2554 parent->slave.Copy(slave);
2555 ConnectBoundaries();
2558NURBSExtension::NURBSExtension(NURBSExtension *parent,
2559 const Array<int> &newOrders, Mode mode)
2562 newOrders.Copy(mOrders);
2563 SetOrderFromOrders();
2565 patchTopo = parent->patchTopo;
2568 parent->edge_to_ukv.Copy(edge_to_ukv);
2570 NumOfKnotVectors = parent->GetNKV();
2571 MFEM_VERIFY(mOrders.Size() == NumOfKnotVectors, "invalid newOrders array
");
2572 knotVectors.SetSize(NumOfKnotVectors);
2573 const Array<int> &pOrders = parent->GetOrders();
2575 for (int i = 0; i < NumOfKnotVectors; i++)
2577 if (mOrders[i] > pOrders[i])
2580 parent->GetKnotVector(i)->DegreeElevate(mOrders[i] - pOrders[i]);
2584 knotVectors[i] = new KnotVector(*parent->GetKnotVector(i));
2587 CreateComprehensiveKV();
2589 // copy some data from parent
2590 NumOfElements = parent->NumOfElements;
2591 NumOfBdrElements = parent->NumOfBdrElements;
2593 GenerateOffsets(); // dof offsets will be different from parent
2595 NumOfActiveVertices = parent->NumOfActiveVertices;
2596 NumOfActiveElems = parent->NumOfActiveElems;
2597 NumOfActiveBdrElems = parent->NumOfActiveBdrElems;
2598 parent->activeVert.Copy(activeVert);
2600 parent->activeElem.Copy(activeElem);
2601 parent->activeBdrElem.Copy(activeBdrElem);
2603 GenerateElementDofTable();
2604 GenerateBdrElementDofTable();
2606 weights.SetSize(GetNDof());
2609 parent->master.Copy(master);
2610 parent->slave.Copy(slave);
2611 ConnectBoundaries();
2614NURBSExtension::NURBSExtension(Mesh *mesh_array[], int num_pieces)
2616 NURBSExtension *parent = mesh_array[0]->NURBSext;
2618 if (!parent->own_topo)
2621 " parent does not own the patch topology!
");
2623 patchTopo = parent->patchTopo;
2625 parent->own_topo = false;
2627 parent->edge_to_ukv.Copy(edge_to_ukv);
2629 parent->GetOrders().Copy(mOrders);
2630 mOrder = parent->GetOrder();
2632 NumOfKnotVectors = parent->GetNKV();
2633 knotVectors.SetSize(NumOfKnotVectors);
2634 for (int i = 0; i < NumOfKnotVectors; i++)
2636 knotVectors[i] = new KnotVector(*parent->GetKnotVector(i));
2638 CreateComprehensiveKV();
2644 // assuming the meshes define a partitioning of all the elements
2645 NumOfActiveElems = NumOfElements;
2646 activeElem.SetSize(NumOfElements);
2649 GenerateActiveVertices();
2651 GenerateElementDofTable();
2652 GenerateActiveBdrElems();
2653 GenerateBdrElementDofTable();
2655 weights.SetSize(GetNDof());
2656 MergeWeights(mesh_array, num_pieces);
2659NURBSExtension::NURBSExtension(const Mesh *patch_topology,
2660 const Array<const NURBSPatch*> &patches_)
2662 // Basic topology checks
2663 MFEM_VERIFY(patches_.Size() > 0, "Must have at least one patch
");
2664 MFEM_VERIFY(patches_.Size() == patch_topology->GetNE(),
2665 "Number of patches must equal number of elements in patch_topology
");
2667 // Copy patch_topology mesh and NURBSPatch(es)
2668 patchTopo = new Mesh( *patch_topology );
2669 patches.SetSize(patches_.Size());
2670 for (int p = 0; p < patches.Size(); p++)
2672 patches[p] = new NURBSPatch(*patches_[p]);
2675 Array<int> ukv_to_rpkv;
2676 patchTopo->GetEdgeToUniqueKnotvector(edge_to_ukv, ukv_to_rpkv);
2679 CheckPatches(); // This is checking the edge_to_ukv mapping
2681 // Set number of unique (not comprehensive) knot vectors
2682 NumOfKnotVectors = ukv_to_rpkv.Size();
2683 knotVectors.SetSize(NumOfKnotVectors);
2686 // Assign the unique knot vectors from patches
2687 for (int i = 0; i < NumOfKnotVectors; i++)
2689 // pkv = p*dim + d for an arbitrarily chosen patch p,
2690 // in its reference direction d
2691 const int pkv = ukv_to_rpkv[i];
2692 const int p = pkv / Dimension();
2693 const int d = pkv % Dimension();
2694 knotVectors[i] = new KnotVector(*patches[p]->GetKV(d));
2697 CreateComprehensiveKV();
2698 SetOrdersFromKnotVectors();
2704 NumOfActiveElems = NumOfElements;
2705 activeElem.SetSize(NumOfElements);
2708 GenerateActiveVertices();
2710 GenerateElementDofTable();
2711 GenerateActiveBdrElems();
2712 GenerateBdrElementDofTable();
2714 ConnectBoundaries();
2717NURBSExtension::~NURBSExtension()
2719 if (bel_dof) { delete bel_dof; }
2720 if (el_dof) { delete el_dof; }
2722 for (int i = 0; i < knotVectors.Size(); i++)
2724 delete knotVectors[i];
2727 for (int i = 0; i < knotVectorsCompr.Size(); i++)
2729 delete knotVectorsCompr[i];
2732 for (int i = 0; i < patches.Size(); i++)
2743void NURBSExtension::Print(std::ostream &os, const std::string &comments) const
2745 Array<int> kvSpacing;
2746 if (patches.Size() == 0)
2748 for (int i = 0; i < NumOfKnotVectors; i++)
2750 if (knotVectors[i]->spacing) { kvSpacing.Append(i); }
2754 bool writeSpacing = false;
2755 bool writeRefinements = false;
2756 if (patchTopo->ncmesh)
2758 // Writing MFEM NURBS NC-patch mesh v1.0
2759 patchTopo->ncmesh->Print(os, comments, true);
2760 patchTopo->PrintTopoEdges(os, edge_to_ukv, true);
2761 writeSpacing = true;
2762 writeRefinements = true;
2766 const int version = kvSpacing.Size() > 0 ? 11 : 10; // v1.0 or v1.1
2767 if (version == 11) { writeSpacing = true; }
2768 patchTopo->PrintTopo(os, edge_to_ukv, version, comments);
2771 if (patches.Size() == 0)
2773 os << "\nknotvectors\n
" << NumOfKnotVectors << '\n';
2774 for (int i = 0; i < NumOfKnotVectors; i++)
2776 knotVectors[i]->Print(os);
2779 if (writeRefinements && ref_factors.Size() > 0)
2781 os << "\nrefinements\n
";
2782 for (int i=0; i<ref_factors.Size(); ++i)
2784 os << ref_factors[i];
2785 if (i == ref_factors.Size() - 1) { os << '\n'; }
2792 MFEM_VERIFY(kvf.size() == (size_t) NumOfKnotVectors, "");
2793 os << "\nknotvector_refinements\n
";
2794 for (size_t i=0; i<kvf.size(); ++i)
2796 if (kvf_coarse.size() > 0)
2798 os << kvf_coarse[i].Size();
2799 for (int j=0; j<kvf_coarse[i].Size(); ++j)
2801 os << ' ' << kvf_coarse[i][j];
2806 os << kvf[i].Size();
2807 for (int j=0; j<kvf[i].Size(); ++j)
2809 os << ' ' << kvf[i][j];
2818 os << "\nspacing\n
" << kvSpacing.Size() << '\n';
2819 for (auto kv : kvSpacing)
2822 knotVectors[kv]->spacing->Print(os);
2826 if (NumOfActiveElems < NumOfElements)
2828 os << "\nmesh_elements\n
" << NumOfActiveElems << '\n';
2829 for (int i = 0; i < NumOfElements; i++)
2836 os << "\nweights\n
";
2837 weights.Print(os, 1);
2841 os << "\npatches\n
";
2842 for (int p = 0; p < patches.Size(); p++)
2844 os << "\n# patch
" << p << "\n\n
";
2845 patches[p]->Print(os);
2850void NURBSExtension::PrintCharacteristics(std::ostream &os) const
2853 "NURBS
Mesh entity sizes:\n
"
2854 "Dimension =
" << Dimension() << "\n
"
2856 Array<int> unique_orders(mOrders);
2857 unique_orders.Sort();
2858 unique_orders.Unique();
2859 unique_orders.Print(os, unique_orders.Size());
2861 "NumOfKnotVectors =
" << GetNKV() << "\n
"
2862 "NumOfPatches =
" << GetNP() << "\n
"
2863 "NumOfBdrPatches =
" << GetNBP() << "\n
"
2864 "NumOfVertices =
" << GetGNV() << "\n
"
2866 "NumOfBdrElements =
" << GetGNBE() << "\n
"
2867 "NumOfDofs =
" << GetNTotalDof() << "\n
"
2868 "NumOfActiveVertices =
" << GetNV() << "\n
"
2869 "NumOfActiveElems =
" << GetNE() << "\n
"
2870 "NumOfActiveBdrElems =
" << GetNBE() << "\n
"
2871 "NumOfActiveDofs =
" << GetNDof() << '\n';
2872 for (int i = 0; i < NumOfKnotVectors; i++)
2874 os << ' ' << i + 1 << ")
";
2875 knotVectors[i]->Print(os);
2880void NURBSExtension::PrintFunctions(const char *basename, int samples) const
2883 for (int i = 0; i < NumOfKnotVectors; i++)
2885 std::ostringstream filename;
2886 filename << basename << "_
" << i << ".dat
";
2887 os.open(filename.str().c_str());
2888 knotVectors[i]->PrintFunctions(os,samples);
2893void NURBSExtension::InitDofMap()
2900void NURBSExtension::ConnectBoundaries(Array<int> &bnds0, Array<int> &bnds1)
2904 ConnectBoundaries();
2907void NURBSExtension::ConnectBoundaries()
2909 if (master.Size() != slave.Size())
2911 mfem_error("NURBSExtension::ConnectBoundaries() boundary lists not of equal size
");
2913 if (master.Size() == 0 ) { return; }
2915 // Initialize d_to_d
2916 d_to_d.SetSize(NumOfDofs);
2917 for (int i = 0; i < NumOfDofs; i++) { d_to_d[i] = i; }
2920 for (int i = 0; i < master.Size(); i++)
2922 int bnd0 = -1, bnd1 = -1;
2923 for (int b = 0; b < GetNBP(); b++)
2925 if (master[i] == patchTopo->GetBdrAttribute(b)) { bnd0 = b; }
2926 if (slave[i]== patchTopo->GetBdrAttribute(b)) { bnd1 = b; }
2928 MFEM_VERIFY(bnd0 != -1,"Bdr 0 not found
");
2929 MFEM_VERIFY(bnd1 != -1,"Bdr 1 not found
");
2931 if (Dimension() == 1)
2933 ConnectBoundaries1D(bnd0, bnd1);
2935 else if (Dimension() == 2)
2937 ConnectBoundaries2D(bnd0, bnd1);
2941 ConnectBoundaries3D(bnd0, bnd1);
2946 Array<int> tmp(d_to_d.Size()+1);
2949 for (int i = 0; i < d_to_d.Size(); i++)
2955 for (int i = 0; i < tmp.Size(); i++)
2957 if (tmp[i] == 1) { tmp[i] = cnt++; }
2961 for (int i = 0; i < d_to_d.Size(); i++)
2963 d_to_d[i] = tmp[d_to_d[i]];
2967 if (el_dof) { delete el_dof; }
2968 if (bel_dof) { delete bel_dof; }
2969 GenerateElementDofTable();
2970 GenerateBdrElementDofTable();
2973void NURBSExtension::ConnectBoundaries1D(int bnd0, int bnd1)
2975 NURBSPatchMap p2g0(this);
2976 NURBSPatchMap p2g1(this);
2978 int okv0[1],okv1[1];
2979 const KnotVector *kv0[1],*kv1[1];
2981 p2g0.SetBdrPatchDofMap(bnd0, kv0, okv0);
2982 p2g1.SetBdrPatchDofMap(bnd1, kv1, okv1);
2984 d_to_d[p2g0(0)] = d_to_d[p2g1(0)];
2987void NURBSExtension::ConnectBoundaries2D(int bnd0, int bnd1)
2989 NURBSPatchMap p2g0(this);
2990 NURBSPatchMap p2g1(this);
2992 int okv0[1],okv1[1];
2993 const KnotVector *kv0[1],*kv1[1];
2995 p2g0.SetBdrPatchDofMap(bnd0, kv0, okv0);
2996 p2g1.SetBdrPatchDofMap(bnd1, kv1, okv1);
2999 int nks0 = kv0[0]->GetNKS();
3002 bool compatible = true;
3003 if (p2g0.nx() != p2g1.nx()) { compatible = false; }
3004 if (kv0[0]->GetNKS() != kv1[0]->GetNKS()) { compatible = false; }
3005 if (kv0[0]->GetOrder() != kv1[0]->GetOrder()) { compatible = false; }
3009 mfem::out<<p2g0.nx()<<" "<<p2g1.nx()<<endl;
3010 mfem::out<<kv0[0]->GetNKS()<<" "<<kv1[0]->GetNKS()<<endl;
3011 mfem::out<<kv0[0]->GetOrder()<<" "<<kv1[0]->GetOrder()<<endl;
3012 mfem_error("NURBS boundaries not compatible
");
3016 for (int i = 0; i < nks0; i++)
3018 if (kv0[0]->isElement(i))
3020 if (!kv1[0]->isElement(i)) { mfem_error("isElement does not match
"); }
3021 for (int ii = 0; ii <= kv0[0]->GetOrder(); ii++)
3023 int ii0 = (okv0[0] >= 0) ? (i+ii) : (nx-i-ii);
3024 int ii1 = (okv1[0] >= 0) ? (i+ii) : (nx-i-ii);
3026 d_to_d[p2g0(ii0)] = d_to_d[p2g1(ii1)];
3033void NURBSExtension::ConnectBoundaries3D(int bnd0, int bnd1)
3035 NURBSPatchMap p2g0(this);
3036 NURBSPatchMap p2g1(this);
3038 int okv0[2],okv1[2];
3039 const KnotVector *kv0[2],*kv1[2];
3041 p2g0.SetBdrPatchDofMap(bnd0, kv0, okv0);
3042 p2g1.SetBdrPatchDofMap(bnd1, kv1, okv1);
3047 int nks0 = kv0[0]->GetNKS();
3048 int nks1 = kv0[1]->GetNKS();
3051 bool compatible = true;
3052 if (p2g0.nx() != p2g1.nx()) { compatible = false; }
3053 if (p2g0.ny() != p2g1.ny()) { compatible = false; }
3055 if (kv0[0]->GetNKS() != kv1[0]->GetNKS()) { compatible = false; }
3056 if (kv0[1]->GetNKS() != kv1[1]->GetNKS()) { compatible = false; }
3058 if (kv0[0]->GetOrder() != kv1[0]->GetOrder()) { compatible = false; }
3059 if (kv0[1]->GetOrder() != kv1[1]->GetOrder()) { compatible = false; }
3063 mfem::out<<p2g0.nx()<<" "<<p2g1.nx()<<endl;
3064 mfem::out<<p2g0.ny()<<" "<<p2g1.ny()<<endl;
3066 mfem::out<<kv0[0]->GetNKS()<<" "<<kv1[0]->GetNKS()<<endl;
3067 mfem::out<<kv0[1]->GetNKS()<<" "<<kv1[1]->GetNKS()<<endl;
3069 mfem::out<<kv0[0]->GetOrder()<<" "<<kv1[0]->GetOrder()<<endl;
3070 mfem::out<<kv0[1]->GetOrder()<<" "<<kv1[1]->GetOrder()<<endl;
3071 mfem_error("NURBS boundaries not compatible
");
3075 for (int j = 0; j < nks1; j++)
3077 if (kv0[1]->isElement(j))
3079 if (!kv1[1]->isElement(j)) { mfem_error("isElement does not match #1
"); }
3080 for (int i = 0; i < nks0; i++)
3082 if (kv0[0]->isElement(i))
3084 if (!kv1[0]->isElement(i)) { mfem_error("isElement does not match #0
"); }
3085 for (int jj = 0; jj <= kv0[1]->GetOrder(); jj++)
3087 int jj0 = (okv0[1] >= 0) ? (j+jj) : (ny-j-jj);
3088 int jj1 = (okv1[1] >= 0) ? (j+jj) : (ny-j-jj);
3090 for (int ii = 0; ii <= kv0[0]->GetOrder(); ii++)
3092 int ii0 = (okv0[0] >= 0) ? (i+ii) : (nx-i-ii);
3093 int ii1 = (okv1[0] >= 0) ? (i+ii) : (nx-i-ii);
3095 d_to_d[p2g0(ii0,jj0)] = d_to_d[p2g1(ii1,jj1)];
3104void NURBSExtension::GenerateActiveVertices()
3106 int vert[8], nv, g_el, nx, ny, nz, dim = Dimension();
3108 NURBSPatchMap p2g(this);
3109 const KnotVector *kv[3];
3112 activeVert.SetSize(GetGNV());
3114 for (int p = 0; p < GetNP(); p++)
3116 p2g.SetPatchVertexMap(p, kv);
3119 ny = (dim >= 2) ? p2g.ny() : 1;
3120 nz = (dim == 3) ? p2g.nz() : 1;
3122 for (int k = 0; k < nz; k++)
3124 for (int j = 0; j < ny; j++)
3126 for (int i = 0; i < nx; i++)
3128 if (activeElem[g_el])
3138 vert[0] = p2g(i, j );
3139 vert[1] = p2g(i+1,j );
3140 vert[2] = p2g(i+1,j+1);
3141 vert[3] = p2g(i, j+1);
3146 vert[0] = p2g(i, j, k);
3147 vert[1] = p2g(i+1,j, k);
3148 vert[2] = p2g(i+1,j+1,k);
3149 vert[3] = p2g(i, j+1,k);
3151 vert[4] = p2g(i, j, k+1);
3152 vert[5] = p2g(i+1,j, k+1);
3153 vert[6] = p2g(i+1,j+1,k+1);
3154 vert[7] = p2g(i, j+1,k+1);
3158 for (int v = 0; v < nv; v++)
3160 activeVert[vert[v]] = 1;
3169 NumOfActiveVertices = 0;
3170 for (int i = 0; i < GetGNV(); i++)
3171 if (activeVert[i] == 1)
3173 activeVert[i] = NumOfActiveVertices++;
3177void NURBSExtension::GenerateActiveBdrElems()
3179 int dim = Dimension();
3180 Array<KnotVector *> kv(dim);
3182 activeBdrElem.SetSize(GetGNBE());
3183 if (GetGNE() == GetNE())
3185 activeBdrElem = true;
3186 NumOfActiveBdrElems = GetGNBE();
3189 activeBdrElem = false;
3190 NumOfActiveBdrElems = 0;
3191 // the mesh will generate the actual boundary including boundary
3192 // elements that are not on boundary patches. we use this for
3193 // visualization of processor boundaries
3195 // TODO: generate actual boundary?
3199void NURBSExtension::MergeWeights(Mesh *mesh_array[], int num_pieces)
3201 Array<int> lelem_elem;
3203 for (int i = 0; i < num_pieces; i++)
3205 NURBSExtension *lext = mesh_array[i]->NURBSext;
3207 lext->GetElementLocalToGlobal(lelem_elem);
3209 for (int lel = 0; lel < lext->GetNE(); lel++)
3211 int gel = lelem_elem[lel];
3213 int nd = el_dof->RowSize(gel);
3214 int *gdofs = el_dof->GetRow(gel);
3215 int *ldofs = lext->el_dof->GetRow(lel);
3216 for (int j = 0; j < nd; j++)
3218 weights(gdofs[j]) = lext->weights(ldofs[j]);
3224void NURBSExtension::MergeGridFunctions(
3225 GridFunction *gf_array[], int num_pieces, GridFunction &merged)
3227 FiniteElementSpace *gfes = merged.FESpace();
3228 Array<int> lelem_elem, dofs;
3231 for (int i = 0; i < num_pieces; i++)
3233 FiniteElementSpace *lfes = gf_array[i]->FESpace();
3234 NURBSExtension *lext = lfes->GetMesh()->NURBSext;
3236 lext->GetElementLocalToGlobal(lelem_elem);
3238 for (int lel = 0; lel < lext->GetNE(); lel++)
3240 lfes->GetElementVDofs(lel, dofs);
3241 gf_array[i]->GetSubVector(dofs, lvec);
3243 gfes->GetElementVDofs(lelem_elem[lel], dofs);
3244 merged.SetSubVector(dofs, lvec);
3249void NURBSExtension::CheckPatches()
3251 if (Dimension() == 1 ) { return; }
3253 Array<int> edges, oedge;
3255 for (int p = 0; p < GetNP(); p++)
3257 patchTopo->GetElementEdges(p, edges, oedge);
3259 for (int i = 0; i < edges.Size(); i++)
3261 edges[i] = edge_to_ukv[edges[i]];
3264 edges[i] = -1 - edges[i];
3268 if ((Dimension() == 2 &&
3269 (edges[0] != -1 - edges[2] || edges[1] != -1 - edges[3])) ||
3271 (Dimension() == 3 &&
3272 (edges[0] != edges[2] || edges[0] != edges[4] ||
3273 edges[0] != edges[6] || edges[1] != edges[3] ||
3274 edges[1] != edges[5] || edges[1] != edges[7] ||
3275 edges[8] != edges[9] || edges[8] != edges[10] ||
3276 edges[8] != edges[11])))
3279 << ")\n Inconsistent edge-to-knotvector mapping!
";
3285void NURBSExtension::CheckBdrPatches()
3290 for (int p = 0; p < GetNBP(); p++)
3292 patchTopo->GetBdrElementEdges(p, edges, oedge);
3294 for (int i = 0; i < edges.Size(); i++)
3296 edges[i] = edge_to_ukv[edges[i]];
3299 edges[i] = -1 - edges[i];
3303 if ((Dimension() == 2 && (edges[0] < 0)) ||
3304 (Dimension() == 3 && (edges[0] < 0 || edges[1] < 0)))
3307 << p << ") : Bad orientation!\n
";
3313void NURBSExtension::CheckKVDirection(int p, Array <int> &kvdir)
3315 // patchTopo->GetElementEdges is not yet implemented for 1D
3316 MFEM_VERIFY(Dimension()>1, "1D not yet implemented.
");
3318 kvdir.SetSize(Dimension());
3321 Array<int> patchvert, edges, orient, edgevert;
3323 patchTopo->GetElementVertices(p, patchvert);
3325 patchTopo->GetElementEdges(p, edges, orient);
3327 // Compare the vertices of the patches with the vertices of the knotvectors of knot2dge
3328 // Based on the match the orientation will be a 1 or a -1
3329 // -1: direction is flipped
3330 // 1: direction is not flipped
3332 for (int i = 0; i < edges.Size(); i++)
3335 patchTopo->GetEdgeVertices(edges[i], edgevert);
3336 const int ks = KnotSign(edges[i]);
3337 if (edgevert[0] == patchvert[0] && edgevert[1] == patchvert[1])
3342 if (edgevert[0] == patchvert[1] && edgevert[1] == patchvert[0])
3348 if (edgevert[0] == patchvert[0] && edgevert[1] == patchvert[3])
3353 if (edgevert[0] == patchvert[3] && edgevert[1] == patchvert[0])
3359 if (Dimension() == 3)
3362 for (int i = 0; i < edges.Size(); i++)
3364 patchTopo->GetEdgeVertices(edges[i], edgevert);
3365 const int ks = KnotSign(edges[i]);
3367 if (edgevert[0] == patchvert[0] && edgevert[1] == patchvert[4])
3372 if (edgevert[0] == patchvert[4] && edgevert[1] == patchvert[0])
3379 MFEM_VERIFY(kvdir.Find(0) == -1, "Could not find
direction of knotvector.
");
3382void NURBSExtension::CreateComprehensiveKV()
3384 Array<int> edges, orient, kvdir;
3385 Array<int> e(Dimension());
3387 // 1D: comprehensive and unique KV are the same
3388 if (Dimension() == 1)
3390 knotVectorsCompr.SetSize(GetNKV());
3391 for (int i = 0; i < GetNKV(); i++)
3393 knotVectorsCompr[i] = new KnotVector(*(KnotVec(i)));
3397 else if (Dimension() == 2)
3399 knotVectorsCompr.SetSize(GetNP()*Dimension());
3403 else if (Dimension() == 3)
3405 knotVectorsCompr.SetSize(GetNP()*Dimension());
3411 for (int p = 0; p < GetNP(); p++)
3413 CheckKVDirection(p, kvdir);
3415 patchTopo->GetElementEdges(p, edges, orient);
3417 for (int d = 0; d < Dimension(); d++)
3419 // Indices in unique and comprehensive sets of the KnotVector
3420 int iun = edges[e[d]];
3421 int icomp = Dimension()*p+d;
3422 knotVectorsCompr[icomp] = new KnotVector(*(KnotVec(iun)));
3423 if (kvdir[d] == -1) { knotVectorsCompr[icomp]->Flip(); }
3427 MFEM_VERIFY(ConsistentKVSets(), "Mismatch in KnotVectors
");
3430void NURBSExtension::UpdateUniqueKV()
3432 Array<int> e(Dimension());
3434 // 1D: comprehensive and unique KV are the same
3435 if (Dimension() == 1)
3437 for (int i = 0; i < GetNKV(); i++)
3439 *(KnotVec(i)) = *(knotVectorsCompr[i]);
3443 else if (Dimension() == 2)
3448 else if (Dimension() == 3)
3455 for (int p = 0; p < GetNP(); p++)
3457 Array<int> edges, orient, kvdir;
3459 patchTopo->GetElementEdges(p, edges, orient);
3460 CheckKVDirection(p, kvdir);
3462 for (int d = 0; d < Dimension(); d++)
3465 if (kvdir[d] == -1) { flip = true; }
3467 // Indices in unique and comprehensive sets of the KnotVector
3468 int iun = edges[e[d]];
3469 int icomp = Dimension()*p+d;
3471 // Check if difference in order
3472 int o1 = KnotVec(iun)->GetOrder();
3473 int o2 = knotVectorsCompr[icomp]->GetOrder();
3474 int diffo = abs(o1 - o2);
3476 int ne1 = KnotVec(iun)->GetNE();
3477 int ne2 = knotVectorsCompr[icomp]->GetNE();
3479 if (diffo || ne1 != ne2)
3481 // Update reduced set of knotvectors
3482 *(KnotVec(iun)) = *(knotVectorsCompr[icomp]);
3484 // Give correct direction to unique knotvector.
3485 if (flip) { KnotVec(iun)->Flip(); }
3488 // Check if difference between knots
3491 if (flip) { knotVectorsCompr[icomp]->Flip(); }
3493 KnotVec(iun)->Difference(*(knotVectorsCompr[icomp]), diffknot);
3495 if (flip) { knotVectorsCompr[icomp]->Flip(); }
3497 if (diffknot.Size() > 0)
3499 // Update reduced set of knotvectors
3500 *(KnotVec(iun)) = *(knotVectorsCompr[icomp]);
3502 // Give correct direction to unique knotvector.
3503 if (flip) {KnotVec(iun)->Flip();}
3508 MFEM_VERIFY(ConsistentKVSets(), "Mismatch in KnotVectors
");
3511bool NURBSExtension::ConsistentKVSets()
3513 // patchTopo->GetElementEdges is not yet implemented for 1D
3514 MFEM_VERIFY(Dimension() > 1, "1D not yet implemented.
");
3516 Array<int> edges, orient, kvdir;
3519 Array<int> e(Dimension());
3523 if (Dimension() == 2)
3527 else if (Dimension() == 3)
3533 for (int p = 0; p < GetNP(); p++)
3535 patchTopo->GetElementEdges(p, edges, orient);
3537 CheckKVDirection(p, kvdir);
3539 for (int d = 0; d < Dimension(); d++)
3542 if (kvdir[d] == -1) {flip = true;}
3544 // Indices in unique and comprehensive sets of the KnotVector
3545 int iun = edges[e[d]];
3546 int icomp = Dimension()*p+d;
3548 // Check if KnotVectors are of equal order
3549 int o1 = KnotVec(iun)->GetOrder();
3550 int o2 = knotVectorsCompr[icomp]->GetOrder();
3551 int diffo = abs(o1 - o2);
3555 mfem::out << "\norder of knotVectorsCompr
" << d << " of patch
" << p;
3556 mfem::out << " does not agree with knotVectors
" << KnotInd(iun) << "\n
";
3560 // Check if Knotvectors have the same knots
3561 if (flip) {knotVectorsCompr[icomp]->Flip();}
3563 KnotVec(iun)->Difference(*(knotVectorsCompr[icomp]), diff);
3565 if (flip) {knotVectorsCompr[icomp]->Flip();}
3567 if (diff.Size() > 0)
3569 mfem::out << "\nknotVectorsCompr
" << d << " of patch
" << p;
3570 mfem::out << " does not agree with knotVectors
" << KnotInd(iun) << "\n
";
3578void NURBSExtension::GetPatchKnotVectors(int p, Array<KnotVector *> &kv)
3580 Array<int> edges, orient;
3582 kv.SetSize(Dimension());
3584 if (Dimension() == 1)
3586 kv[0] = knotVectorsCompr[Dimension()*p];
3588 else if (Dimension() == 2)
3590 kv[0] = knotVectorsCompr[Dimension()*p];
3591 kv[1] = knotVectorsCompr[Dimension()*p + 1];
3595 kv[0] = knotVectorsCompr[Dimension()*p];
3596 kv[1] = knotVectorsCompr[Dimension()*p + 1];
3597 kv[2] = knotVectorsCompr[Dimension()*p + 2];
3601void NURBSExtension::GetPatchKnotVectors(int p, Array<const KnotVector *> &kv)
3604 kv.SetSize(Dimension());
3606 if (Dimension() == 1)
3608 kv[0] = knotVectorsCompr[Dimension()*p];
3610 else if (Dimension() == 2)
3612 kv[0] = knotVectorsCompr[Dimension()*p];
3613 kv[1] = knotVectorsCompr[Dimension()*p + 1];
3617 kv[0] = knotVectorsCompr[Dimension()*p];
3618 kv[1] = knotVectorsCompr[Dimension()*p + 1];
3619 kv[2] = knotVectorsCompr[Dimension()*p + 2];
3623void NURBSExtension::GetBdrPatchKnotVectors(int bp, Array<KnotVector *> &kv)
3628 kv.SetSize(Dimension() - 1);
3630 if (Dimension() == 2)
3632 patchTopo->GetBdrElementEdges(bp, edges, orient);
3633 kv[0] = KnotVec(edges[0]);
3635 else if (Dimension() == 3)
3637 patchTopo->GetBdrElementEdges(bp, edges, orient);
3638 kv[0] = KnotVec(edges[0]);
3639 kv[1] = KnotVec(edges[1]);
3643void NURBSExtension::GetBdrPatchKnotVectors(
3644 int bp, Array<const KnotVector *> &kv) const
3649 kv.SetSize(Dimension() - 1);
3651 if (Dimension() == 2)
3653 patchTopo->GetBdrElementEdges(bp, edges, orient);
3654 kv[0] = KnotVec(edges[0]);
3656 else if (Dimension() == 3)
3658 patchTopo->GetBdrElementEdges(bp, edges, orient);
3659 kv[0] = KnotVec(edges[0]);
3660 kv[1] = KnotVec(edges[1]);
3664void NURBSExtension::SetOrderFromOrders()
3666 MFEM_VERIFY(mOrders.Size() > 0, "");
3667 mOrder = mOrders[0];
3668 for (int i = 1; i < mOrders.Size(); i++)
3670 if (mOrders[i] != mOrder)
3672 mOrder = NURBSFECollection::VariableOrder;
3678void NURBSExtension::SetOrdersFromKnotVectors()
3680 mOrders.SetSize(NumOfKnotVectors);
3681 for (int i = 0; i < NumOfKnotVectors; i++)
3683 mOrders[i] = knotVectors[i]->GetOrder();
3685 SetOrderFromOrders();
3688void NURBSExtension::GenerateOffsets()
3690 const int nv = patchTopo->GetNV();
3691 const int ne = patchTopo->GetNEdges();
3692 const int nf = patchTopo->GetNFaces();
3693 const int np = patchTopo->GetNE();
3694 int meshCounter, spaceCounter;
3696 Array<int> edges, orient;
3698 v_meshOffsets.SetSize(nv);
3699 e_meshOffsets.SetSize(ne);
3700 f_meshOffsets.SetSize(nf);
3701 p_meshOffsets.SetSize(np);
3703 v_spaceOffsets.SetSize(nv);
3704 e_spaceOffsets.SetSize(ne);
3705 f_spaceOffsets.SetSize(nf);
3706 p_spaceOffsets.SetSize(np);
3708 // Get vertex offsets
3709 for (meshCounter = 0; meshCounter < nv; meshCounter++)
3711 v_meshOffsets[meshCounter] = meshCounter;
3712 v_spaceOffsets[meshCounter] = meshCounter;
3714 spaceCounter = meshCounter;
3717 for (int e = 0; e < ne; e++)
3719 e_meshOffsets[e] = meshCounter;
3720 e_spaceOffsets[e] = spaceCounter;
3721 meshCounter += KnotVec(e)->GetNE() - 1;
3722 spaceCounter += KnotVec(e)->GetNCP() - 2;
3726 for (int f = 0; f < nf; f++)
3728 f_meshOffsets[f] = meshCounter;
3729 f_spaceOffsets[f] = spaceCounter;
3731 patchTopo->GetFaceEdges(f, edges, orient);
3734 (KnotVec(edges[0])->GetNE() - 1) *
3735 (KnotVec(edges[1])->GetNE() - 1);
3737 (KnotVec(edges[0])->GetNCP() - 2) *
3738 (KnotVec(edges[1])->GetNCP() - 2);
3741 // Get patch offsets
3742 GetPatchOffsets(meshCounter, spaceCounter);
3744 NumOfVertices = meshCounter;
3745 NumOfDofs = spaceCounter;
3748void NURBSExtension::GetPatchOffsets(int &meshCounter, int &spaceCounter)
3750 const int np = patchTopo->GetNE();
3751 const int dim = Dimension();
3752 Array<int> edges, orient;
3753 for (int p = 0; p < np; p++)
3755 p_meshOffsets[p] = meshCounter;
3756 p_spaceOffsets[p] = spaceCounter;
3760 meshCounter += KnotVec(0)->GetNE() - 1;
3761 spaceCounter += KnotVec(0)->GetNCP() - 2;
3765 patchTopo->GetElementEdges(p, edges, orient);
3767 (KnotVec(edges[0])->GetNE() - 1) *
3768 (KnotVec(edges[1])->GetNE() - 1);
3770 (KnotVec(edges[0])->GetNCP() - 2) *
3771 (KnotVec(edges[1])->GetNCP() - 2);
3775 patchTopo->GetElementEdges(p, edges, orient);
3777 (KnotVec(edges[0])->GetNE() - 1) *
3778 (KnotVec(edges[3])->GetNE() - 1) *
3779 (KnotVec(edges[8])->GetNE() - 1);
3781 (KnotVec(edges[0])->GetNCP() - 2) *
3782 (KnotVec(edges[3])->GetNCP() - 2) *
3783 (KnotVec(edges[8])->GetNCP() - 2);
3788void NURBSExtension::CountElements()
3790 int dim = Dimension();
3791 Array<const KnotVector *> kv(dim);
3794 for (int p = 0; p < GetNP(); p++)
3796 GetPatchKnotVectors(p, kv);
3798 int ne = kv[0]->GetNE();
3799 for (int d = 1; d < dim; d++)
3801 ne *= kv[d]->GetNE();
3804 NumOfElements += ne;
3808void NURBSExtension::CountBdrElements()
3810 int dim = Dimension() - 1;
3811 Array<KnotVector *> kv(dim);
3813 NumOfBdrElements = 0;
3814 for (int p = 0; p < GetNBP(); p++)
3816 GetBdrPatchKnotVectors(p, kv);
3819 for (int d = 0; d < dim; d++)
3821 ne *= kv[d]->GetNE();
3824 NumOfBdrElements += ne;
3828void NURBSExtension::GetElementTopo(Array<Element *> &elements) const
3830 elements.SetSize(GetNE());
3832 if (Dimension() == 1)
3834 Get1DElementTopo(elements);
3836 else if (Dimension() == 2)
3838 Get2DElementTopo(elements);
3842 Get3DElementTopo(elements);
3846void NURBSExtension::Get1DElementTopo(Array<Element *> &elements) const
3851 NURBSPatchMap p2g(this);
3852 const KnotVector *kv[1];
3854 for (int p = 0; p < GetNP(); p++)
3856 p2g.SetPatchVertexMap(p, kv);
3859 int patch_attr = patchTopo->GetAttribute(p);
3861 for (int i = 0; i < nx; i++)
3865 ind[0] = activeVert[p2g(i)];
3866 ind[1] = activeVert[p2g(i+1)];
3868 elements[el] = new Segment(ind, patch_attr);
3876void NURBSExtension::Get2DElementTopo(Array<Element *> &elements) const
3881 NURBSPatchMap p2g(this);
3882 const KnotVector *kv[2];
3884 for (int p = 0; p < GetNP(); p++)
3886 p2g.SetPatchVertexMap(p, kv);
3890 int patch_attr = patchTopo->GetAttribute(p);
3892 for (int j = 0; j < ny; j++)
3894 for (int i = 0; i < nx; i++)
3898 ind[0] = activeVert[p2g(i, j )];
3899 ind[1] = activeVert[p2g(i+1,j )];
3900 ind[2] = activeVert[p2g(i+1,j+1)];
3901 ind[3] = activeVert[p2g(i, j+1)];
3903 elements[el] = new Quadrilateral(ind, patch_attr);
3912void NURBSExtension::Get3DElementTopo(Array<Element *> &elements) const
3917 NURBSPatchMap p2g(this);
3918 const KnotVector *kv[3];
3920 for (int p = 0; p < GetNP(); p++)
3922 p2g.SetPatchVertexMap(p, kv);
3927 int patch_attr = patchTopo->GetAttribute(p);
3929 for (int k = 0; k < nz; k++)
3931 for (int j = 0; j < ny; j++)
3933 for (int i = 0; i < nx; i++)
3937 ind[0] = activeVert[p2g(i, j, k)];
3938 ind[1] = activeVert[p2g(i+1,j, k)];
3939 ind[2] = activeVert[p2g(i+1,j+1,k)];
3940 ind[3] = activeVert[p2g(i, j+1,k)];
3942 ind[4] = activeVert[p2g(i, j, k+1)];
3943 ind[5] = activeVert[p2g(i+1,j, k+1)];
3944 ind[6] = activeVert[p2g(i+1,j+1,k+1)];
3945 ind[7] = activeVert[p2g(i, j+1,k+1)];
3947 elements[el] = new Hexahedron(ind, patch_attr);
3957void NURBSExtension::GetBdrElementTopo(Array<Element *> &boundary) const
3959 boundary.SetSize(GetNBE());
3961 if (Dimension() == 1)
3963 Get1DBdrElementTopo(boundary);
3965 else if (Dimension() == 2)
3967 Get2DBdrElementTopo(boundary);
3971 Get3DBdrElementTopo(boundary);
3975void NURBSExtension::Get1DBdrElementTopo(Array<Element *> &boundary) const
3979 NURBSPatchMap p2g(this);
3980 const KnotVector *kv[1];
3983 for (int b = 0; b < GetNBP(); b++)
3985 p2g.SetBdrPatchVertexMap(b, kv, okv);
3986 int bdr_patch_attr = patchTopo->GetBdrAttribute(b);
3988 if (activeBdrElem[g_be])
3990 ind[0] = activeVert[p2g[0]];
3991 boundary[l_be] = new Point(ind, bdr_patch_attr);
3998void NURBSExtension::Get2DBdrElementTopo(Array<Element *> &boundary) const
4002 NURBSPatchMap p2g(this);
4003 const KnotVector *kv[1];
4006 for (int b = 0; b < GetNBP(); b++)
4008 p2g.SetBdrPatchVertexMap(b, kv, okv);
4011 int bdr_patch_attr = patchTopo->GetBdrAttribute(b);
4013 for (int i = 0; i < nx; i++)
4015 if (activeBdrElem[g_be])
4017 int i_ = (okv[0] >= 0) ? i : (nx - 1 - i);
4018 ind[0] = activeVert[p2g[i_ ]];
4019 ind[1] = activeVert[p2g[i_+1]];
4021 boundary[l_be] = new Segment(ind, bdr_patch_attr);
4029void NURBSExtension::Get3DBdrElementTopo(Array<Element *> &boundary) const
4033 NURBSPatchMap p2g(this);
4034 const KnotVector *kv[2];
4037 for (int b = 0; b < GetNBP(); b++)
4039 p2g.SetBdrPatchVertexMap(b, kv, okv);
4043 int bdr_patch_attr = patchTopo->GetBdrAttribute(b);
4045 for (int j = 0; j < ny; j++)
4047 int j_ = (okv[1] >= 0) ? j : (ny - 1 - j);
4048 for (int i = 0; i < nx; i++)
4050 if (activeBdrElem[g_be])
4052 int i_ = (okv[0] >= 0) ? i : (nx - 1 - i);
4053 ind[0] = activeVert[p2g(i_, j_ )];
4054 ind[1] = activeVert[p2g(i_+1,j_ )];
4055 ind[2] = activeVert[p2g(i_+1,j_+1)];
4056 ind[3] = activeVert[p2g(i_, j_+1)];
4058 boundary[l_be] = new Quadrilateral(ind, bdr_patch_attr);
4067void NURBSExtension::GenerateElementDofTable()
4069 activeDof.SetSize(GetNTotalDof());
4072 if (Dimension() == 1)
4074 Generate1DElementDofTable();
4076 else if (Dimension() == 2)
4078 Generate2DElementDofTable();
4082 Generate3DElementDofTable();
4085 SetPatchToElements();
4087 NumOfActiveDofs = 0;
4088 for (int d = 0; d < GetNTotalDof(); d++)
4092 activeDof[d] = NumOfActiveDofs;
4095 int *dof = el_dof->GetJ();
4096 int ndof = el_dof->Size_of_connections();
4097 for (int i = 0; i < ndof; i++)
4099 dof[i] = activeDof[dof[i]] - 1;
4103void NURBSExtension::Generate1DElementDofTable()
4107 const KnotVector *kv[2];
4108 NURBSPatchMap p2g(this);
4110 Array<Connection> el_dof_list;
4111 el_to_patch.SetSize(NumOfActiveElems);
4112 el_to_IJK.SetSize(NumOfActiveElems, 2);
4114 for (int p = 0; p < GetNP(); p++)
4116 p2g.SetPatchDofMap(p, kv);
4119 const int ord0 = kv[0]->GetOrder();
4120 for (int i = 0; i < kv[0]->GetNKS(); i++)
4122 if (kv[0]->isElement(i))
4126 Connection conn(el,0);
4127 for (int ii = 0; ii <= ord0; ii++)
4129 conn.to = DofMap(p2g(i+ii));
4130 activeDof[conn.to] = 1;
4131 el_dof_list.Append(conn);
4133 el_to_patch[el] = p;
4134 el_to_IJK(el,0) = i;
4142 // We must NOT sort el_dof_list in this case.
4143 el_dof = new Table(NumOfActiveElems, el_dof_list);
4146void NURBSExtension::Generate2DElementDofTable()
4150 const KnotVector *kv[2];
4151 NURBSPatchMap p2g(this);
4153 Array<Connection> el_dof_list;
4154 el_to_patch.SetSize(NumOfActiveElems);
4155 el_to_IJK.SetSize(NumOfActiveElems, 2);
4157 for (int p = 0; p < GetNP(); p++)
4159 p2g.SetPatchDofMap(p, kv);
4162 const int ord0 = kv[0]->GetOrder();
4163 const int ord1 = kv[1]->GetOrder();
4164 for (int j = 0; j < kv[1]->GetNKS(); j++)
4166 if (kv[1]->isElement(j))
4168 for (int i = 0; i < kv[0]->GetNKS(); i++)
4170 if (kv[0]->isElement(i))
4174 Connection conn(el,0);
4175 for (int jj = 0; jj <= ord1; jj++)
4177 for (int ii = 0; ii <= ord0; ii++)
4179 conn.to = DofMap(p2g(i+ii,j+jj));
4180 activeDof[conn.to] = 1;
4181 el_dof_list.Append(conn);
4184 el_to_patch[el] = p;
4185 el_to_IJK(el,0) = i;
4186 el_to_IJK(el,1) = j;
4196 // We must NOT sort el_dof_list in this case.
4197 el_dof = new Table(NumOfActiveElems, el_dof_list);
4200void NURBSExtension::Generate3DElementDofTable()
4204 const KnotVector *kv[3];
4205 NURBSPatchMap p2g(this);
4207 Array<Connection> el_dof_list;
4208 el_to_patch.SetSize(NumOfActiveElems);
4209 el_to_IJK.SetSize(NumOfActiveElems, 3);
4211 for (int p = 0; p < GetNP(); p++)
4213 p2g.SetPatchDofMap(p, kv);
4216 const int ord0 = kv[0]->GetOrder();
4217 const int ord1 = kv[1]->GetOrder();
4218 const int ord2 = kv[2]->GetOrder();
4219 for (int k = 0; k < kv[2]->GetNKS(); k++)
4221 if (kv[2]->isElement(k))
4223 for (int j = 0; j < kv[1]->GetNKS(); j++)
4225 if (kv[1]->isElement(j))
4227 for (int i = 0; i < kv[0]->GetNKS(); i++)
4229 if (kv[0]->isElement(i))
4233 Connection conn(el,0);
4234 for (int kk = 0; kk <= ord2; kk++)
4236 for (int jj = 0; jj <= ord1; jj++)
4238 for (int ii = 0; ii <= ord0; ii++)
4240 conn.to = DofMap(p2g(i+ii, j+jj, k+kk));
4241 activeDof[conn.to] = 1;
4242 el_dof_list.Append(conn);
4247 el_to_patch[el] = p;
4248 el_to_IJK(el,0) = i;
4249 el_to_IJK(el,1) = j;
4250 el_to_IJK(el,2) = k;
4262 // We must NOT sort el_dof_list in this case.
4263 el_dof = new Table(NumOfActiveElems, el_dof_list);
4266void NURBSExtension::GetPatchDofs(const int patch, Array<int> &dofs)
4268 const KnotVector *kv[3];
4269 NURBSPatchMap p2g(this);
4271 p2g.SetPatchDofMap(patch, kv);
4273 if (Dimension() == 1)
4275 const int nx = kv[0]->GetNCP();
4278 for (int i=0; i<nx; ++i)
4280 dofs[i] = DofMap(p2g(i));
4283 else if (Dimension() == 2)
4285 const int nx = kv[0]->GetNCP();
4286 const int ny = kv[1]->GetNCP();
4287 dofs.SetSize(nx * ny);
4289 for (int j=0; j<ny; ++j)
4290 for (int i=0; i<nx; ++i)
4292 dofs[i + (nx * j)] = DofMap(p2g(i, j));
4295 else if (Dimension() == 3)
4297 const int nx = kv[0]->GetNCP();
4298 const int ny = kv[1]->GetNCP();
4299 const int nz = kv[2]->GetNCP();
4300 dofs.SetSize(nx * ny * nz);
4302 for (int k=0; k<nz; ++k)
4303 for (int j=0; j<ny; ++j)
4304 for (int i=0; i<nx; ++i)
4306 dofs[i + (nx * (j + (k * ny)))] = DofMap(p2g(i, j, k));
4311 MFEM_ABORT("Only 1D/2D/3D supported currently in
NURBSExtension::GetPatchDofs
");
4315void NURBSExtension::GenerateBdrElementDofTable()
4317 if (Dimension() == 1)
4319 Generate1DBdrElementDofTable();
4321 else if (Dimension() == 2)
4323 Generate2DBdrElementDofTable();
4327 Generate3DBdrElementDofTable();
4330 SetPatchToBdrElements();
4332 int *dof = bel_dof->GetJ();
4333 int ndof = bel_dof->Size_of_connections();
4334 for (int i = 0; i < ndof; i++)
4339 dof[i] = -1 - (activeDof[-1-idx] - 1);
4340 dof[i] = -activeDof[-1-idx];
4344 dof[i] = activeDof[idx] - 1;
4349void NURBSExtension::Generate1DBdrElementDofTable()
4352 int lbe = 0, okv[1];
4353 const KnotVector *kv[1];
4354 NURBSPatchMap p2g(this);
4356 Array<Connection> bel_dof_list;
4357 bel_to_patch.SetSize(NumOfActiveBdrElems);
4358 bel_to_IJK.SetSize(NumOfActiveBdrElems, 1);
4360 for (int b = 0; b < GetNBP(); b++)
4362 p2g.SetBdrPatchDofMap(b, kv, okv);
4364 if (activeBdrElem[gbe])
4366 Connection conn(lbe,0);
4367 conn.to = DofMap(p2g[0]);
4368 bel_dof_list.Append(conn);
4369 bel_to_patch[lbe] = b;
4370 bel_to_IJK(lbe,0) = 0;
4375 // We must NOT sort bel_dof_list in this case.
4376 bel_dof = new Table(NumOfActiveBdrElems, bel_dof_list);
4379void NURBSExtension::Generate2DBdrElementDofTable()
4382 int lbe = 0, okv[1];
4383 const KnotVector *kv[1];
4384 NURBSPatchMap p2g(this);
4386 Array<Connection> bel_dof_list;
4387 bel_to_patch.SetSize(NumOfActiveBdrElems);
4388 bel_to_IJK.SetSize(NumOfActiveBdrElems, 1);
4390 for (int b = 0; b < GetNBP(); b++)
4392 p2g.SetBdrPatchDofMap(b, kv, okv);
4393 const int nx = p2g.nx(); // NCP-1
4395 const int nks0 = kv[0]->GetNKS();
4396 const int ord0 = kv[0]->GetOrder();
4398 bool add_dofs = true;
4401 if (mode == Mode::H_DIV)
4403 int fn = patchTopo->GetBdrElementFaceIndex(b);
4404 if (ord0 == mOrders.Max()) { add_dofs = false; }
4405 if (fn == 0) { s = -1; }
4406 if (fn == 2) { s = -1; }
4408 else if (mode == Mode::H_CURL)
4410 if (ord0 == mOrders.Max()) { add_dofs = false; }
4413 for (int i = 0; i < nks0; i++)
4415 if (kv[0]->isElement(i))
4417 if (activeBdrElem[gbe])
4419 Connection conn(lbe,0);
4422 for (int ii = 0; ii <= ord0; ii++)
4424 conn.to = DofMap(p2g[(okv[0] >= 0) ? (i+ii) : (nx-i-ii)]);
4425 if (s == -1) { conn.to = -1 -conn.to; }
4426 bel_dof_list.Append(conn);
4429 bel_to_patch[lbe] = b;
4430 bel_to_IJK(lbe,0) = (okv[0] >= 0) ? i : (-1-i);
4437 // We must NOT sort bel_dof_list in this case.
4438 bel_dof = new Table(NumOfActiveBdrElems, bel_dof_list);
4442void NURBSExtension::Generate3DBdrElementDofTable()
4445 int lbe = 0, okv[2];
4446 const KnotVector *kv[2];
4447 NURBSPatchMap p2g(this);
4449 Array<Connection> bel_dof_list;
4450 bel_to_patch.SetSize(NumOfActiveBdrElems);
4451 bel_to_IJK.SetSize(NumOfActiveBdrElems, 2);
4453 for (int b = 0; b < GetNBP(); b++)
4455 p2g.SetBdrPatchDofMap(b, kv, okv);
4456 const int nx = p2g.nx(); // NCP0-1
4457 const int ny = p2g.ny(); // NCP1-1
4460 const int nks0 = kv[0]->GetNKS();
4461 const int ord0 = kv[0]->GetOrder();
4462 const int nks1 = kv[1]->GetNKS();
4463 const int ord1 = kv[1]->GetOrder();
4465 // Check if dofs are actually defined on boundary
4466 bool add_dofs = true;
4469 if (mode == Mode::H_DIV)
4471 int fn = patchTopo->GetBdrElementFaceIndex(b);
4472 if (ord0 != ord1) { add_dofs = false; }
4473 if (fn == 4) { s = -1; }
4474 if (fn == 1) { s = -1; }
4475 if (fn == 0) { s = -1; }
4477 else if (mode == Mode::H_CURL)
4479 if (ord0 == ord1) { add_dofs = false; }
4483 for (int j = 0; j < nks1; j++)
4485 if (kv[1]->isElement(j))
4487 for (int i = 0; i < nks0; i++)
4489 if (kv[0]->isElement(i))
4491 if (activeBdrElem[gbe])
4493 Connection conn(lbe,0);
4496 for (int jj = 0; jj <= ord1; jj++)
4498 const int jj_ = (okv[1] >= 0) ? (j+jj) : (ny-j-jj);
4499 for (int ii = 0; ii <= ord0; ii++)
4501 const int ii_ = (okv[0] >= 0) ? (i+ii) : (nx-i-ii);
4502 conn.to = DofMap(p2g(ii_, jj_));
4503 if (s == -1) { conn.to = -1 -conn.to; }
4504 bel_dof_list.Append(conn);
4508 bel_to_patch[lbe] = b;
4509 bel_to_IJK(lbe,0) = (okv[0] >= 0) ? i : (-1-i);
4510 bel_to_IJK(lbe,1) = (okv[1] >= 0) ? j : (-1-j);
4519 // We must NOT sort bel_dof_list in this case.
4520 bel_dof = new Table(NumOfActiveBdrElems, bel_dof_list);
4523void NURBSExtension::GetVertexLocalToGlobal(Array<int> &lvert_vert)
4525 lvert_vert.SetSize(GetNV());
4526 for (int gv = 0; gv < GetGNV(); gv++)
4527 if (activeVert[gv] >= 0)
4529 lvert_vert[activeVert[gv]] = gv;
4533void NURBSExtension::GetElementLocalToGlobal(Array<int> &lelem_elem)
4535 lelem_elem.SetSize(GetNE());
4536 for (int le = 0, ge = 0; ge < GetGNE(); ge++)
4539 lelem_elem[le++] = ge;
4543void NURBSExtension::LoadFE(int i, const FiniteElement *FE) const
4545 const NURBSFiniteElement *NURBSFE =
4546 dynamic_cast<const NURBSFiniteElement *>(FE);
4548 if (NURBSFE->GetElement() != i)
4551 NURBSFE->SetIJK(el_to_IJK.GetRow(i));
4552 if (el_to_patch[i] != NURBSFE->GetPatch())
4554 GetPatchKnotVectors(el_to_patch[i], NURBSFE->KnotVectors());
4555 NURBSFE->SetPatch(el_to_patch[i]);
4556 NURBSFE->SetOrder();
4558 el_dof->GetRow(i, dofs);
4559 weights.GetSubVector(dofs, NURBSFE->Weights());
4560 NURBSFE->SetElement(i);
4564void NURBSExtension::LoadBE(int i, const FiniteElement *BE) const
4566 if (Dimension() == 1) { return; }
4568 const NURBSFiniteElement *NURBSFE =
4569 dynamic_cast<const NURBSFiniteElement *>(BE);
4571 if (NURBSFE->GetElement() != i)
4574 NURBSFE->SetIJK(bel_to_IJK.GetRow(i));
4575 if (bel_to_patch[i] != NURBSFE->GetPatch())
4577 GetBdrPatchKnotVectors(bel_to_patch[i], NURBSFE->KnotVectors());
4578 NURBSFE->SetPatch(bel_to_patch[i]);
4579 NURBSFE->SetOrder();
4581 bel_dof->GetRow(i, dofs);
4582 weights.GetSubVector(dofs, NURBSFE->Weights());
4583 NURBSFE->SetElement(i);
4587void NURBSExtension::ConvertToPatches(const Vector &Nodes)
4592 if (patches.Size() == 0)
4594 GetPatchNets(Nodes, Dimension());
4598void NURBSExtension::SetCoordsFromPatches(Vector &Nodes)
4600 if (patches.Size() == 0) { return; }
4602 SetSolutionVector(Nodes, Dimension());
4606void NURBSExtension::SetKnotsFromPatches()
4608 if (patches.Size() == 0)
4611 " No patches available!
");
4614 Array<KnotVector *> kv;
4616 for (int p = 0; p < patches.Size(); p++)
4618 GetPatchKnotVectors(p, kv);
4620 for (int i = 0; i < kv.Size(); i++)
4622 *kv[i] = *patches[p]->GetKV(i);
4627 SetOrdersFromKnotVectors();
4633 // all elements must be active
4634 NumOfActiveElems = NumOfElements;
4635 activeElem.SetSize(NumOfElements);
4638 GenerateActiveVertices();
4640 GenerateElementDofTable();
4641 GenerateActiveBdrElems();
4642 GenerateBdrElementDofTable();
4644 ConnectBoundaries();
4647void NURBSExtension::LoadSolution(std::istream &input, GridFunction &sol) const
4649 const FiniteElementSpace *fes = sol.FESpace();
4650 MFEM_VERIFY(fes->GetNURBSext() == this, "");
4652 sol.SetSize(fes->GetVSize());
4654 Array<const KnotVector *> kv(Dimension());
4655 NURBSPatchMap p2g(this);
4656 const int vdim = fes->GetVDim();
4658 for (int p = 0; p < GetNP(); p++)
4660 skip_comment_lines(input, '#');
4662 p2g.SetPatchDofMap(p, kv);
4663 const int nx = kv[0]->GetNCP();
4664 const int ny = kv[1]->GetNCP();
4665 const int nz = (kv.Size() == 2) ? 1 : kv[2]->GetNCP();
4666 for (int k = 0; k < nz; k++)
4668 for (int j = 0; j < ny; j++)
4670 for (int i = 0; i < nx; i++)
4672 const int ll = (kv.Size() == 2) ? p2g(i,j) : p2g(i,j,k);
4673 const int l = DofMap(ll);
4674 for (int vd = 0; vd < vdim; vd++)
4676 input >> sol(fes->DofToVDof(l,vd));
4684void NURBSExtension::PrintSolution(const GridFunction &sol, std::ostream &os)
4687 const FiniteElementSpace *fes = sol.FESpace();
4688 MFEM_VERIFY(fes->GetNURBSext() == this, "");
4690 Array<const KnotVector *> kv(Dimension());
4691 NURBSPatchMap p2g(this);
4692 const int vdim = fes->GetVDim();
4694 for (int p = 0; p < GetNP(); p++)
4696 os << "\n# patch
" << p << "\n\n
";
4698 p2g.SetPatchDofMap(p, kv);
4699 const int nx = kv[0]->GetNCP();
4700 const int ny = kv[1]->GetNCP();
4701 const int nz = (kv.Size() == 2) ? 1 : kv[2]->GetNCP();
4702 for (int k = 0; k < nz; k++)
4704 for (int j = 0; j < ny; j++)
4706 for (int i = 0; i < nx; i++)
4708 const int ll = (kv.Size() == 2) ? p2g(i,j) : p2g(i,j,k);
4709 const int l = DofMap(ll);
4710 os << sol(fes->DofToVDof(l,0));
4711 for (int vd = 1; vd < vdim; vd++)
4713 os << ' ' << sol(fes->DofToVDof(l,vd));
4722void NURBSExtension::DegreeElevate(int rel_degree, int degree)
4724 for (int p = 0; p < patches.Size(); p++)
4726 for (int dir = 0; dir < patches[p]->GetNKV(); dir++)
4728 int oldd = patches[p]->GetKV(dir)->GetOrder();
4729 int newd = std::min(oldd + rel_degree, degree);
4732 patches[p]->DegreeElevate(dir, newd - oldd);
4738NURBSExtension* NURBSExtension::GetDivExtension(int component)
4744 "only works for single patch NURBS meshes
");
4747 Array<int> newOrders = GetOrders();
4748 newOrders[component] += 1;
4750 return new NURBSExtension(this, newOrders, Mode::H_DIV);
4753NURBSExtension* NURBSExtension::GetCurlExtension(int component)
4759 "only works for single patch NURBS meshes
");
4762 Array<int> newOrders = GetOrders();
4763 for (int c = 0; c < newOrders.Size(); c++) { newOrders[c]++; }
4764 newOrders[component] -= 1;
4766 return new NURBSExtension(this, newOrders, Mode::H_CURL);
4769void NURBSExtension::UniformRefinement(const Array<int> &rf)
4771 for (int p = 0; p < patches.Size(); p++)
4773 patches[p]->UniformRefinement(rf);
4777void NURBSExtension::UniformRefinement(int rf)
4779 Array<int> rf_array(Dimension());
4781 UniformRefinement(rf_array);
4784void NURBSExtension::Coarsen(const Array<int> &cf, real_t tol)
4786 // First, mark all knot vectors on all patches as not coarse. This prevents
4787 // coarsening the same knot vector twice.
4788 for (int p = 0; p < patches.Size(); p++)
4790 patches[p]->SetKnotVectorsCoarse(false);
4793 for (int p = 0; p < patches.Size(); p++)
4795 patches[p]->Coarsen(cf, tol);
4798 if (ref_factors.Size() > 0)
4800 MFEM_VERIFY(cf.Size() == ref_factors.Size(), "");
4801 for (int i=0; i<cf.Size(); ++i) { ref_factors[i] /= cf[i]; }
4805void NURBSExtension::FullyCoarsen()
4807 // First, mark all knot vectors on all patches as not coarse. This prevents
4808 // coarsening the same knot vector twice.
4809 for (int p = 0; p < patches.Size(); p++)
4811 patches[p]->SetKnotVectorsCoarse(false);
4814 const int maxOrder = mOrders.Max();
4816 // For degree maxOrder, there are 2*(maxOrder + 1) knots for a single element,
4817 // and the number of control points in each dimension is
4818 // 2*(maxOrder + 1) - maxOrder - 1
4819 const int ncp1D = maxOrder + 1;
4820 const int ncp = static_cast<int>(pow(ncp1D, Dimension()));
4822 for (int p = 0; p < patches.Size(); p++)
4824 if (p < num_structured_patches)
4826 // Use data from patchCP
4827 Array2D<double> pcp(ncp, Dimension());
4828 for (int i=0; i<ncp; ++i)
4830 for (int j=0; j<Dimension(); ++j) { pcp(i, j) = patchCP(p, i, j); }
4833 patches[p]->FullyCoarsen(pcp, ncp1D);
4838void NURBSExtension::Coarsen(int cf, real_t tol)
4840 Array<int> cf_array(Dimension());
4842 Coarsen(cf_array, tol);
4845void NURBSExtension::GetCoarseningFactors(Array<int> & f) const
4848 for (auto patch : patches)
4851 patch->GetCoarseningFactors(pf);
4854 f = pf; // Initialize
4858 MFEM_VERIFY(f.Size() == pf.Size(), "");
4859 for (int i=0; i<f.Size(); ++i)
4861 if (nonconformingPT)
4863 if ((f[i] == 1 && pf[i] != 1) || (pf[i] < f[i] && pf[i] != 1))
4870 MFEM_VERIFY(f[i] == pf[i] || f[i] == 1 || pf[i] == 1,
4871 "Inconsistent patch coarsening factors
");
4872 if (f[i] == 1 && pf[i] != 1)
4882void NURBSExtension::KnotInsert(Array<KnotVector *> &kv)
4888 Array<KnotVector *> pkv(Dimension());
4890 for (int p = 0; p < patches.Size(); p++)
4894 pkv[0] = kv[KnotInd(p)];
4896 else if (Dimension()==2)
4898 patchTopo->GetElementEdges(p, edges, orient);
4899 pkv[0] = kv[KnotInd(edges[0])];
4900 pkv[1] = kv[KnotInd(edges[1])];
4902 else if (Dimension()==3)
4904 patchTopo->GetElementEdges(p, edges, orient);
4905 pkv[0] = kv[KnotInd(edges[0])];
4906 pkv[1] = kv[KnotInd(edges[3])];
4907 pkv[2] = kv[KnotInd(edges[8])];
4910 // Check whether inserted knots should be flipped before inserting.
4911 // Knotvectors are stored in a different array pkvc such that the original
4912 // knots which are inserted are not changed.
4913 // We need those knots for multiple patches so they have to remain original
4914 CheckKVDirection(p, kvdir);
4916 Array<KnotVector *> pkvc(Dimension());
4917 for (int d = 0; d < Dimension(); d++)
4919 pkvc[d] = new KnotVector(*(pkv[d]));
4927 patches[p]->KnotInsert(pkvc);
4928 for (int d = 0; d < Dimension(); d++) { delete pkvc[d]; }
4932void NURBSExtension::KnotInsert(Array<Vector *> &kv)
4938 Array<Vector *> pkv(Dimension());
4940 for (int p = 0; p < patches.Size(); p++)
4944 pkv[0] = kv[KnotInd(p)];
4946 else if (Dimension()==2)
4948 patchTopo->GetElementEdges(p, edges, orient);
4949 pkv[0] = kv[KnotInd(edges[0])];
4950 pkv[1] = kv[KnotInd(edges[1])];
4952 else if (Dimension()==3)
4954 patchTopo->GetElementEdges(p, edges, orient);
4955 pkv[0] = kv[KnotInd(edges[0])];
4956 pkv[1] = kv[KnotInd(edges[3])];
4957 pkv[2] = kv[KnotInd(edges[8])];
4960 // Check whether inserted knots should be flipped before inserting.
4961 // Knotvectors are stored in a different array pkvc such that the original
4962 // knots which are inserted are not changed.
4963 CheckKVDirection(p, kvdir);
4965 Array<Vector *> pkvc(Dimension());
4966 for (int d = 0; d < Dimension(); d++)
4968 pkvc[d] = new Vector(*(pkv[d]));
4972 // Find flip point, for knotvectors that do not have the domain [0:1]
4973 KnotVector *kva = knotVectorsCompr[Dimension()*p+d];
4974 real_t apb = (*kva)[0] + (*kva)[kva->Size()-1];
4977 int size = pkvc[d]->Size();
4978 int ns = static_cast<int>(ceil(size/2.0));
4979 for (int j = 0; j < ns; j++)
4981 real_t tmp = apb - pkvc[d]->Elem(j);
4982 pkvc[d]->Elem(j) = apb - pkvc[d]->Elem(size-1-j);
4983 pkvc[d]->Elem(size-1-j) = tmp;
4988 patches[p]->KnotInsert(pkvc);
4990 for (int i = 0; i < Dimension(); i++) { delete pkvc[i]; }
4994void NURBSExtension::KnotRemove(Array<Vector *> &kv, real_t tol)
5000 Array<Vector *> pkv(Dimension());
5002 for (int p = 0; p < patches.Size(); p++)
5006 pkv[0] = kv[KnotInd(p)];
5008 else if (Dimension()==2)
5010 patchTopo->GetElementEdges(p, edges, orient);
5011 pkv[0] = kv[KnotInd(edges[0])];
5012 pkv[1] = kv[KnotInd(edges[1])];
5014 else if (Dimension()==3)
5016 patchTopo->GetElementEdges(p, edges, orient);
5017 pkv[0] = kv[KnotInd(edges[0])];
5018 pkv[1] = kv[KnotInd(edges[3])];
5019 pkv[2] = kv[KnotInd(edges[8])];
5022 // Check whether knots should be flipped before removing.
5023 CheckKVDirection(p, kvdir);
5025 Array<Vector *> pkvc(Dimension());
5026 for (int d = 0; d < Dimension(); d++)
5028 pkvc[d] = new Vector(*(pkv[d]));
5032 // Find flip point, for knotvectors that do not have the domain [0:1]
5033 KnotVector *kva = knotVectorsCompr[Dimension()*p+d];
5034 real_t apb = (*kva)[0] + (*kva)[kva->Size()-1];
5037 int size = pkvc[d]->Size();
5038 int ns = static_cast<int>(ceil(size/2.0));
5039 for (int j = 0; j < ns; j++)
5041 real_t tmp = apb - pkvc[d]->Elem(j);
5042 pkvc[d]->Elem(j) = apb - pkvc[d]->Elem(size-1-j);
5043 pkvc[d]->Elem(size-1-j) = tmp;
5048 patches[p]->KnotRemove(pkvc, tol);
5050 for (int i = 0; i < Dimension(); i++) { delete pkvc[i]; }
5054void NURBSExtension::GetPatchNets(const Vector &coords, int vdim)
5056 if (Dimension() == 1)
5058 Get1DPatchNets(coords, vdim);
5060 else if (Dimension() == 2)
5062 Get2DPatchNets(coords, vdim);
5066 Get3DPatchNets(coords, vdim);
5070void NURBSExtension::Get1DPatchNets(const Vector &coords, int vdim)
5072 Array<const KnotVector *> kv(1);
5073 NURBSPatchMap p2g(this);
5075 patches.SetSize(GetNP());
5076 for (int p = 0; p < GetNP(); p++)
5078 p2g.SetPatchDofMap(p, kv);
5079 patches[p] = new NURBSPatch(kv, vdim+1);
5080 NURBSPatch &Patch = *patches[p];
5082 for (int i = 0; i < kv[0]->GetNCP(); i++)
5084 const int l = DofMap(p2g(i));
5085 for (int d = 0; d < vdim; d++)
5087 Patch(i,d) = coords(l*vdim + d)*weights(l);
5089 Patch(i,vdim) = weights(l);
5094void NURBSExtension::Get2DPatchNets(const Vector &coords, int vdim)
5096 Array<const KnotVector *> kv(2);
5097 NURBSPatchMap p2g(this);
5099 patches.SetSize(GetNP());
5100 for (int p = 0; p < GetNP(); p++)
5102 p2g.SetPatchDofMap(p, kv);
5103 patches[p] = new NURBSPatch(kv, vdim+1);
5104 NURBSPatch &Patch = *patches[p];
5106 for (int j = 0; j < kv[1]->GetNCP(); j++)
5108 for (int i = 0; i < kv[0]->GetNCP(); i++)
5110 const int l = DofMap(p2g(i,j));
5111 for (int d = 0; d < vdim; d++)
5113 Patch(i,j,d) = coords(l*vdim + d)*weights(l);
5115 Patch(i,j,vdim) = weights(l);
5121void NURBSExtension::Get3DPatchNets(const Vector &coords, int vdim)
5123 Array<const KnotVector *> kv(3);
5124 NURBSPatchMap p2g(this);
5126 patches.SetSize(GetNP());
5127 for (int p = 0; p < GetNP(); p++)
5129 p2g.SetPatchDofMap(p, kv);
5130 patches[p] = new NURBSPatch(kv, vdim+1);
5131 NURBSPatch &Patch = *patches[p];
5133 for (int k = 0; k < kv[2]->GetNCP(); k++)
5135 for (int j = 0; j < kv[1]->GetNCP(); j++)
5137 for (int i = 0; i < kv[0]->GetNCP(); i++)
5139 const int l = DofMap(p2g(i,j,k));
5140 for (int d = 0; d < vdim; d++)
5142 Patch(i,j,k,d) = coords(l*vdim + d)*weights(l);
5144 Patch(i,j,k,vdim) = weights(l);
5151void NURBSExtension::SetSolutionVector(Vector &coords, int vdim)
5153 if (Dimension() == 1)
5155 Set1DSolutionVector(coords, vdim);
5157 else if (Dimension() == 2)
5159 Set2DSolutionVector(coords, vdim);
5163 Set3DSolutionVector(coords, vdim);
5167void NURBSExtension::Set1DSolutionVector(Vector &coords, int vdim)
5169 Array<const KnotVector *> kv(1);
5170 NURBSPatchMap p2g(this);
5172 weights.SetSize(GetNDof());
5173 for (int p = 0; p < GetNP(); p++)
5175 p2g.SetPatchDofMap(p, kv);
5176 NURBSPatch &patch = *patches[p];
5177 MFEM_ASSERT(vdim+1 == patch.GetNC(), "");
5179 for (int i = 0; i < kv[0]->GetNCP(); i++)
5181 const int l = p2g(i);
5182 for (int d = 0; d < vdim; d++)
5184 coords(l*vdim + d) = patch(i,d)/patch(i,vdim);
5186 weights(l) = patch(i,vdim);
5193void NURBSExtension::Set2DSolutionVector(Vector &coords, int vdim)
5195 Array<const KnotVector *> kv(2);
5196 NURBSPatchMap p2g(this);
5198 const bool d2p = dof2patch.Size() > 0;
5200 weights.SetSize(GetNDof());
5201 for (int p = 0; p < GetNP(); p++)
5203 p2g.SetPatchDofMap(p, kv);
5204 NURBSPatch &patch = *patches[p];
5205 MFEM_ASSERT(vdim+1 == patch.GetNC(), "");
5207 for (int j = 0; j < kv[1]->GetNCP(); j++)
5209 for (int i = 0; i < kv[0]->GetNCP(); i++)
5211 const int l = p2g(i,j);
5212 if (d2p && dof2patch[l] >= 0 && dof2patch[l] != p) { continue; }
5214 for (int d = 0; d < vdim; d++)
5216 coords(l*vdim + d) = patch(i,j,d)/patch(i,j,vdim);
5218 weights(l) = patch(i,j,vdim);
5225void NURBSExtension::Set3DSolutionVector(Vector &coords, int vdim)
5227 Array<const KnotVector *> kv(3);
5228 NURBSPatchMap p2g(this);
5230 const bool d2p = dof2patch.Size() > 0;
5232 weights.SetSize(GetNDof());
5233 for (int p = 0; p < GetNP(); p++)
5235 p2g.SetPatchDofMap(p, kv);
5236 NURBSPatch &patch = *patches[p];
5237 MFEM_ASSERT(vdim+1 == patch.GetNC(), "");
5239 for (int k = 0; k < kv[2]->GetNCP(); k++)
5241 for (int j = 0; j < kv[1]->GetNCP(); j++)
5243 for (int i = 0; i < kv[0]->GetNCP(); i++)
5245 const int l = p2g(i,j,k);
5246 if (d2p && dof2patch[l] >= 0 && dof2patch[l] != p) { continue; }
5248 for (int d = 0; d < vdim; d++)
5250 coords(l*vdim + d) = patch(i,j,k,d)/patch(i,j,k,vdim);
5252 weights(l) = patch(i,j,k,vdim);
5260void NURBSExtension::GetElementIJK(int elem, Array<int> & ijk)
5262 MFEM_VERIFY(ijk.Size() == el_to_IJK.NumCols(), "");
5263 el_to_IJK.GetRow(elem, ijk);
5266void NURBSExtension::GetPatches(Array<NURBSPatch*> &patches_copy)
5268 const int NP = patches.Size();
5269 patches_copy.SetSize(NP);
5270 for (int p = 0; p < NP; p++)
5272 patches_copy[p] = new NURBSPatch(*GetPatch(p));
5276void NURBSExtension::SetPatchToElements()
5278 const int np = GetNP();
5279 patch_to_el.resize(np);
5281 for (int e=0; e<el_to_patch.Size(); ++e)
5283 patch_to_el[el_to_patch[e]].Append(e);
5287void NURBSExtension::SetPatchToBdrElements()
5289 const int nbp = GetNBP();
5290 patch_to_bel.resize(nbp);
5292 for (int e=0; e<bel_to_patch.Size(); ++e)
5294 patch_to_bel[bel_to_patch[e]].Append(e);
5298const Array<int>& NURBSExtension::GetPatchElements(int patch)
5300 MFEM_ASSERT(patch_to_el.size() > 0, "patch_to_el not set
");
5302 return patch_to_el[patch];
5305const Array<int>& NURBSExtension::GetPatchBdrElements(int patch)
5307 MFEM_ASSERT(patch_to_bel.size() > 0, "patch_to_el not set
");
5309 return patch_to_bel[patch];
5312void NURBSExtension::GetVertexDofs(int vertex, Array<int> &dofs) const
5314 MFEM_ASSERT(vertex < v_spaceOffsets.Size(), "");
5316 const int os = v_spaceOffsets[vertex];
5317 const int os1 = vertex + 1 == v_spaceOffsets.Size() ? e_spaceOffsets[0] :
5318 v_spaceOffsets[vertex + 1];
5321 dofs.Reserve(os1 - os);
5323 for (int i=os; i<os1; ++i) { dofs.Append(i); }
5326void NURBSExtension::GetEdgeDofs(int edge, Array<int> &dofs) const
5328 MFEM_ASSERT(edge < e_spaceOffsets.Size(), "");
5330 const int os = e_spaceOffsets[edge];
5331 const int os_upper = f_spaceOffsets.Size() > 0 ? f_spaceOffsets[0] :
5333 const int os1 = edge + 1 == e_spaceOffsets.Size() ? os_upper :
5334 v_spaceOffsets[edge + 1];
5337 // Reserve 2 for the two vertices and os1 - os for the interior edge DOFs.
5338 dofs.Reserve(2 + os1 - os);
5340 // First get the DOFs for the vertices of the edge.
5343 patchTopo->GetEdgeVertices(edge, vert);
5348 GetVertexDofs(v, vdofs);
5352 // Now get the interior edge DOFs.
5353 for (int i=os; i<os1; ++i) { dofs.Append(i); }
5356void NURBSExtension::ReadCoarsePatchCP(std::istream &input)
5361void NURBSExtension::PrintCoarsePatches(std::ostream &os)
5363 const int patchCP_size1 = patchCP.GetSize1();
5364 MFEM_VERIFY(patchCP_size1 == num_structured_patches || patchCP_size1 == 0,
5367 if (patchCP_size1 == 0) { return; }
5372int NURBSExtension::VertexPairToEdge(const std::pair<int, int> &vertices) const
5378void NURBSExtension::GetMasterEdgeDofs(bool dof, int me, Array<int> &dofs) const
5383void NURBSExtension::GetMasterFaceDofs(bool dof, int mf,
5384 Array2D<int> &dofs) const
5389void NURBSExtension::RefineWithKVFactors(int rf,
5390 const std::string &kvf_filename,
5396NURBSPatch::NURBSPatch(const KnotVector *kv0, const KnotVector *kv1, int dim_,
5397 const real_t* control_points)
5400 kv[0] = new KnotVector(*kv0);
5401 kv[1] = new KnotVector(*kv1);
5403 memcpy(data, control_points, sizeof (real_t) * ni * nj * dim_);
5406NURBSPatch::NURBSPatch(const KnotVector *kv0, const KnotVector *kv1,
5407 const KnotVector *kv2, int dim_,
5408 const real_t* control_points)
5411 kv[0] = new KnotVector(*kv0);
5412 kv[1] = new KnotVector(*kv1);
5413 kv[2] = new KnotVector(*kv2);
5415 memcpy(data, control_points, sizeof (real_t) * ni * nj * nk * dim_);
5418NURBSPatch::NURBSPatch(Array<const KnotVector *> &kv_, int dim_,
5419 const real_t* control_points)
5421 kv.SetSize(kv_.Size());
5423 for (int i = 0; i < kv.Size(); i++)
5425 kv[i] = new KnotVector(*kv_[i]);
5426 n *= kv[i]->GetNCP();
5429 memcpy(data, control_points, sizeof(real_t)*n);
5433ParNURBSExtension::ParNURBSExtension(const ParNURBSExtension &orig)
5434 : NURBSExtension(orig),
5435 partitioning(orig.partitioning),
5437 ldof_group(orig.ldof_group)
5441ParNURBSExtension::ParNURBSExtension(MPI_Comm comm, NURBSExtension *parent,
5442 const int *partitioning_,
5443 const Array<bool> &active_bel)
5446 if (parent->NumOfActiveElems < parent->NumOfElements)
5448 // SetActive (BuildGroups?) and the way the weights are copied
5449 // do not support this case
5451 " all elements in the parent must be active!
");
5454 patchTopo = parent->patchTopo;
5455 // steal ownership of patchTopo from the 'parent' NURBS extension
5456 if (!parent->own_topo)
5459 " parent does not own the patch topology!
");
5462 parent->own_topo = false;
5464 parent->edge_to_ukv.Copy(edge_to_ukv);
5466 parent->GetOrders().Copy(mOrders);
5467 mOrder = parent->GetOrder();
5469 NumOfKnotVectors = parent->GetNKV();
5470 knotVectors.SetSize(NumOfKnotVectors);
5471 for (int i = 0; i < NumOfKnotVectors; i++)
5473 knotVectors[i] = new KnotVector(*parent->GetKnotVector(i));
5475 CreateComprehensiveKV();
5481 // copy 'partitioning_' to 'partitioning'
5482 partitioning.SetSize(GetGNE());
5483 for (int i = 0; i < GetGNE(); i++)
5485 partitioning[i] = partitioning_[i];
5487 SetActive(partitioning, active_bel);
5489 GenerateActiveVertices();
5490 GenerateElementDofTable();
5491 // GenerateActiveBdrElems(); // done by SetActive for now
5492 GenerateBdrElementDofTable();
5494 Table *serial_elem_dof = parent->GetElementDofTable();
5495 BuildGroups(partitioning, *serial_elem_dof);
5497 weights.SetSize(GetNDof());
5498 // copy weights from parent
5499 for (int gel = 0, lel = 0; gel < GetGNE(); gel++)
5501 if (activeElem[gel])
5503 int ndofs = el_dof->RowSize(lel);
5504 int *ldofs = el_dof->GetRow(lel);
5505 int *gdofs = serial_elem_dof->GetRow(gel);
5506 for (int i = 0; i < ndofs; i++)
5508 weights(ldofs[i]) = parent->weights(gdofs[i]);
5515ParNURBSExtension::ParNURBSExtension(NURBSExtension *parent,
5516 const ParNURBSExtension *par_parent)
5517 : gtopo(par_parent->gtopo.GetComm())
5519 // steal all data from parent
5520 mOrder = parent->mOrder;
5521 Swap(mOrders, parent->mOrders);
5523 patchTopo = parent->patchTopo;
5524 own_topo = parent->own_topo;
5525 parent->own_topo = false;
5527 Swap(edge_to_ukv, parent->edge_to_ukv);
5529 NumOfKnotVectors = parent->NumOfKnotVectors;
5530 Swap(knotVectors, parent->knotVectors);
5531 Swap(knotVectorsCompr, parent->knotVectorsCompr);
5533 NumOfVertices = parent->NumOfVertices;
5534 NumOfElements = parent->NumOfElements;
5535 NumOfBdrElements = parent->NumOfBdrElements;
5536 NumOfDofs = parent->NumOfDofs;
5538 Swap(v_meshOffsets, parent->v_meshOffsets);
5539 Swap(e_meshOffsets, parent->e_meshOffsets);
5540 Swap(f_meshOffsets, parent->f_meshOffsets);
5541 Swap(p_meshOffsets, parent->p_meshOffsets);
5543 Swap(v_spaceOffsets, parent->v_spaceOffsets);
5544 Swap(e_spaceOffsets, parent->e_spaceOffsets);
5545 Swap(f_spaceOffsets, parent->f_spaceOffsets);
5546 Swap(p_spaceOffsets, parent->p_spaceOffsets);
5548 Swap(d_to_d, parent->d_to_d);
5549 Swap(master, parent->master);
5550 Swap(slave, parent->slave);
5552 NumOfActiveVertices = parent->NumOfActiveVertices;
5553 NumOfActiveElems = parent->NumOfActiveElems;
5554 NumOfActiveBdrElems = parent->NumOfActiveBdrElems;
5555 NumOfActiveDofs = parent->NumOfActiveDofs;
5557 Swap(activeVert, parent->activeVert);
5558 Swap(activeElem, parent->activeElem);
5559 Swap(activeBdrElem, parent->activeBdrElem);
5560 Swap(activeDof, parent->activeDof);
5562 el_dof = parent->el_dof;
5563 bel_dof = parent->bel_dof;
5564 parent->el_dof = parent->bel_dof = NULL;
5566 Swap(el_to_patch, parent->el_to_patch);
5567 Swap(bel_to_patch, parent->bel_to_patch);
5568 Swap(el_to_IJK, parent->el_to_IJK);
5569 Swap(bel_to_IJK, parent->bel_to_IJK);
5571 Swap(weights, parent->weights);
5572 MFEM_VERIFY(!parent->HavePatches(), "");
5576 MFEM_VERIFY(par_parent->partitioning,
5579 // Support for the case when 'parent' is not a local NURBSExtension, i.e.
5580 // NumOfActiveElems is not the same as in 'par_parent'. In that case, we
5581 // assume 'parent' is a global NURBSExtension, i.e. all elements are active.
5582 bool extract_weights = false;
5583 if (NumOfActiveElems != par_parent->NumOfActiveElems)
5585 MFEM_ASSERT(NumOfActiveElems == NumOfElements, "internal error
");
5587 SetActive(par_parent->partitioning, par_parent->activeBdrElem);
5588 GenerateActiveVertices();
5590 el_to_patch.DeleteAll();
5591 el_to_IJK.DeleteAll();
5592 GenerateElementDofTable();
5593 // GenerateActiveBdrElems(); // done by SetActive for now
5595 bel_to_patch.DeleteAll();
5596 bel_to_IJK.DeleteAll();
5597 GenerateBdrElementDofTable();
5598 extract_weights = true;
5601 Table *glob_elem_dof = GetGlobalElementDofTable();
5602 BuildGroups(par_parent->partitioning, *glob_elem_dof);
5603 if (extract_weights)
5605 Vector glob_weights;
5606 Swap(weights, glob_weights);
5607 weights.SetSize(GetNDof());
5608 // Copy the local 'weights' from the 'glob_weights'.
5609 // Assumption: the local element ids follow the global ordering.
5610 for (int gel = 0, lel = 0; gel < GetGNE(); gel++)
5612 if (activeElem[gel])
5614 int ndofs = el_dof->RowSize(lel);
5615 int *ldofs = el_dof->GetRow(lel);
5616 int *gdofs = glob_elem_dof->GetRow(gel);
5617 for (int i = 0; i < ndofs; i++)
5619 weights(ldofs[i]) = glob_weights(gdofs[i]);
5625 delete glob_elem_dof;
5628Table *ParNURBSExtension::GetGlobalElementDofTable()
5630 if (Dimension() == 1)
5632 return Get1DGlobalElementDofTable();
5634 else if (Dimension() == 2)
5636 return Get2DGlobalElementDofTable();
5640 return Get3DGlobalElementDofTable();
5644Table *ParNURBSExtension::Get1DGlobalElementDofTable()
5647 const KnotVector *kv[1];
5648 NURBSPatchMap p2g(this);
5649 Array<Connection> gel_dof_list;
5651 for (int p = 0; p < GetNP(); p++)
5653 p2g.SetPatchDofMap(p, kv);
5656 const int ord0 = kv[0]->GetOrder();
5658 for (int i = 0; i < kv[0]->GetNKS(); i++)
5660 if (kv[0]->isElement(i))
5662 Connection conn(el,0);
5663 for (int ii = 0; ii <= ord0; ii++)
5665 conn.to = DofMap(p2g(i+ii));
5666 gel_dof_list.Append(conn);
5672 // We must NOT sort gel_dof_list in this case.
5673 return (new Table(GetGNE(), gel_dof_list));
5676Table *ParNURBSExtension::Get2DGlobalElementDofTable()
5679 const KnotVector *kv[2];
5680 NURBSPatchMap p2g(this);
5681 Array<Connection> gel_dof_list;
5683 for (int p = 0; p < GetNP(); p++)
5685 p2g.SetPatchDofMap(p, kv);
5688 const int ord0 = kv[0]->GetOrder();
5689 const int ord1 = kv[1]->GetOrder();
5690 for (int j = 0; j < kv[1]->GetNKS(); j++)
5692 if (kv[1]->isElement(j))
5694 for (int i = 0; i < kv[0]->GetNKS(); i++)
5696 if (kv[0]->isElement(i))
5698 Connection conn(el,0);
5699 for (int jj = 0; jj <= ord1; jj++)
5701 for (int ii = 0; ii <= ord0; ii++)
5703 conn.to = DofMap(p2g(i+ii,j+jj));
5704 gel_dof_list.Append(conn);
5713 // We must NOT sort gel_dof_list in this case.
5714 return (new Table(GetGNE(), gel_dof_list));
5717Table *ParNURBSExtension::Get3DGlobalElementDofTable()
5720 const KnotVector *kv[3];
5721 NURBSPatchMap p2g(this);
5722 Array<Connection> gel_dof_list;
5724 for (int p = 0; p < GetNP(); p++)
5726 p2g.SetPatchDofMap(p, kv);
5729 const int ord0 = kv[0]->GetOrder();
5730 const int ord1 = kv[1]->GetOrder();
5731 const int ord2 = kv[2]->GetOrder();
5732 for (int k = 0; k < kv[2]->GetNKS(); k++)
5734 if (kv[2]->isElement(k))
5736 for (int j = 0; j < kv[1]->GetNKS(); j++)
5738 if (kv[1]->isElement(j))
5740 for (int i = 0; i < kv[0]->GetNKS(); i++)
5742 if (kv[0]->isElement(i))
5744 Connection conn(el,0);
5745 for (int kk = 0; kk <= ord2; kk++)
5747 for (int jj = 0; jj <= ord1; jj++)
5749 for (int ii = 0; ii <= ord0; ii++)
5751 conn.to = DofMap(p2g(i+ii,j+jj,k+kk));
5752 gel_dof_list.Append(conn);
5764 // We must NOT sort gel_dof_list in this case.
5765 return (new Table(GetGNE(), gel_dof_list));
5768void ParNURBSExtension::SetActive(const int *partition,
5769 const Array<bool> &active_bel)
5771 activeElem.SetSize(GetGNE());
5773 NumOfActiveElems = 0;
5774 const int MyRank = gtopo.MyRank();
5775 for (int i = 0; i < GetGNE(); i++)
5776 if (partition[i] == MyRank)
5778 activeElem[i] = true;
5782 active_bel.Copy(activeBdrElem);
5783 NumOfActiveBdrElems = 0;
5784 for (int i = 0; i < GetGNBE(); i++)
5785 if (activeBdrElem[i])
5787 NumOfActiveBdrElems++;
5791void ParNURBSExtension::BuildGroups(const int *partition,
5792 const Table &elem_dof)
5796 ListOfIntegerSets groups;
5799 Transpose(elem_dof, dof_proc); // dof_proc is dof_elem
5801 // convert elements to processors
5802 for (int i = 0; i < dof_proc.Size_of_connections(); i++)
5804 dof_proc.GetJ()[i] = partition[dof_proc.GetJ()[i]];
5807 // the first group is the local one
5808 int MyRank = gtopo.MyRank();
5809 group.Recreate(1, &MyRank);
5810 groups.Insert(group);
5813 ldof_group.SetSize(GetNDof());
5814 for (int d = 0; d < GetNTotalDof(); d++)
5817 group.Recreate(dof_proc.RowSize(d), dof_proc.GetRow(d));
5818 ldof_group[dof] = groups.Insert(group);
5823 gtopo.Create(groups, 1822);
5825#endif // MFEM_USE_MPI
5828void NURBSPatchMap::GetPatchKnotVectors(int p, const KnotVector *kv[])
5830 Ext->patchTopo->GetElementVertices(p, verts);
5832 if (Ext->Dimension() == 1)
5834 kv[0] = Ext->knotVectorsCompr[Ext->Dimension()*p];
5836 else if (Ext->Dimension() == 2)
5838 Ext->patchTopo->GetElementEdges(p, edges, oedge);
5840 kv[0] = Ext->knotVectorsCompr[Ext->Dimension()*p];
5841 kv[1] = Ext->knotVectorsCompr[Ext->Dimension()*p + 1];
5843 else if (Ext->Dimension() == 3)
5845 Ext->patchTopo->GetElementEdges(p, edges, oedge);
5846 Ext->patchTopo->GetElementFaces(p, faces, oface);
5848 kv[0] = Ext->knotVectorsCompr[Ext->Dimension()*p];
5849 kv[1] = Ext->knotVectorsCompr[Ext->Dimension()*p + 1];
5850 kv[2] = Ext->knotVectorsCompr[Ext->Dimension()*p + 2];
5855void NURBSPatchMap::GetBdrPatchKnotVectors(int p, const KnotVector *kv[],
5858 Ext->patchTopo->GetBdrElementVertices(p, verts);
5860 if (Ext->Dimension() == 2)
5862 Ext->patchTopo->GetBdrElementEdges(p, edges, oedge);
5863 kv[0] = Ext->KnotVec(edges[0], oedge[0], &okv[0]);
5866 else if (Ext->Dimension() == 3)
5869 Ext->patchTopo->GetBdrElementEdges(p, edges, oedge);
5870 Ext->patchTopo->GetBdrElementFace(p, &faces[0], &opatch);
5872 kv[0] = Ext->KnotVec(edges[0], oedge[0], &okv[0]);
5873 kv[1] = Ext->KnotVec(edges[1], oedge[1], &okv[1]);
5877void NURBSPatchMap::SetPatchVertexMap(int p, const KnotVector *kv[])
5879 GetPatchKnotVectors(p, kv);
5881 I = kv[0]->GetNE() - 1;
5883 for (int i = 0; i < verts.Size(); i++)
5885 verts[i] = Ext->v_meshOffsets[verts[i]];
5888 if (Ext->Dimension() >= 2)
5890 J = kv[1]->GetNE() - 1;
5891 SetMasterEdges(false, kv);
5892 for (int i = 0; i < edges.Size(); i++)
5894 edges[i] = Ext->e_meshOffsets[edges[i]];
5897 if (Ext->Dimension() == 3)
5899 K = kv[2]->GetNE() - 1;
5900 SetMasterFaces(false);
5901 for (int i = 0; i < faces.Size(); i++)
5903 faces[i] = Ext->f_meshOffsets[faces[i]];
5907 pOffset = Ext->p_meshOffsets[p];
5910void NURBSPatchMap::SetPatchDofMap(int p, const KnotVector *kv[])
5912 GetPatchKnotVectors(p, kv);
5914 I = kv[0]->GetNCP() - 2;
5916 for (int i = 0; i < verts.Size(); i++)
5918 verts[i] = Ext->v_spaceOffsets[verts[i]];
5920 if (Ext->Dimension() >= 2)
5922 J = kv[1]->GetNCP() - 2;
5923 SetMasterEdges(true);
5925 if (Ext->NonconformingPatches() && Ext->patchTopo->ncmesh
5926 && Ext->patchTopo->ncmesh->GetVertexToKnotSpan().Size() > 0)
5928 for (int i = 0; i < edges.Size(); i++)
5930 // Find the patchTopo->ncmesh edge corresponding to edges[i].
5932 Ext->patchTopo->GetEdgeVertices(edges[i], vert);
5933 const std::pair<int, int> vpair(vert[0], vert[1]);
5934 const int ncedge = Ext->VertexPairToEdge(vpair);
5935 edges[i] = Ext->e_spaceOffsets[ncedge];
5940 for (int i = 0; i < edges.Size(); i++)
5942 edges[i] = Ext->e_spaceOffsets[edges[i]];
5946 if (Ext->Dimension() == 3)
5948 K = kv[2]->GetNCP() - 2;
5949 SetMasterFaces(true);
5950 for (int i = 0; i < faces.Size(); i++)
5952 faces[i] = Ext->f_spaceOffsets[faces[i]];
5956 pOffset = Ext->p_spaceOffsets[p];
5959void NURBSPatchMap::SetBdrPatchVertexMap(int p, const KnotVector *kv[],
5962 GetBdrPatchKnotVectors(p, kv, okv);
5964 for (int i = 0; i < verts.Size(); i++)
5966 verts[i] = Ext->v_meshOffsets[verts[i]];
5969 if (Ext->Dimension() == 1)
5973 else if (Ext->Dimension() == 2)
5975 I = kv[0]->GetNE() - 1;
5976 pOffset = Ext->e_meshOffsets[edges[0]];
5977 SetMasterEdges(false);
5979 else if (Ext->Dimension() == 3)
5981 I = kv[0]->GetNE() - 1;
5982 J = kv[1]->GetNE() - 1;
5984 SetMasterEdges(false);
5985 SetMasterFaces(false);
5986 for (int i = 0; i < edges.Size(); i++)
5988 edges[i] = Ext->e_meshOffsets[edges[i]];
5991 pOffset = Ext->f_meshOffsets[faces[0]];
5995void NURBSPatchMap::SetBdrPatchDofMap(int p, const KnotVector *kv[], int *okv)
5997 GetBdrPatchKnotVectors(p, kv, okv);
5999 for (int i = 0; i < verts.Size(); i++)
6001 verts[i] = Ext->v_spaceOffsets[verts[i]];
6004 if (Ext->Dimension() == 1)
6008 else if (Ext->Dimension() == 2)
6010 I = kv[0]->GetNCP() - 2;
6011 pOffset = Ext->e_spaceOffsets[edges[0]];
6013 SetMasterEdges(true);
6015 else if (Ext->Dimension() == 3)
6017 I = kv[0]->GetNCP() - 2;
6018 J = kv[1]->GetNCP() - 2;
6020 SetMasterEdges(true);
6021 for (int i = 0; i < edges.Size(); i++)
6023 edges[i] = Ext->e_spaceOffsets[edges[i]];
6026 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 PrintFunctions(std::ostream &os, int samples=11) const
Prints the non-zero shape functions and their first and second derivatives associated with the KnotVe...
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.
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.
Vector knot
Stores the values of all knots.
KnotVector()=default
Create an empty KnotVector.
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.
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 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)
void mfem_error(const char *msg)
NURBSPatch * Interpolate(NURBSPatch &p1, NURBSPatch &p2)
NURBSPatch * Revolve3D(NURBSPatch &patch, real_t n[], real_t ang, int times)