18#if defined(_MSC_VER) && (_MSC_VER < 1800)
20#define copysign _copysign
68 " Parent KnotVector order higher than child");
71 const int nOrder =
Order +
t;
74 for (
int i = 0; i <= nOrder; i++)
76 (*newkv)[i] =
knot(0);
78 for (
int i = nOrder + 1; i < newkv->
GetNCP(); i++)
80 (*newkv)[i] =
knot(i -
t);
82 for (
int i = 0; i <= nOrder; i++)
94 MFEM_VERIFY(rf > 1,
"Refinement factor must be at least 2.");
100 for (
int i = 0; i <
knot.
Size()-1; i++)
104 for (
int m = 1; m < rf; ++m)
106 newknots(j) = m * h * (
knot(i) +
knot(i+1));
135 if (cf < 2) {
return fine; }
138 MFEM_VERIFY(cne > 0 && cne * cf ==
NumOfElements,
"Invalid coarsening factor");
145 for (
int c=0; c<cne; ++c)
151 if (
knot(i) != kprev)
157 fine[fcnt] =
knot(i);
164 MFEM_VERIFY(fcnt == fine.
Size(),
"");
171 MFEM_VERIFY(rf > 1,
"Refinement factor must be at least 2.");
189 for (
int i = 0; i <
knot.
Size()-1; i++)
214 for (j=0; j<rf-1; ++j)
217 newknots(((rf - 1) * i) + j) = ((1.0 - s0) * k0) + (s0 * k1);
219 s0 +=
s[(rf*i) + j + 1];
246 for (
int i = 1; i <= ns; i++)
262 MFEM_VERIFY(
GetNE(),
"Elements not counted. Use GetElements().");
272 for (
int e = 0; e <
GetNE(); e++, cnt++)
277 for (
int j = 0; j <samples; j++)
283 for (
int d = 0; d <
Order+1; d++) { os<<
"\t"<<shape[d]; }
286 for (
int d = 0; d <
Order+1; d++) { os<<
"\t"<<shape[d]; }
289 for (
int d = 0; d <
Order+1; d++) { os<<
"\t"<<shape[d]; }
302 int ip = (i >= 0) ? (i + p) : (-1 - i + p);
303 real_t u = getKnotLocation((i >= 0) ? xi : 1. - xi, ip), saved, tmp;
304 real_t left[MaxOrder+1], right[MaxOrder+1];
307 for (int j = 1; j <= p; ++j)
309 left[j] = u - knot(ip+1-j);
310 right[j] = knot(ip+j) - u;
312 for (int r = 0; r < j; ++r)
314 tmp = shape(r)/(right[r+1] + left[j-r]);
315 shape(r) = saved + right[r+1]*tmp;
316 saved = left[j-r]*tmp;
322// Routine from "The NURBS book
" - 2nd ed - Piegl and Tiller
323// Algorithm A2.3 p. 72
324void KnotVector::CalcDShape(Vector &grad, int i, real_t xi) const
326 int p = Order, rk, pk;
327 int ip = (i >= 0) ? (i + p) : (-1 - i + p);
328 real_t u = getKnotLocation((i >= 0) ? xi : 1. - xi, ip), temp, saved, d;
329 real_t ndu[MaxOrder+1][MaxOrder+1], left[MaxOrder+1], right[MaxOrder+1];
339 for (int j = 1; j <= p; j++)
341 left[j] = u - knot(ip-j+1);
342 right[j] = knot(ip+j) - u;
344 for (int r = 0; r < j; r++)
346 ndu[j][r] = right[r+1] + left[j-r];
347 temp = ndu[r][j-1]/ndu[j][r];
348 ndu[r][j] = saved + right[r+1]*temp;
349 saved = left[j-r]*temp;
354 for (int r = 0; r <= p; ++r)
361 d = ndu[rk][pk]/ndu[p][rk];
365 d -= ndu[r][pk]/ndu[p][r];
372 grad *= p*(knot(ip+1) - knot(ip));
376 grad *= p*(knot(ip) - knot(ip+1));
380// Routine from "The NURBS book
" - 2nd ed - Piegl and Tiller
381void KnotVector::CalcDnShape(Vector &gradn, int n, int i, real_t xi) const
383 int p = Order, rk, pk, j1, j2,r,j,k;
384 int ip = (i >= 0) ? (i + p) : (-1 - i + p);
385 real_t u = getKnotLocation((i >= 0) ? xi : 1. - xi, ip);
386 real_t temp, saved, d;
387 real_t a[2][MaxOrder+1],ndu[MaxOrder+1][MaxOrder+1], left[MaxOrder+1],
398 for (j = 1; j <= p; j++)
400 left[j] = u - knot(ip-j+1);
401 right[j] = knot(ip+j)- u;
404 for (r = 0; r < j; r++)
406 ndu[j][r] = right[r+1] + left[j-r];
407 temp = ndu[r][j-1]/ndu[j][r];
408 ndu[r][j] = saved + right[r+1]*temp;
409 saved = left[j-r]*temp;
414 for (r = 0; r <= p; r++)
419 for (k = 1; k <= n; k++)
426 a[s2][0] = a[s1][0]/ndu[pk+1][rk];
427 d = a[s2][0]*ndu[rk][pk];
448 for (j = j1; j <= j2; j++)
450 a[s2][j] = (a[s1][j] - a[s1][j-1])/ndu[pk+1][rk+j];
451 d += a[s2][j]*ndu[rk+j][pk];
456 a[s2][k] = - a[s1][k-1]/ndu[pk+1][r];
457 d += a[s2][j]*ndu[rk+j][pk];
468 u = (knot(ip+1) - knot(ip));
472 u = (knot(ip) - knot(ip+1));
476 for (k = 1; k <= n-1; k++) { temp *= (p-k)*u; }
478 for (j = 0; j <= p; j++) { gradn[j] *= temp; }
482void KnotVector::FindMaxima(Array<int> &ks, Vector &xi, Vector &u) const
484 Vector shape(Order+1);
485 Vector maxima(GetNCP());
486 real_t arg1, arg2, arg, max1, max2, max;
488 xi.SetSize(GetNCP());
490 ks.SetSize(GetNCP());
491 for (int j = 0; j <GetNCP(); j++)
494 for (int d = 0; d < Order+1; d++)
500 CalcShape(shape, i, arg1);
504 CalcShape(shape, i, arg2);
507 arg = (arg1 + arg2)/2;
508 CalcShape(shape, i, arg);
511 while ( ( max > max1 ) || (max > max2) )
524 arg = (arg1 + arg2)/2;
525 CalcShape ( shape, i, arg);
534 u[j] = getKnotLocation(arg, i+Order);
541// Routine from "The NURBS book
" - 2nd ed - Piegl and Tiller
542// Algorithm A9.1 p. 369
543void KnotVector::FindInterpolant(Array<Vector*> &x)
545 int order = GetOrder();
548 // Find interpolation points
549 Vector xi_args, u_args;
551 FindMaxima(i_args,xi_args, u_args);
553 // Assemble collocation matrix
554 Vector shape(order+1);
555 DenseMatrix A(ncp,ncp);
557 for (int i = 0; i < ncp; i++)
559 CalcShape ( shape, i_args[i], xi_args[i]);
560 for (int p = 0; p < order+1; p++)
562 A(i,i_args[i] + p) = shape[p];
569 for (int i= 0; i < x.Size(); i++)
576int KnotVector::findKnotSpan(real_t u) const
580 if (u == knot(NumOfControlPoints+Order))
582 mid = NumOfControlPoints;
587 high = NumOfControlPoints + 1;
588 mid = (low + high)/2;
589 while ( (u < knot(mid-1)) || (u > knot(mid)) )
599 mid = (low + high)/2;
605void KnotVector::Difference(const KnotVector &kv, Vector &diff) const
607 if (Order != kv.GetOrder())
610 " Can not compare
knot vectors with different orders!
");
613 int s = kv.Size() - Size();
616 kv.Difference(*this, diff);
622 if (s == 0) { return; }
626 for (int j = 0; j < kv.Size(); j++)
628 if (abs(knot(i) - kv[j]) < 2 * std::numeric_limits<real_t>::epsilon())
640void NURBSPatch::init(int dim_)
647 ni = kv[0]->GetNCP();
651 data = new real_t[ni*Dim];
654 for (int i = 0; i < ni*Dim; i++)
660 else if (kv.Size() == 2)
662 ni = kv[0]->GetNCP();
663 nj = kv[1]->GetNCP();
666 data = new real_t[ni*nj*Dim];
669 for (int i = 0; i < ni*nj*Dim; i++)
675 else if (kv.Size() == 3)
677 ni = kv[0]->GetNCP();
678 nj = kv[1]->GetNCP();
679 nk = kv[2]->GetNCP();
681 data = new real_t[ni*nj*nk*Dim];
684 for (int i = 0; i < ni*nj*nk*Dim; i++)
696NURBSPatch::NURBSPatch(const NURBSPatch &orig)
697 : ni(orig.ni), nj(orig.nj), nk(orig.nk), Dim(orig.Dim),
698 data(NULL), kv(orig.kv.Size()), nd(orig.nd), ls(orig.ls), sd(orig.sd)
700 // Allocate and copy data:
701 const int data_size = Dim*ni*nj*((kv.Size() == 2) ? 1 : nk);
702 data = new real_t[data_size];
703 std::memcpy(data, orig.data, data_size*sizeof(real_t));
705 // Copy the knot vectors:
706 for (int i = 0; i < kv.Size(); i++)
708 kv[i] = new KnotVector(*orig.kv[i]);
712NURBSPatch::NURBSPatch(std::istream &input)
714 int pdim, dim, size = 1;
717 input >> ws >> ident >> pdim; // knotvectors
719 for (int i = 0; i < pdim; i++)
721 kv[i] = new KnotVector(input);
722 size *= kv[i]->GetNCP();
725 input >> ws >> ident >> dim; // dimension
728 input >> ws >> ident; // controlpoints (homogeneous coordinates)
729 if (ident == "controlpoints
" || ident == "controlpoints_homogeneous
")
731 for (int j = 0, i = 0; i < size; i++)
732 for (int d = 0; d <= dim; d++, j++)
737 else // "controlpoints_cartesian
" (Cartesian coordinates with weight)
739 for (int j = 0, i = 0; i < size; i++)
741 for (int d = 0; d <= dim; d++)
745 for (int d = 0; d < dim; d++)
747 data[j+d] *= data[j+dim];
754NURBSPatch::NURBSPatch(const KnotVector *kv0, const KnotVector *kv1, int dim_)
757 kv[0] = new KnotVector(*kv0);
758 kv[1] = new KnotVector(*kv1);
762NURBSPatch::NURBSPatch(const KnotVector *kv0, const KnotVector *kv1,
763 const KnotVector *kv2, int dim_)
766 kv[0] = new KnotVector(*kv0);
767 kv[1] = new KnotVector(*kv1);
768 kv[2] = new KnotVector(*kv2);
772NURBSPatch::NURBSPatch(Array<const KnotVector *> &kv_, int dim_)
774 kv.SetSize(kv_.Size());
775 for (int i = 0; i < kv.Size(); i++)
777 kv[i] = new KnotVector(*kv_[i]);
782NURBSPatch::NURBSPatch(NURBSPatch *parent, int dir, int Order, int NCP)
784 kv.SetSize(parent->kv.Size());
785 for (int i = 0; i < kv.Size(); i++)
788 kv[i] = new KnotVector(*parent->kv[i]);
792 kv[i] = new KnotVector(Order, NCP);
797void NURBSPatch::swap(NURBSPatch *np)
804 for (int i = 0; i < kv.Size(); i++)
806 if (kv[i]) { delete kv[i]; }
823NURBSPatch::~NURBSPatch()
830 for (int i = 0; i < kv.Size(); i++)
832 if (kv[i]) { delete kv[i]; }
836void NURBSPatch::Print(std::ostream &os) const
840 os << "knotvectors\n
" << kv.Size() << '\n';
841 for (int i = 0; i < kv.Size(); i++)
844 size *= kv[i]->GetNCP();
847 os << "\ndimension\n
" << Dim - 1
848 << "\n\ncontrolpoints\n
";
849 for (int j = 0, i = 0; i < size; i++)
852 for (int d = 1; d < Dim; d++)
854 os << ' ' << data[j++];
860int NURBSPatch::SetLoopDirection(int dir)
873 mfem::err << "NURBSPatch::SetLoopDirection :\n
"
874 " Direction error in 1D patch, dir =
" << dir << '\n';
896 mfem::err << "NURBSPatch::SetLoopDirection :\n
"
897 " Direction error in 2D patch, dir =
" << dir << '\n';
926 mfem::err << "NURBSPatch::SetLoopDirection :\n
"
927 " Direction error in 3D patch, dir =
" << dir << '\n';
935void NURBSPatch::UniformRefinement(Array<int> const& rf)
938 for (int dir = 0; dir < kv.Size(); dir++)
942 kv[dir]->Refinement(newknots, rf[dir]);
943 KnotInsert(dir, newknots);
948void NURBSPatch::UniformRefinement(int rf)
950 Array<int> rf_array(kv.Size());
952 UniformRefinement(rf_array);
955void NURBSPatch::Coarsen(Array<int> const& cf, real_t tol)
957 for (int dir = 0; dir < kv.Size(); dir++)
959 if (!kv[dir]->coarse)
961 const int ne_fine = kv[dir]->GetNE();
962 KnotRemove(dir, kv[dir]->GetFineKnots(cf[dir]), tol);
963 kv[dir]->coarse = true;
964 kv[dir]->GetElements();
966 const int ne_coarse = kv[dir]->GetNE();
967 MFEM_VERIFY(ne_fine == cf[dir] * ne_coarse, "");
968 if (kv[dir]->spacing)
970 kv[dir]->spacing->SetSize(ne_coarse);
971 kv[dir]->spacing->ScaleParameters((real_t) cf[dir]);
977void NURBSPatch::Coarsen(int cf, real_t tol)
979 Array<int> cf_array(kv.Size());
981 Coarsen(cf_array, tol);
984void NURBSPatch::GetCoarseningFactors(Array<int> & f) const
986 f.SetSize(kv.Size());
987 for (int dir = 0; dir < kv.Size(); dir++)
989 f[dir] = kv[dir]->GetCoarseningFactor();
993void NURBSPatch::KnotInsert(Array<KnotVector *> &newkv)
995 for (int dir = 0; dir < kv.Size(); dir++)
997 KnotInsert(dir, *newkv[dir]);
1001void NURBSPatch::KnotInsert(int dir, const KnotVector &newkv)
1003 if (dir >= kv.Size() || dir < 0)
1008 int t = newkv.GetOrder() - kv[dir]->GetOrder();
1012 DegreeElevate(dir, t);
1016 mfem_error("NURBSPatch::KnotInsert : Incorrect order!
");
1020 GetKV(dir)->Difference(newkv, diff);
1021 if (diff.Size() > 0)
1023 KnotInsert(dir, diff);
1027void NURBSPatch::KnotInsert(Array<Vector *> &newkv)
1029 for (int dir = 0; dir < kv.Size(); dir++)
1031 KnotInsert(dir, *newkv[dir]);
1035void NURBSPatch::KnotRemove(Array<Vector *> &rmkv, real_t tol)
1037 for (int dir = 0; dir < kv.Size(); dir++)
1039 KnotRemove(dir, *rmkv[dir], tol);
1043void NURBSPatch::KnotRemove(int dir, const Vector &knot, real_t tol)
1045 // TODO: implement an efficient version of this!
1048 KnotRemove(dir, k, 1, tol);
1052// Algorithm A5.5 from "The NURBS Book
", 2nd ed, Piegl and Tiller, chapter 5.
1053void NURBSPatch::KnotInsert(int dir, const Vector &knot)
1055 if (knot.Size() == 0 ) { return; }
1057 if (dir >= kv.Size() || dir < 0)
1062 NURBSPatch &oldp = *this;
1063 KnotVector &oldkv = *kv[dir];
1065 NURBSPatch *newpatch = new NURBSPatch(this, dir, oldkv.GetOrder(),
1066 oldkv.GetNCP() + knot.Size());
1067 NURBSPatch &newp = *newpatch;
1068 KnotVector &newkv = *newp.GetKV(dir);
1070 newkv.spacing = oldkv.spacing;
1072 int size = oldp.SetLoopDirection(dir);
1073 if (size != newp.SetLoopDirection(dir))
1078 int rr = knot.Size() - 1;
1079 int a = oldkv.findKnotSpan(knot(0)) - 1;
1080 int b = oldkv.findKnotSpan(knot(rr)) - 1;
1081 int pl = oldkv.GetOrder();
1082 int ml = oldkv.GetNCP();
1084 for (int j = 0; j <= a; j++)
1086 newkv[j] = oldkv[j];
1088 for (int j = b+pl; j <= ml+pl; j++)
1090 newkv[j+rr+1] = oldkv[j];
1092 for (int k = 0; k <= (a-pl); k++)
1094 for (int ll = 0; ll < size; ll++)
1096 newp.slice(k,ll) = oldp.slice(k,ll);
1099 for (int k = (b-1); k < ml; k++)
1101 for (int ll = 0; ll < size; ll++)
1103 newp.slice(k+rr+1,ll) = oldp.slice(k,ll);
1110 for (int j = rr; j >= 0; j--)
1112 while ( (knot(j) <= oldkv[i]) && (i > a) )
1114 newkv[k] = oldkv[i];
1115 for (int ll = 0; ll < size; ll++)
1117 newp.slice(k-pl-1,ll) = oldp.slice(i-pl-1,ll);
1124 for (int ll = 0; ll < size; ll++)
1126 newp.slice(k-pl-1,ll) = newp.slice(k-pl,ll);
1129 for (int l = 1; l <= pl; l++)
1132 real_t alfa = newkv[k+l] - knot(j);
1133 if (fabs(alfa) == 0.0)
1135 for (int ll = 0; ll < size; ll++)
1137 newp.slice(ind-1,ll) = newp.slice(ind,ll);
1142 alfa = alfa/(newkv[k+l] - oldkv[i-pl+l]);
1143 for (int ll = 0; ll < size; ll++)
1145 newp.slice(ind-1,ll) = alfa*newp.slice(ind-1,ll) +
1146 (1.0-alfa)*newp.slice(ind, ll);
1155 newkv.GetElements();
1160// Algorithm A5.8 from "The NURBS Book
", 2nd ed, Piegl and Tiller, chapter 5.
1161int NURBSPatch::KnotRemove(int dir, real_t knot, int ntimes, real_t tol)
1163 if (dir >= kv.Size() || dir < 0)
1168 NURBSPatch &oldp = *this;
1169 KnotVector &oldkv = *kv[dir];
1171 // Find the index of the last occurrence of the knot.
1173 int multiplicity = 0;
1174 for (int i=0; i<oldkv.Size(); ++i)
1176 if (oldkv[i] == knot)
1183 MFEM_VERIFY(0 < id && id < oldkv.Size() - 1 && ntimes <= multiplicity,
1184 "Only interior knots of sufficient multiplicity may be removed.
");
1186 const int p = oldkv.GetOrder();
1188 NURBSPatch tmpp(this, dir, p, oldkv.GetNCP());
1190 const int size = oldp.SetLoopDirection(dir);
1191 if (size != tmpp.SetLoopDirection(dir))
1197 for (int k = 0; k < oldp.nd; ++k)
1199 for (int ll = 0; ll < size; ll++)
1201 tmpp.slice(k,ll) = oldp.slice(k,ll);
1206 const int s = multiplicity;
1214 Array2D<real_t> temp(last + ntimes + 1, size);
1216 for (int t=0; t<ntimes; ++t)
1218 int off = first - 1; // Difference in index between temp and P.
1220 for (int ll = 0; ll < size; ll++)
1222 temp(0, ll) = oldp.slice(off, ll);
1223 temp(last + 1 - off, ll) = oldp.slice(last + 1, ll);
1227 int jj = last - off;
1231 // Compute new control points for one removal step
1232 const real_t a_i = (knot - oldkv[i]) / (oldkv[i+p+1] - oldkv[i]);
1233 const real_t a_j = (knot - oldkv[j]) / (oldkv[j+p+1] - oldkv[j]);
1235 for (int ll = 0; ll < size; ll++)
1237 temp(ii,ll) = (1.0 / a_i) * oldp.slice(i,ll) -
1238 ((1.0/a_i) - 1.0) * temp(ii - 1, ll);
1240 temp(jj,ll) = (1.0 / (1.0 - a_j)) * (oldp.slice(j,ll) -
1241 (a_j * temp(jj + 1, ll)));
1248 // Check whether knot is removable
1252 for (int ll = 0; ll < size; ll++)
1254 diff[ll] = temp(ii-1, ll) - temp(jj+1, ll);
1259 const real_t a_i = (knot - oldkv[i]) / (oldkv[i+p+1] - oldkv[i]);
1260 for (int ll = 0; ll < size; ll++)
1261 diff[ll] = oldp.slice(i,ll) - (a_i * temp(ii+1, ll))
1262 - ((1.0 - a_i) * temp(ii-1, ll));
1265 const real_t dist = diff.Norml2();
1268 // Removal failed. Return the number of successful removals.
1269 mfem::out << "Knot removal failed after
" << t
1270 << " successful removals
" << endl;
1274 // Note that the new weights may not be positive.
1276 // Save new control points
1282 for (int ll = 0; ll < size; ll++)
1284 tmpp.slice(i,ll) = temp(i - off,ll);
1285 tmpp.slice(j,ll) = temp(j - off,ll);
1293 } // End of loop (t) over ntimes.
1295 const int fout = ((2*r) - s - p) / 2; // First control point out
1299 for (int k=1; k<ntimes; ++k)
1311 NURBSPatch *newpatch = new NURBSPatch(this, dir, p,
1312 oldkv.GetNCP() - ntimes);
1313 NURBSPatch &newp = *newpatch;
1314 if (size != newp.SetLoopDirection(dir))
1319 for (int k = 0; k < fout; ++k)
1321 for (int ll = 0; ll < size; ll++)
1323 newp.slice(k,ll) = oldp.slice(k,ll); // Copy old data
1327 for (int k = i+1; k < oldp.nd; ++k)
1329 for (int ll = 0; ll < size; ll++)
1331 newp.slice(j,ll) = tmpp.slice(k,ll); // Shift
1337 KnotVector &newkv = *newp.GetKV(dir);
1338 MFEM_VERIFY(newkv.Size() == oldkv.Size() - ntimes, "");
1340 newkv.spacing = oldkv.spacing;
1341 newkv.coarse = oldkv.coarse;
1343 for (int k = 0; k < id - ntimes + 1; k++)
1345 newkv[k] = oldkv[k];
1347 for (int k = id + 1; k < oldkv.Size(); k++)
1349 newkv[k - ntimes] = oldkv[k];
1352 newkv.GetElements();
1359void NURBSPatch::DegreeElevate(int t)
1361 for (int dir = 0; dir < kv.Size(); dir++)
1363 DegreeElevate(dir, t);
1367// Routine from "The NURBS book
" - 2nd ed - Piegl and Tiller
1368void NURBSPatch::DegreeElevate(int dir, int t)
1370 if (dir >= kv.Size() || dir < 0)
1375 int i, j, k, kj, mpi, mul, mh, kind, cind, first, last;
1376 int r, a, b, oldr, save, s, tr, lbz, rbz, l;
1377 real_t inv, ua, ub, numer, alf, den, bet, gam;
1379 NURBSPatch &oldp = *this;
1380 KnotVector &oldkv = *kv[dir];
1381 oldkv.GetElements();
1383 NURBSPatch *newpatch = new NURBSPatch(this, dir, oldkv.GetOrder() + t,
1384 oldkv.GetNCP() + oldkv.GetNE()*t);
1385 NURBSPatch &newp = *newpatch;
1386 KnotVector &newkv = *newp.GetKV(dir);
1388 if (oldkv.spacing) { newkv.spacing = oldkv.spacing; }
1390 int size = oldp.SetLoopDirection(dir);
1391 if (size != newp.SetLoopDirection(dir))
1396 int p = oldkv.GetOrder();
1397 int n = oldkv.GetNCP()-1;
1399 DenseMatrix bezalfs (p+t+1, p+1);
1400 DenseMatrix bpts (p+1, size);
1401 DenseMatrix ebpts (p+t+1, size);
1402 DenseMatrix nextbpts(p-1, size);
1403 Vector alphas (p-1);
1410 Array2D<int> binom(ph+1, ph+1);
1411 for (i = 0; i <= ph; i++)
1413 binom(i,0) = binom(i,i) = 1;
1414 for (j = 1; j < i; j++)
1416 binom(i,j) = binom(i-1,j) + binom(i-1,j-1);
1421 bezalfs(ph,p) = 1.0;
1423 for (i = 1; i <= ph2; i++)
1425 inv = 1.0/binom(ph,i);
1427 for (j = max(0,i-t); j <= mpi; j++)
1429 bezalfs(i,j) = inv*binom(p,j)*binom(t,i-j);
1434 for (i = ph2+1; i < ph; i++)
1437 for (j = max(0,i-t); j <= mpi; j++)
1439 bezalfs(i,j) = bezalfs(ph-i,p-j);
1450 for (l = 0; l < size; l++)
1452 newp.slice(0,l) = oldp.slice(0,l);
1454 for (i = 0; i <= ph; i++)
1459 for (i = 0; i <= p; i++)
1461 for (l = 0; l < size; l++)
1463 bpts(i,l) = oldp.slice(i,l);
1470 while (b < m && oldkv[b] == oldkv[b+1]) { b++; }
1478 if (oldr > 0) { lbz = (oldr+2)/2; }
1481 if (r > 0) { rbz = ph-(r+1)/2; }
1487 for (k = p ; k > mul; k--)
1489 alphas[k-mul-1] = numer/(oldkv[a+k]-ua);
1492 for (j = 1; j <= r; j++)
1496 for (k = p; k >= s; k--)
1498 for (l = 0; l < size; l++)
1499 bpts(k,l) = (alphas[k-s]*bpts(k,l) +
1500 (1.0-alphas[k-s])*bpts(k-1,l));
1502 for (l = 0; l < size; l++)
1504 nextbpts(save,l) = bpts(p,l);
1509 for (i = lbz; i <= ph; i++)
1511 for (l = 0; l < size; l++)
1516 for (j = max(0,i-t); j <= mpi; j++)
1518 for (l = 0; l < size; l++)
1520 ebpts(i,l) += bezalfs(i,j)*bpts(j,l);
1530 bet = (ub-newkv[kind-1])/den;
1532 for (tr = 1; tr < oldr; tr++)
1541 alf = (ub-newkv[i])/(ua-newkv[i]);
1542 for (l = 0; l < size; l++)
1544 newp.slice(i,l) = alf*newp.slice(i,l)-(1.0-alf)*newp.slice(i-1,l);
1549 if ((j-tr) <= (kind-ph+oldr))
1551 gam = (ub-newkv[j-tr])/den;
1552 for (l = 0; l < size; l++)
1554 ebpts(kj,l) = gam*ebpts(kj,l) + (1.0-gam)*ebpts(kj+1,l);
1559 for (l = 0; l < size; l++)
1561 ebpts(kj,l) = bet*ebpts(kj,l) + (1.0-bet)*ebpts(kj+1,l);
1576 for (i = 0; i < (ph-oldr); i++)
1582 for (j = lbz; j <= rbz; j++)
1584 for (l = 0; l < size; l++)
1586 newp.slice(cind,l) = ebpts(j,l);
1593 for (j = 0; j <r; j++)
1594 for (l = 0; l < size; l++)
1596 bpts(j,l) = nextbpts(j,l);
1599 for (j = r; j <= p; j++)
1600 for (l = 0; l < size; l++)
1602 bpts(j,l) = oldp.slice(b-p+j,l);
1611 for (i = 0; i <= ph; i++)
1617 newkv.GetElements();
1622void NURBSPatch::FlipDirection(int dir)
1624 int size = SetLoopDirection(dir);
1626 for (int id = 0; id < nd/2; id++)
1627 for (int i = 0; i < size; i++)
1629 Swap<real_t>((*this).slice(id,i), (*this).slice(nd-1-id,i));
1634void NURBSPatch::SwapDirections(int dir1, int dir2)
1636 if (abs(dir1-dir2) == 2)
1639 " directions 0 and 2 are not supported!
");
1642 Array<const KnotVector *> nkv(kv);
1644 Swap<const KnotVector *>(nkv[dir1], nkv[dir2]);
1645 NURBSPatch *newpatch = new NURBSPatch(nkv, Dim);
1647 int size = SetLoopDirection(dir1);
1648 newpatch->SetLoopDirection(dir2);
1650 for (int id = 0; id < nd; id++)
1651 for (int i = 0; i < size; i++)
1653 (*newpatch).slice(id,i) = (*this).slice(id,i);
1659void NURBSPatch::Rotate(real_t angle, real_t n[])
1669 mfem_error("NURBSPatch::Rotate : Specify an angle for
a 3D rotation.
");
1676void NURBSPatch::Get2DRotationMatrix(real_t angle, DenseMatrix &T)
1678 real_t s = sin(angle);
1679 real_t c = cos(angle);
1688void NURBSPatch::Rotate2D(real_t angle)
1696 Vector x(2), y(NULL, 2);
1698 Get2DRotationMatrix(angle, T);
1701 for (int i = 0; i < kv.Size(); i++)
1703 size *= kv[i]->GetNCP();
1706 for (int i = 0; i < size; i++)
1708 y.SetData(data + i*Dim);
1714void NURBSPatch::Get3DRotationMatrix(real_t n[], real_t angle, real_t r,
1718 real_t l2 = n[0]*n[0] + n[1]*n[1] + n[2]*n[2];
1719 real_t l = sqrt(l2);
1721 if (fabs(angle) == (real_t)(M_PI_2))
1723 s = r*copysign(1., angle);
1727 else if (fabs(angle) == (real_t)(M_PI))
1742 T(0,0) = (n[0]*n[0] + (n[1]*n[1] + n[2]*n[2])*c)/l2;
1743 T(0,1) = -(n[0]*n[1]*c1)/l2 - (n[2]*s)/l;
1744 T(0,2) = -(n[0]*n[2]*c1)/l2 + (n[1]*s)/l;
1745 T(1,0) = -(n[0]*n[1]*c1)/l2 + (n[2]*s)/l;
1746 T(1,1) = (n[1]*n[1] + (n[0]*n[0] + n[2]*n[2])*c)/l2;
1747 T(1,2) = -(n[1]*n[2]*c1)/l2 - (n[0]*s)/l;
1748 T(2,0) = -(n[0]*n[2]*c1)/l2 - (n[1]*s)/l;
1749 T(2,1) = -(n[1]*n[2]*c1)/l2 + (n[0]*s)/l;
1750 T(2,2) = (n[2]*n[2] + (n[0]*n[0] + n[1]*n[1])*c)/l2;
1753void NURBSPatch::Rotate3D(real_t n[], real_t angle)
1761 Vector x(3), y(NULL, 3);
1763 Get3DRotationMatrix(n, angle, 1., T);
1766 for (int i = 0; i < kv.Size(); i++)
1768 size *= kv[i]->GetNCP();
1771 for (int i = 0; i < size; i++)
1773 y.SetData(data + i*Dim);
1779int NURBSPatch::MakeUniformDegree(int degree)
1785 for (int dir = 0; dir < kv.Size(); dir++)
1787 maxd = std::max(maxd, kv[dir]->GetOrder());
1791 for (int dir = 0; dir < kv.Size(); dir++)
1793 if (maxd > kv[dir]->GetOrder())
1795 DegreeElevate(dir, maxd - kv[dir]->GetOrder());
1802NURBSPatch *Interpolate(NURBSPatch &p1, NURBSPatch &p2)
1804 if (p1.kv.Size() != p2.kv.Size() || p1.Dim != p2.Dim)
1809 int size = 1, dim = p1.Dim;
1810 Array<const KnotVector *> kv(p1.kv.Size() + 1);
1812 for (int i = 0; i < p1.kv.Size(); i++)
1814 if (p1.kv[i]->GetOrder() < p2.kv[i]->GetOrder())
1816 p1.KnotInsert(i, *p2.kv[i]);
1817 p2.KnotInsert(i, *p1.kv[i]);
1821 p2.KnotInsert(i, *p1.kv[i]);
1822 p1.KnotInsert(i, *p2.kv[i]);
1825 size *= kv[i]->GetNCP();
1828 KnotVector &nkv = *(new KnotVector(1, 2));
1829 nkv[0] = nkv[1] = 0.0;
1830 nkv[2] = nkv[3] = 1.0;
1834 NURBSPatch *patch = new NURBSPatch(kv, dim);
1837 for (int i = 0; i < size; i++)
1839 for (int d = 0; d < dim; d++)
1841 patch->data[i*dim+d] = p1.data[i*dim+d];
1842 patch->data[(i+size)*dim+d] = p2.data[i*dim+d];
1849NURBSPatch *Revolve3D(NURBSPatch &patch, real_t n[], real_t ang, int times)
1857 Array<const KnotVector *> nkv(patch.kv.Size() + 1);
1859 for (int i = 0; i < patch.kv.Size(); i++)
1861 nkv[i] = patch.kv[i];
1862 size *= nkv[i]->GetNCP();
1865 KnotVector &lkv = *(new KnotVector(2, ns));
1867 lkv[0] = lkv[1] = lkv[2] = 0.0;
1868 for (int i = 1; i < times; i++)
1870 lkv[2*i+1] = lkv[2*i+2] = i;
1872 lkv[ns] = lkv[ns+1] = lkv[ns+2] = times;
1874 NURBSPatch *newpatch = new NURBSPatch(nkv, 4);
1877 DenseMatrix T(3), T2(3);
1878 Vector u(NULL, 3), v(NULL, 3);
1880 NURBSPatch::Get3DRotationMatrix(n, ang, 1., T);
1881 real_t c = cos(ang/2);
1882 NURBSPatch::Get3DRotationMatrix(n, ang/2, 1./c, T2);
1885 real_t *op = patch.data, *np;
1886 for (int i = 0; i < size; i++)
1888 np = newpatch->data + 4*i;
1889 for (int j = 0; j < 4; j++)
1893 for (int j = 0; j < times; j++)
1896 v.SetData(np += 4*size);
1899 v.SetData(np += 4*size);
1909void NURBSPatch::SetKnotVectorsCoarse(bool c)
1911 for (int i=0; i<kv.Size(); ++i)
1917NURBSExtension::NURBSExtension(const NURBSExtension &orig)
1918 : mOrder(orig.mOrder), mOrders(orig.mOrders),
1919 NumOfKnotVectors(orig.NumOfKnotVectors),
1920 NumOfVertices(orig.NumOfVertices),
1921 NumOfElements(orig.NumOfElements),
1922 NumOfBdrElements(orig.NumOfBdrElements),
1923 NumOfDofs(orig.NumOfDofs),
1924 NumOfActiveVertices(orig.NumOfActiveVertices),
1925 NumOfActiveElems(orig.NumOfActiveElems),
1926 NumOfActiveBdrElems(orig.NumOfActiveBdrElems),
1927 NumOfActiveDofs(orig.NumOfActiveDofs),
1928 activeVert(orig.activeVert),
1929 activeElem(orig.activeElem),
1930 activeBdrElem(orig.activeBdrElem),
1931 activeDof(orig.activeDof),
1932 patchTopo(new Mesh(*orig.patchTopo)),
1934 edge_to_knot(orig.edge_to_knot),
1935 knotVectors(orig.knotVectors.Size()), // knotVectors are copied in the body
1936 knotVectorsCompr(orig.knotVectorsCompr.Size()),
1937 weights(orig.weights),
1938 d_to_d(orig.d_to_d),
1939 master(orig.master),
1941 v_meshOffsets(orig.v_meshOffsets),
1942 e_meshOffsets(orig.e_meshOffsets),
1943 f_meshOffsets(orig.f_meshOffsets),
1944 p_meshOffsets(orig.p_meshOffsets),
1945 v_spaceOffsets(orig.v_spaceOffsets),
1946 e_spaceOffsets(orig.e_spaceOffsets),
1947 f_spaceOffsets(orig.f_spaceOffsets),
1948 p_spaceOffsets(orig.p_spaceOffsets),
1949 el_dof(orig.el_dof ? new Table(*orig.el_dof) : NULL),
1950 bel_dof(orig.bel_dof ? new Table(*orig.bel_dof) : NULL),
1951 el_to_patch(orig.el_to_patch),
1952 bel_to_patch(orig.bel_to_patch),
1953 el_to_IJK(orig.el_to_IJK),
1954 bel_to_IJK(orig.bel_to_IJK),
1955 patches(orig.patches.Size()) // patches are copied in the body
1957 // Copy the knot vectors:
1958 for (int i = 0; i < knotVectors.Size(); i++)
1960 knotVectors[i] = new KnotVector(*orig.knotVectors[i]);
1962 CreateComprehensiveKV();
1964 // Copy the patches:
1965 for (int p = 0; p < patches.Size(); p++)
1967 patches[p] = new NURBSPatch(*orig.patches[p]);
1971NURBSExtension::NURBSExtension(std::istream &input, bool spacing)
1974 patchTopo = new Mesh;
1975 patchTopo->LoadPatchTopo(input, edge_to_knot);
1979 // CheckBdrPatches();
1981 skip_comment_lines(input, '#');
1983 // Read knotvectors or patches
1985 input >> ws >> ident; // 'knotvectors' or 'patches'
1986 if (ident == "knotvectors
")
1988 input >> NumOfKnotVectors;
1989 knotVectors.SetSize(NumOfKnotVectors);
1990 for (int i = 0; i < NumOfKnotVectors; i++)
1992 knotVectors[i] = new KnotVector(input);
1995 if (spacing) // Read spacing formulas for knotvectors
1997 input >> ws >> ident; // 'spacing'
1998 MFEM_VERIFY(ident == "spacing",
1999 "Spacing formula section missing from NURBS mesh file
");
2001 input >> numSpacing;
2002 for (int j = 0; j < numSpacing; j++)
2004 int ki, spacingType, numIntParam, numDoubleParam;
2005 input >> ki >> spacingType >> numIntParam >> numDoubleParam;
2007 MFEM_VERIFY(0 <= ki && ki < NumOfKnotVectors,
2008 "Invalid knotvector
index");
2009 MFEM_VERIFY(numIntParam >= 0 && numDoubleParam >= 0,
2010 "Invalid number of parameters in
KnotVector");
2012 Array<int> ipar(numIntParam);
2013 Vector dpar(numDoubleParam);
2015 for (int i=0; i<numIntParam; ++i)
2020 for (int i=0; i<numDoubleParam; ++i)
2025 const SpacingType s = (SpacingType) spacingType;
2026 knotVectors[ki]->spacing = GetSpacingFunction(s, ipar, dpar);
2030 else if (ident == "patches
")
2032 patches.SetSize(GetNP());
2033 for (int p = 0; p < patches.Size(); p++)
2035 skip_comment_lines(input, '#');
2036 patches[p] = new NURBSPatch(input);
2039 NumOfKnotVectors = 0;
2040 for (int i = 0; i < patchTopo->GetNEdges(); i++)
2041 if (NumOfKnotVectors < KnotInd(i))
2043 NumOfKnotVectors = KnotInd(i);
2046 knotVectors.SetSize(NumOfKnotVectors);
2049 Array<int> edges, oedge;
2050 for (int p = 0; p < patches.Size(); p++)
2052 if (Dimension() == 1)
2054 if (knotVectors[KnotInd(p)] == NULL)
2056 knotVectors[KnotInd(p)] =
2057 new KnotVector(*patches[p]->GetKV(0));
2060 if (Dimension() == 2)
2062 patchTopo->GetElementEdges(p, edges, oedge);
2063 if (knotVectors[KnotInd(edges[0])] == NULL)
2065 knotVectors[KnotInd(edges[0])] =
2066 new KnotVector(*patches[p]->GetKV(0));
2068 if (knotVectors[KnotInd(edges[1])] == NULL)
2070 knotVectors[KnotInd(edges[1])] =
2071 new KnotVector(*patches[p]->GetKV(1));
2074 else if (Dimension() == 3)
2076 patchTopo->GetElementEdges(p, edges, oedge);
2077 if (knotVectors[KnotInd(edges[0])] == NULL)
2079 knotVectors[KnotInd(edges[0])] =
2080 new KnotVector(*patches[p]->GetKV(0));
2082 if (knotVectors[KnotInd(edges[3])] == NULL)
2084 knotVectors[KnotInd(edges[3])] =
2085 new KnotVector(*patches[p]->GetKV(1));
2087 if (knotVectors[KnotInd(edges[8])] == NULL)
2089 knotVectors[KnotInd(edges[8])] =
2090 new KnotVector(*patches[p]->GetKV(2));
2097 MFEM_ABORT("invalid section:
" << ident);
2100 CreateComprehensiveKV();
2102 SetOrdersFromKnotVectors();
2107 // NumOfVertices, NumOfElements, NumOfBdrElements, NumOfDofs
2109 skip_comment_lines(input, '#');
2111 // Check for a list of mesh elements
2112 if (patches.Size() == 0)
2114 input >> ws >> ident;
2116 if (patches.Size() == 0 && ident == "mesh_elements
")
2118 input >> NumOfActiveElems;
2119 activeElem.SetSize(GetGNE());
2122 for (int i = 0; i < NumOfActiveElems; i++)
2125 activeElem[glob_elem] = true;
2128 skip_comment_lines(input, '#');
2129 input >> ws >> ident;
2133 NumOfActiveElems = NumOfElements;
2134 activeElem.SetSize(NumOfElements);
2138 GenerateActiveVertices();
2140 GenerateElementDofTable();
2141 GenerateActiveBdrElems();
2142 GenerateBdrElementDofTable();
2145 if (ident == "periodic
")
2150 skip_comment_lines(input, '#');
2151 input >> ws >> ident;
2154 if (patches.Size() == 0)
2157 if (ident == "weights
")
2159 weights.Load(input, GetNDof());
2161 else // e.g. ident = "unitweights
" or "autoweights
"
2163 weights.SetSize(GetNDof());
2169 ConnectBoundaries();
2172NURBSExtension::NURBSExtension(NURBSExtension *parent, int newOrder)
2174 patchTopo = parent->patchTopo;
2177 parent->edge_to_knot.Copy(edge_to_knot);
2179 NumOfKnotVectors = parent->GetNKV();
2180 knotVectors.SetSize(NumOfKnotVectors);
2181 knotVectorsCompr.SetSize(parent->GetNP()*parent->Dimension());
2182 const Array<int> &pOrders = parent->GetOrders();
2183 for (int i = 0; i < NumOfKnotVectors; i++)
2185 if (newOrder > pOrders[i])
2188 parent->GetKnotVector(i)->DegreeElevate(newOrder - pOrders[i]);
2192 knotVectors[i] = new KnotVector(*parent->GetKnotVector(i));
2195 CreateComprehensiveKV();
2197 // copy some data from parent
2198 NumOfElements = parent->NumOfElements;
2199 NumOfBdrElements = parent->NumOfBdrElements;
2201 SetOrdersFromKnotVectors();
2203 GenerateOffsets(); // dof offsets will be different from parent
2205 NumOfActiveVertices = parent->NumOfActiveVertices;
2206 NumOfActiveElems = parent->NumOfActiveElems;
2207 NumOfActiveBdrElems = parent->NumOfActiveBdrElems;
2208 parent->activeVert.Copy(activeVert);
2210 parent->activeElem.Copy(activeElem);
2211 parent->activeBdrElem.Copy(activeBdrElem);
2213 GenerateElementDofTable();
2214 GenerateBdrElementDofTable();
2216 weights.SetSize(GetNDof());
2220 parent->master.Copy(master);
2221 parent->slave.Copy(slave);
2222 ConnectBoundaries();
2225NURBSExtension::NURBSExtension(NURBSExtension *parent,
2226 const Array<int> &newOrders)
2228 newOrders.Copy(mOrders);
2229 SetOrderFromOrders();
2231 patchTopo = parent->patchTopo;
2234 parent->edge_to_knot.Copy(edge_to_knot);
2236 NumOfKnotVectors = parent->GetNKV();
2237 MFEM_VERIFY(mOrders.Size() == NumOfKnotVectors, "invalid newOrders array
");
2238 knotVectors.SetSize(NumOfKnotVectors);
2239 const Array<int> &pOrders = parent->GetOrders();
2241 for (int i = 0; i < NumOfKnotVectors; i++)
2243 if (mOrders[i] > pOrders[i])
2246 parent->GetKnotVector(i)->DegreeElevate(mOrders[i] - pOrders[i]);
2250 knotVectors[i] = new KnotVector(*parent->GetKnotVector(i));
2253 CreateComprehensiveKV();
2255 // copy some data from parent
2256 NumOfElements = parent->NumOfElements;
2257 NumOfBdrElements = parent->NumOfBdrElements;
2259 GenerateOffsets(); // dof offsets will be different from parent
2261 NumOfActiveVertices = parent->NumOfActiveVertices;
2262 NumOfActiveElems = parent->NumOfActiveElems;
2263 NumOfActiveBdrElems = parent->NumOfActiveBdrElems;
2264 parent->activeVert.Copy(activeVert);
2266 parent->activeElem.Copy(activeElem);
2267 parent->activeBdrElem.Copy(activeBdrElem);
2269 GenerateElementDofTable();
2270 GenerateBdrElementDofTable();
2272 weights.SetSize(GetNDof());
2275 parent->master.Copy(master);
2276 parent->slave.Copy(slave);
2277 ConnectBoundaries();
2280NURBSExtension::NURBSExtension(Mesh *mesh_array[], int num_pieces)
2282 NURBSExtension *parent = mesh_array[0]->NURBSext;
2284 if (!parent->own_topo)
2287 " parent does not own the patch topology!
");
2289 patchTopo = parent->patchTopo;
2291 parent->own_topo = 0;
2293 parent->edge_to_knot.Copy(edge_to_knot);
2295 parent->GetOrders().Copy(mOrders);
2296 mOrder = parent->GetOrder();
2298 NumOfKnotVectors = parent->GetNKV();
2299 knotVectors.SetSize(NumOfKnotVectors);
2300 for (int i = 0; i < NumOfKnotVectors; i++)
2302 knotVectors[i] = new KnotVector(*parent->GetKnotVector(i));
2304 CreateComprehensiveKV();
2310 // assuming the meshes define a partitioning of all the elements
2311 NumOfActiveElems = NumOfElements;
2312 activeElem.SetSize(NumOfElements);
2315 GenerateActiveVertices();
2317 GenerateElementDofTable();
2318 GenerateActiveBdrElems();
2319 GenerateBdrElementDofTable();
2321 weights.SetSize(GetNDof());
2322 MergeWeights(mesh_array, num_pieces);
2325NURBSExtension::~NURBSExtension()
2327 if (patches.Size() == 0)
2333 for (int i = 0; i < knotVectors.Size(); i++)
2335 delete knotVectors[i];
2338 for (int i = 0; i < knotVectorsCompr.Size(); i++)
2340 delete knotVectorsCompr[i];
2343 for (int i = 0; i < patches.Size(); i++)
2354void NURBSExtension::Print(std::ostream &os, const std::string &comments) const
2356 Array<int> kvSpacing;
2357 if (patches.Size() == 0)
2359 for (int i = 0; i < NumOfKnotVectors; i++)
2361 if (knotVectors[i]->spacing) { kvSpacing.Append(i); }
2365 const int version = kvSpacing.Size() > 0 ? 11 : 10; // v1.0 or v1.1
2366 patchTopo->PrintTopo(os, edge_to_knot, version, comments);
2367 if (patches.Size() == 0)
2369 os << "\nknotvectors\n
" << NumOfKnotVectors << '\n';
2370 for (int i = 0; i < NumOfKnotVectors; i++)
2372 knotVectors[i]->Print(os);
2375 if (kvSpacing.Size() > 0)
2377 os << "\nspacing\n
" << kvSpacing.Size() << '\n';
2378 for (auto kv : kvSpacing)
2381 knotVectors[kv]->spacing->Print(os);
2385 if (NumOfActiveElems < NumOfElements)
2387 os << "\nmesh_elements\n
" << NumOfActiveElems << '\n';
2388 for (int i = 0; i < NumOfElements; i++)
2395 os << "\nweights\n
";
2396 weights.Print(os, 1);
2400 os << "\npatches\n
";
2401 for (int p = 0; p < patches.Size(); p++)
2403 os << "\n# patch
" << p << "\n\n
";
2404 patches[p]->Print(os);
2409void NURBSExtension::PrintCharacteristics(std::ostream &os) const
2412 "NURBS
Mesh entity sizes:\n
"
2413 "Dimension =
" << Dimension() << "\n
"
2415 Array<int> unique_orders(mOrders);
2416 unique_orders.Sort();
2417 unique_orders.Unique();
2418 unique_orders.Print(os, unique_orders.Size());
2420 "NumOfKnotVectors =
" << GetNKV() << "\n
"
2421 "NumOfPatches =
" << GetNP() << "\n
"
2422 "NumOfBdrPatches =
" << GetNBP() << "\n
"
2423 "NumOfVertices =
" << GetGNV() << "\n
"
2425 "NumOfBdrElements =
" << GetGNBE() << "\n
"
2426 "NumOfDofs =
" << GetNTotalDof() << "\n
"
2427 "NumOfActiveVertices =
" << GetNV() << "\n
"
2428 "NumOfActiveElems =
" << GetNE() << "\n
"
2429 "NumOfActiveBdrElems =
" << GetNBE() << "\n
"
2430 "NumOfActiveDofs =
" << GetNDof() << '\n';
2431 for (int i = 0; i < NumOfKnotVectors; i++)
2433 os << ' ' << i + 1 << ")
";
2434 knotVectors[i]->Print(os);
2439void NURBSExtension::PrintFunctions(const char *basename, int samples) const
2442 for (int i = 0; i < NumOfKnotVectors; i++)
2444 std::ostringstream filename;
2445 filename << basename<<"_
"<<i<<".dat
";
2446 os.open(filename.str().c_str());
2447 knotVectors[i]->PrintFunctions(os,samples);
2452void NURBSExtension::InitDofMap()
2459void NURBSExtension::ConnectBoundaries(Array<int> &bnds0, Array<int> &bnds1)
2463 ConnectBoundaries();
2466void NURBSExtension::ConnectBoundaries()
2468 if (master.Size() != slave.Size())
2470 mfem_error("NURBSExtension::ConnectBoundaries() boundary lists not of equal size
");
2472 if (master.Size() == 0 ) { return; }
2474 // Initialize d_to_d
2475 d_to_d.SetSize(NumOfDofs);
2476 for (int i = 0; i < NumOfDofs; i++) { d_to_d[i] = i; }
2479 for (int i = 0; i < master.Size(); i++)
2481 int bnd0 = -1, bnd1 = -1;
2482 for (int b = 0; b < GetNBP(); b++)
2484 if (master[i] == patchTopo->GetBdrAttribute(b)) { bnd0 = b; }
2485 if (slave[i]== patchTopo->GetBdrAttribute(b)) { bnd1 = b; }
2487 MFEM_VERIFY(bnd0 != -1,"Bdr 0 not found
");
2488 MFEM_VERIFY(bnd1 != -1,"Bdr 1 not found
");
2490 if (Dimension() == 1)
2492 ConnectBoundaries1D(bnd0, bnd1);
2494 else if (Dimension() == 2)
2496 ConnectBoundaries2D(bnd0, bnd1);
2500 ConnectBoundaries3D(bnd0, bnd1);
2505 Array<int> tmp(d_to_d.Size()+1);
2508 for (int i = 0; i < d_to_d.Size(); i++)
2514 for (int i = 0; i < tmp.Size(); i++)
2516 if (tmp[i] == 1) { tmp[i] = cnt++; }
2520 for (int i = 0; i < d_to_d.Size(); i++)
2522 d_to_d[i] = tmp[d_to_d[i]];
2526 if (el_dof) { delete el_dof; }
2527 if (bel_dof) { delete bel_dof; }
2528 GenerateElementDofTable();
2529 GenerateBdrElementDofTable();
2532void NURBSExtension::ConnectBoundaries1D(int bnd0, int bnd1)
2534 NURBSPatchMap p2g0(this);
2535 NURBSPatchMap p2g1(this);
2537 int okv0[1],okv1[1];
2538 const KnotVector *kv0[1],*kv1[1];
2540 p2g0.SetBdrPatchDofMap(bnd0, kv0, okv0);
2541 p2g1.SetBdrPatchDofMap(bnd1, kv1, okv1);
2543 d_to_d[p2g0(0)] = d_to_d[p2g1(0)];
2546void NURBSExtension::ConnectBoundaries2D(int bnd0, int bnd1)
2548 NURBSPatchMap p2g0(this);
2549 NURBSPatchMap p2g1(this);
2551 int okv0[1],okv1[1];
2552 const KnotVector *kv0[1],*kv1[1];
2554 p2g0.SetBdrPatchDofMap(bnd0, kv0, okv0);
2555 p2g1.SetBdrPatchDofMap(bnd1, kv1, okv1);
2558 int nks0 = kv0[0]->GetNKS();
2561 bool compatible = true;
2562 if (p2g0.nx() != p2g1.nx()) { compatible = false; }
2563 if (kv0[0]->GetNKS() != kv1[0]->GetNKS()) { compatible = false; }
2564 if (kv0[0]->GetOrder() != kv1[0]->GetOrder()) { compatible = false; }
2568 mfem::out<<p2g0.nx()<<" "<<p2g1.nx()<<endl;
2569 mfem::out<<kv0[0]->GetNKS()<<" "<<kv1[0]->GetNKS()<<endl;
2570 mfem::out<<kv0[0]->GetOrder()<<" "<<kv1[0]->GetOrder()<<endl;
2571 mfem_error("NURBS boundaries not compatible
");
2575 for (int i = 0; i < nks0; i++)
2577 if (kv0[0]->isElement(i))
2579 if (!kv1[0]->isElement(i)) { mfem_error("isElement does not match
"); }
2580 for (int ii = 0; ii <= kv0[0]->GetOrder(); ii++)
2582 int ii0 = (okv0[0] >= 0) ? (i+ii) : (nx-i-ii);
2583 int ii1 = (okv1[0] >= 0) ? (i+ii) : (nx-i-ii);
2585 d_to_d[p2g0(ii0)] = d_to_d[p2g1(ii1)];
2592void NURBSExtension::ConnectBoundaries3D(int bnd0, int bnd1)
2594 NURBSPatchMap p2g0(this);
2595 NURBSPatchMap p2g1(this);
2597 int okv0[2],okv1[2];
2598 const KnotVector *kv0[2],*kv1[2];
2600 p2g0.SetBdrPatchDofMap(bnd0, kv0, okv0);
2601 p2g1.SetBdrPatchDofMap(bnd1, kv1, okv1);
2606 int nks0 = kv0[0]->GetNKS();
2607 int nks1 = kv0[1]->GetNKS();
2610 bool compatible = true;
2611 if (p2g0.nx() != p2g1.nx()) { compatible = false; }
2612 if (p2g0.ny() != p2g1.ny()) { compatible = false; }
2614 if (kv0[0]->GetNKS() != kv1[0]->GetNKS()) { compatible = false; }
2615 if (kv0[1]->GetNKS() != kv1[1]->GetNKS()) { compatible = false; }
2617 if (kv0[0]->GetOrder() != kv1[0]->GetOrder()) { compatible = false; }
2618 if (kv0[1]->GetOrder() != kv1[1]->GetOrder()) { compatible = false; }
2622 mfem::out<<p2g0.nx()<<" "<<p2g1.nx()<<endl;
2623 mfem::out<<p2g0.ny()<<" "<<p2g1.ny()<<endl;
2625 mfem::out<<kv0[0]->GetNKS()<<" "<<kv1[0]->GetNKS()<<endl;
2626 mfem::out<<kv0[1]->GetNKS()<<" "<<kv1[1]->GetNKS()<<endl;
2628 mfem::out<<kv0[0]->GetOrder()<<" "<<kv1[0]->GetOrder()<<endl;
2629 mfem::out<<kv0[1]->GetOrder()<<" "<<kv1[1]->GetOrder()<<endl;
2630 mfem_error("NURBS boundaries not compatible
");
2634 for (int j = 0; j < nks1; j++)
2636 if (kv0[1]->isElement(j))
2638 if (!kv1[1]->isElement(j)) { mfem_error("isElement does not match #1
"); }
2639 for (int i = 0; i < nks0; i++)
2641 if (kv0[0]->isElement(i))
2643 if (!kv1[0]->isElement(i)) { mfem_error("isElement does not match #0
"); }
2644 for (int jj = 0; jj <= kv0[1]->GetOrder(); jj++)
2646 int jj0 = (okv0[1] >= 0) ? (j+jj) : (ny-j-jj);
2647 int jj1 = (okv1[1] >= 0) ? (j+jj) : (ny-j-jj);
2649 for (int ii = 0; ii <= kv0[0]->GetOrder(); ii++)
2651 int ii0 = (okv0[0] >= 0) ? (i+ii) : (nx-i-ii);
2652 int ii1 = (okv1[0] >= 0) ? (i+ii) : (nx-i-ii);
2654 d_to_d[p2g0(ii0,jj0)] = d_to_d[p2g1(ii1,jj1)];
2663void NURBSExtension::GenerateActiveVertices()
2665 int vert[8], nv, g_el, nx, ny, nz, dim = Dimension();
2667 NURBSPatchMap p2g(this);
2668 const KnotVector *kv[3];
2671 activeVert.SetSize(GetGNV());
2673 for (int p = 0; p < GetNP(); p++)
2675 p2g.SetPatchVertexMap(p, kv);
2678 ny = (dim >= 2) ? p2g.ny() : 1;
2679 nz = (dim == 3) ? p2g.nz() : 1;
2681 for (int k = 0; k < nz; k++)
2683 for (int j = 0; j < ny; j++)
2685 for (int i = 0; i < nx; i++)
2687 if (activeElem[g_el])
2697 vert[0] = p2g(i, j );
2698 vert[1] = p2g(i+1,j );
2699 vert[2] = p2g(i+1,j+1);
2700 vert[3] = p2g(i, j+1);
2705 vert[0] = p2g(i, j, k);
2706 vert[1] = p2g(i+1,j, k);
2707 vert[2] = p2g(i+1,j+1,k);
2708 vert[3] = p2g(i, j+1,k);
2710 vert[4] = p2g(i, j, k+1);
2711 vert[5] = p2g(i+1,j, k+1);
2712 vert[6] = p2g(i+1,j+1,k+1);
2713 vert[7] = p2g(i, j+1,k+1);
2717 for (int v = 0; v < nv; v++)
2719 activeVert[vert[v]] = 1;
2728 NumOfActiveVertices = 0;
2729 for (int i = 0; i < GetGNV(); i++)
2730 if (activeVert[i] == 1)
2732 activeVert[i] = NumOfActiveVertices++;
2736void NURBSExtension::GenerateActiveBdrElems()
2738 int dim = Dimension();
2739 Array<KnotVector *> kv(dim);
2741 activeBdrElem.SetSize(GetGNBE());
2742 if (GetGNE() == GetNE())
2744 activeBdrElem = true;
2745 NumOfActiveBdrElems = GetGNBE();
2748 activeBdrElem = false;
2749 NumOfActiveBdrElems = 0;
2750 // the mesh will generate the actual boundary including boundary
2751 // elements that are not on boundary patches. we use this for
2752 // visualization of processor boundaries
2754 // TODO: generate actual boundary?
2758void NURBSExtension::MergeWeights(Mesh *mesh_array[], int num_pieces)
2760 Array<int> lelem_elem;
2762 for (int i = 0; i < num_pieces; i++)
2764 NURBSExtension *lext = mesh_array[i]->NURBSext;
2766 lext->GetElementLocalToGlobal(lelem_elem);
2768 for (int lel = 0; lel < lext->GetNE(); lel++)
2770 int gel = lelem_elem[lel];
2772 int nd = el_dof->RowSize(gel);
2773 int *gdofs = el_dof->GetRow(gel);
2774 int *ldofs = lext->el_dof->GetRow(lel);
2775 for (int j = 0; j < nd; j++)
2777 weights(gdofs[j]) = lext->weights(ldofs[j]);
2783void NURBSExtension::MergeGridFunctions(
2784 GridFunction *gf_array[], int num_pieces, GridFunction &merged)
2786 FiniteElementSpace *gfes = merged.FESpace();
2787 Array<int> lelem_elem, dofs;
2790 for (int i = 0; i < num_pieces; i++)
2792 FiniteElementSpace *lfes = gf_array[i]->FESpace();
2793 NURBSExtension *lext = lfes->GetMesh()->NURBSext;
2795 lext->GetElementLocalToGlobal(lelem_elem);
2797 for (int lel = 0; lel < lext->GetNE(); lel++)
2799 lfes->GetElementVDofs(lel, dofs);
2800 gf_array[i]->GetSubVector(dofs, lvec);
2802 gfes->GetElementVDofs(lelem_elem[lel], dofs);
2803 merged.SetSubVector(dofs, lvec);
2808void NURBSExtension::CheckPatches()
2810 if (Dimension() == 1 ) { return; }
2815 for (int p = 0; p < GetNP(); p++)
2817 patchTopo->GetElementEdges(p, edges, oedge);
2819 for (int i = 0; i < edges.Size(); i++)
2821 edges[i] = edge_to_knot[edges[i]];
2824 edges[i] = -1 - edges[i];
2828 if ((Dimension() == 2 &&
2829 (edges[0] != -1 - edges[2] || edges[1] != -1 - edges[3])) ||
2831 (Dimension() == 3 &&
2832 (edges[0] != edges[2] || edges[0] != edges[4] ||
2833 edges[0] != edges[6] || edges[1] != edges[3] ||
2834 edges[1] != edges[5] || edges[1] != edges[7] ||
2835 edges[8] != edges[9] || edges[8] != edges[10] ||
2836 edges[8] != edges[11])))
2839 << ")\n Inconsistent edge-to-
knot mapping!\n
";
2845void NURBSExtension::CheckBdrPatches()
2850 for (int p = 0; p < GetNBP(); p++)
2852 patchTopo->GetBdrElementEdges(p, edges, oedge);
2854 for (int i = 0; i < edges.Size(); i++)
2856 edges[i] = edge_to_knot[edges[i]];
2859 edges[i] = -1 - edges[i];
2863 if ((Dimension() == 2 && (edges[0] < 0)) ||
2864 (Dimension() == 3 && (edges[0] < 0 || edges[1] < 0)))
2867 << p << ") : Bad orientation!\n
";
2873void NURBSExtension::CheckKVDirection(int p, Array <int> &kvdir)
2875 // patchTopo->GetElementEdges is not yet implemented for 1D
2876 MFEM_VERIFY(Dimension()>1, "1D not yet implemented.
");
2878 kvdir.SetSize(Dimension());
2881 Array<int> patchvert, edges, orient, edgevert;
2883 patchTopo->GetElementVertices(p, patchvert);
2885 patchTopo->GetElementEdges(p, edges, orient);
2887 // Compare the vertices of the patches with the vertices of the knotvectors of knot2dge
2888 // Based on the match the orientation will be a 1 or a -1
2889 // -1: direction is flipped
2890 // 1: direction is not flipped
2893 for (int i = 0; i < edges.Size(); i++)
2896 patchTopo->GetEdgeVertices(edges[i], edgevert);
2897 if (edgevert[0] == patchvert[0] && edgevert[1] == patchvert[1])
2902 if (edgevert[0] == patchvert[1] && edgevert[1] == patchvert[0])
2908 if (edgevert[0] == patchvert[1] && edgevert[1] == patchvert[2])
2913 if (edgevert[0] == patchvert[2] && edgevert[1] == patchvert[1])
2919 if (Dimension() == 3)
2922 for (int i = 0; i < edges.Size(); i++)
2924 patchTopo->GetEdgeVertices(edges[i], edgevert);
2926 if (edgevert[0] == patchvert[0] && edgevert[1] == patchvert[4])
2931 if (edgevert[0] == patchvert[4] && edgevert[1] == patchvert[0])
2938 MFEM_VERIFY(kvdir.Find(0) == -1, "Could not find
direction of knotvector.
");
2941void NURBSExtension::CreateComprehensiveKV()
2943 Array<int> edges, orient, kvdir;
2944 Array<int> e(Dimension());
2946 // 1D: comprehensive and unique KV are the same
2947 if (Dimension() == 1)
2949 knotVectorsCompr.SetSize(GetNKV());
2950 for (int i = 0; i < GetNKV(); i++)
2952 knotVectorsCompr[i] = new KnotVector(*(KnotVec(i)));
2956 else if (Dimension() == 2)
2958 knotVectorsCompr.SetSize(GetNP()*Dimension());
2962 else if (Dimension() == 3)
2964 knotVectorsCompr.SetSize(GetNP()*Dimension());
2970 for (int p = 0; p < GetNP(); p++)
2972 CheckKVDirection(p, kvdir);
2974 patchTopo->GetElementEdges(p, edges, orient);
2976 for (int d = 0; d < Dimension(); d++)
2978 // Indices in unique and comprehensive sets of the KnotVector
2979 int iun = edges[e[d]];
2980 int icomp = Dimension()*p+d;
2982 knotVectorsCompr[icomp] = new KnotVector(*(KnotVec(iun)));
2984 if (kvdir[d] == -1) {knotVectorsCompr[icomp]->Flip();}
2988 MFEM_VERIFY(ConsistentKVSets(), "Mismatch in KnotVectors
");
2991void NURBSExtension::UpdateUniqueKV()
2993 Array<int> e(Dimension());
2995 // 1D: comprehensive and unique KV are the same
2996 if (Dimension() == 1)
2998 for (int i = 0; i < GetNKV(); i++)
3000 *(KnotVec(i)) = *(knotVectorsCompr[i]);
3004 else if (Dimension() == 2)
3009 else if (Dimension() == 3)
3016 for (int p = 0; p < GetNP(); p++)
3018 Array<int> edges, orient, kvdir;
3020 patchTopo->GetElementEdges(p, edges, orient);
3021 CheckKVDirection(p, kvdir);
3023 for ( int d = 0; d < Dimension(); d++)
3026 if (kvdir[d] == -1) {flip = true;}
3028 // Indices in unique and comprehensive sets of the KnotVector
3029 int iun = edges[e[d]];
3030 int icomp = Dimension()*p+d;
3032 // Check if difference in order
3033 int o1 = KnotVec(iun)->GetOrder();
3034 int o2 = knotVectorsCompr[icomp]->GetOrder();
3035 int diffo = abs(o1 - o2);
3039 // Update reduced set of knotvectors
3040 *(KnotVec(iun)) = *(knotVectorsCompr[icomp]);
3042 // Give correct direction to unique knotvector.
3043 if (flip) { KnotVec(iun)->Flip(); }
3046 // Check if difference between knots
3049 if (flip) { knotVectorsCompr[icomp]->Flip(); }
3051 KnotVec(iun)->Difference(*(knotVectorsCompr[icomp]), diffknot);
3053 if (flip) { knotVectorsCompr[icomp]->Flip(); }
3055 if (diffknot.Size() > 0)
3057 // Update reduced set of knotvectors
3058 *(KnotVec(iun)) = *(knotVectorsCompr[icomp]);
3060 // Give correct direction to unique knotvector.
3061 if (flip) {KnotVec(iun)->Flip();}
3066 MFEM_VERIFY(ConsistentKVSets(), "Mismatch in KnotVectors
");
3069bool NURBSExtension::ConsistentKVSets()
3071 // patchTopo->GetElementEdges is not yet implemented for 1D
3072 MFEM_VERIFY(Dimension()>1, "1D not yet implemented.
");
3074 Array<int> edges, orient, kvdir;
3077 Array<int> e(Dimension());
3081 if (Dimension() == 2)
3085 else if (Dimension() == 3)
3091 for (int p = 0; p < GetNP(); p++)
3093 patchTopo->GetElementEdges(p, edges, orient);
3095 CheckKVDirection(p, kvdir);
3097 for (int d = 0; d < Dimension(); d++)
3100 if (kvdir[d] == -1) {flip = true;}
3102 // Indices in unique and comprehensive sets of the KnotVector
3103 int iun = edges[e[d]];
3104 int icomp = Dimension()*p+d;
3106 // Check if KnotVectors are of equal order
3107 int o1 = KnotVec(iun)->GetOrder();
3108 int o2 = knotVectorsCompr[icomp]->GetOrder();
3109 int diffo = abs(o1 - o2);
3113 mfem::out << "\norder of knotVectorsCompr
" << d << " of patch
" << p;
3114 mfem::out << " does not agree with knotVectors
" << KnotInd(iun) << "\n
";
3118 // Check if Knotvectors have the same knots
3119 if (flip) {knotVectorsCompr[icomp]->Flip();}
3121 KnotVec(iun)->Difference(*(knotVectorsCompr[icomp]), diff);
3123 if (flip) {knotVectorsCompr[icomp]->Flip();}
3125 if (diff.Size() > 0)
3127 mfem::out << "\nknotVectorsCompr
" << d << " of patch
" << p;
3128 mfem::out << " does not agree with knotVectors
" << KnotInd(iun) << "\n
";
3136void NURBSExtension::GetPatchKnotVectors(int p, Array<KnotVector *> &kv)
3138 Array<int> edges, orient;
3140 kv.SetSize(Dimension());
3142 if (Dimension() == 1)
3144 kv[0] = knotVectorsCompr[Dimension()*p];
3146 else if (Dimension() == 2)
3148 kv[0] = knotVectorsCompr[Dimension()*p];
3149 kv[1] = knotVectorsCompr[Dimension()*p + 1];
3153 kv[0] = knotVectorsCompr[Dimension()*p];
3154 kv[1] = knotVectorsCompr[Dimension()*p + 1];
3155 kv[2] = knotVectorsCompr[Dimension()*p + 2];
3159void NURBSExtension::GetPatchKnotVectors(int p, Array<const KnotVector *> &kv)
3162 Array<int> edges, orient;
3164 kv.SetSize(Dimension());
3166 if (Dimension() == 1)
3168 kv[0] = knotVectorsCompr[Dimension()*p];
3170 else if (Dimension() == 2)
3172 kv[0] = knotVectorsCompr[Dimension()*p];
3173 kv[1] = knotVectorsCompr[Dimension()*p + 1];
3177 kv[0] = knotVectorsCompr[Dimension()*p];
3178 kv[1] = knotVectorsCompr[Dimension()*p + 1];
3179 kv[2] = knotVectorsCompr[Dimension()*p + 2];
3183void NURBSExtension::GetBdrPatchKnotVectors(int p, Array<KnotVector *> &kv)
3188 kv.SetSize(Dimension() - 1);
3190 if (Dimension() == 2)
3192 patchTopo->GetBdrElementEdges(p, edges, orient);
3193 kv[0] = KnotVec(edges[0]);
3195 else if (Dimension() == 3)
3197 patchTopo->GetBdrElementEdges(p, edges, orient);
3198 kv[0] = KnotVec(edges[0]);
3199 kv[1] = KnotVec(edges[1]);
3203void NURBSExtension::GetBdrPatchKnotVectors(
3204 int p, Array<const KnotVector *> &kv) const
3209 kv.SetSize(Dimension() - 1);
3211 if (Dimension() == 2)
3213 patchTopo->GetBdrElementEdges(p, edges, orient);
3214 kv[0] = KnotVec(edges[0]);
3216 else if (Dimension() == 3)
3218 patchTopo->GetBdrElementEdges(p, edges, orient);
3219 kv[0] = KnotVec(edges[0]);
3220 kv[1] = KnotVec(edges[1]);
3224void NURBSExtension::SetOrderFromOrders()
3226 MFEM_VERIFY(mOrders.Size() > 0, "");
3227 mOrder = mOrders[0];
3228 for (int i = 1; i < mOrders.Size(); i++)
3230 if (mOrders[i] != mOrder)
3232 mOrder = NURBSFECollection::VariableOrder;
3238void NURBSExtension::SetOrdersFromKnotVectors()
3240 mOrders.SetSize(NumOfKnotVectors);
3241 for (int i = 0; i < NumOfKnotVectors; i++)
3243 mOrders[i] = knotVectors[i]->GetOrder();
3245 SetOrderFromOrders();
3248void NURBSExtension::GenerateOffsets()
3250 int nv = patchTopo->GetNV();
3251 int ne = patchTopo->GetNEdges();
3252 int nf = patchTopo->GetNFaces();
3253 int np = patchTopo->GetNE();
3254 int meshCounter, spaceCounter, dim = Dimension();
3259 v_meshOffsets.SetSize(nv);
3260 e_meshOffsets.SetSize(ne);
3261 f_meshOffsets.SetSize(nf);
3262 p_meshOffsets.SetSize(np);
3264 v_spaceOffsets.SetSize(nv);
3265 e_spaceOffsets.SetSize(ne);
3266 f_spaceOffsets.SetSize(nf);
3267 p_spaceOffsets.SetSize(np);
3269 // Get vertex offsets
3270 for (meshCounter = 0; meshCounter < nv; meshCounter++)
3272 v_meshOffsets[meshCounter] = meshCounter;
3273 v_spaceOffsets[meshCounter] = meshCounter;
3275 spaceCounter = meshCounter;
3278 for (int e = 0; e < ne; e++)
3280 e_meshOffsets[e] = meshCounter;
3281 e_spaceOffsets[e] = spaceCounter;
3282 meshCounter += KnotVec(e)->GetNE() - 1;
3283 spaceCounter += KnotVec(e)->GetNCP() - 2;
3287 for (int f = 0; f < nf; f++)
3289 f_meshOffsets[f] = meshCounter;
3290 f_spaceOffsets[f] = spaceCounter;
3292 patchTopo->GetFaceEdges(f, edges, orient);
3295 (KnotVec(edges[0])->GetNE() - 1) *
3296 (KnotVec(edges[1])->GetNE() - 1);
3298 (KnotVec(edges[0])->GetNCP() - 2) *
3299 (KnotVec(edges[1])->GetNCP() - 2);
3302 // Get patch offsets
3303 for (int p = 0; p < np; p++)
3305 p_meshOffsets[p] = meshCounter;
3306 p_spaceOffsets[p] = spaceCounter;
3312 meshCounter += KnotVec(0)->GetNE() - 1;
3313 spaceCounter += KnotVec(0)->GetNCP() - 2;
3317 patchTopo->GetElementEdges(p, edges, orient);
3319 (KnotVec(edges[0])->GetNE() - 1) *
3320 (KnotVec(edges[1])->GetNE() - 1);
3322 (KnotVec(edges[0])->GetNCP() - 2) *
3323 (KnotVec(edges[1])->GetNCP() - 2);
3327 patchTopo->GetElementEdges(p, edges, orient);
3329 (KnotVec(edges[0])->GetNE() - 1) *
3330 (KnotVec(edges[3])->GetNE() - 1) *
3331 (KnotVec(edges[8])->GetNE() - 1);
3333 (KnotVec(edges[0])->GetNCP() - 2) *
3334 (KnotVec(edges[3])->GetNCP() - 2) *
3335 (KnotVec(edges[8])->GetNCP() - 2);
3338 NumOfVertices = meshCounter;
3339 NumOfDofs = spaceCounter;
3342void NURBSExtension::CountElements()
3344 int dim = Dimension();
3345 Array<const KnotVector *> kv(dim);
3348 for (int p = 0; p < GetNP(); p++)
3350 GetPatchKnotVectors(p, kv);
3352 int ne = kv[0]->GetNE();
3353 for (int d = 1; d < dim; d++)
3355 ne *= kv[d]->GetNE();
3358 NumOfElements += ne;
3362void NURBSExtension::CountBdrElements()
3364 int dim = Dimension() - 1;
3365 Array<KnotVector *> kv(dim);
3367 NumOfBdrElements = 0;
3368 for (int p = 0; p < GetNBP(); p++)
3370 GetBdrPatchKnotVectors(p, kv);
3373 for (int d = 0; d < dim; d++)
3375 ne *= kv[d]->GetNE();
3378 NumOfBdrElements += ne;
3382void NURBSExtension::GetElementTopo(Array<Element *> &elements) const
3384 elements.SetSize(GetNE());
3386 if (Dimension() == 1)
3388 Get1DElementTopo(elements);
3390 else if (Dimension() == 2)
3392 Get2DElementTopo(elements);
3396 Get3DElementTopo(elements);
3400void NURBSExtension::Get1DElementTopo(Array<Element *> &elements) const
3405 NURBSPatchMap p2g(this);
3406 const KnotVector *kv[1];
3408 for (int p = 0; p < GetNP(); p++)
3410 p2g.SetPatchVertexMap(p, kv);
3413 int patch_attr = patchTopo->GetAttribute(p);
3415 for (int i = 0; i < nx; i++)
3419 ind[0] = activeVert[p2g(i)];
3420 ind[1] = activeVert[p2g(i+1)];
3422 elements[el] = new Segment(ind, patch_attr);
3430void NURBSExtension::Get2DElementTopo(Array<Element *> &elements) const
3435 NURBSPatchMap p2g(this);
3436 const KnotVector *kv[2];
3438 for (int p = 0; p < GetNP(); p++)
3440 p2g.SetPatchVertexMap(p, kv);
3444 int patch_attr = patchTopo->GetAttribute(p);
3446 for (int j = 0; j < ny; j++)
3448 for (int i = 0; i < nx; i++)
3452 ind[0] = activeVert[p2g(i, j )];
3453 ind[1] = activeVert[p2g(i+1,j )];
3454 ind[2] = activeVert[p2g(i+1,j+1)];
3455 ind[3] = activeVert[p2g(i, j+1)];
3457 elements[el] = new Quadrilateral(ind, patch_attr);
3466void NURBSExtension::Get3DElementTopo(Array<Element *> &elements) const
3471 NURBSPatchMap p2g(this);
3472 const KnotVector *kv[3];
3474 for (int p = 0; p < GetNP(); p++)
3476 p2g.SetPatchVertexMap(p, kv);
3481 int patch_attr = patchTopo->GetAttribute(p);
3483 for (int k = 0; k < nz; k++)
3485 for (int j = 0; j < ny; j++)
3487 for (int i = 0; i < nx; i++)
3491 ind[0] = activeVert[p2g(i, j, k)];
3492 ind[1] = activeVert[p2g(i+1,j, k)];
3493 ind[2] = activeVert[p2g(i+1,j+1,k)];
3494 ind[3] = activeVert[p2g(i, j+1,k)];
3496 ind[4] = activeVert[p2g(i, j, k+1)];
3497 ind[5] = activeVert[p2g(i+1,j, k+1)];
3498 ind[6] = activeVert[p2g(i+1,j+1,k+1)];
3499 ind[7] = activeVert[p2g(i, j+1,k+1)];
3501 elements[el] = new Hexahedron(ind, patch_attr);
3511void NURBSExtension::GetBdrElementTopo(Array<Element *> &boundary) const
3513 boundary.SetSize(GetNBE());
3515 if (Dimension() == 1)
3517 Get1DBdrElementTopo(boundary);
3519 else if (Dimension() == 2)
3521 Get2DBdrElementTopo(boundary);
3525 Get3DBdrElementTopo(boundary);
3529void NURBSExtension::Get1DBdrElementTopo(Array<Element *> &boundary) const
3533 NURBSPatchMap p2g(this);
3534 const KnotVector *kv[1];
3537 for (int b = 0; b < GetNBP(); b++)
3539 p2g.SetBdrPatchVertexMap(b, kv, okv);
3540 int bdr_patch_attr = patchTopo->GetBdrAttribute(b);
3542 if (activeBdrElem[g_be])
3544 ind[0] = activeVert[p2g[0]];
3545 boundary[l_be] = new Point(ind, bdr_patch_attr);
3552void NURBSExtension::Get2DBdrElementTopo(Array<Element *> &boundary) const
3556 NURBSPatchMap p2g(this);
3557 const KnotVector *kv[1];
3560 for (int b = 0; b < GetNBP(); b++)
3562 p2g.SetBdrPatchVertexMap(b, kv, okv);
3565 int bdr_patch_attr = patchTopo->GetBdrAttribute(b);
3567 for (int i = 0; i < nx; i++)
3569 if (activeBdrElem[g_be])
3571 int i_ = (okv[0] >= 0) ? i : (nx - 1 - i);
3572 ind[0] = activeVert[p2g[i_ ]];
3573 ind[1] = activeVert[p2g[i_+1]];
3575 boundary[l_be] = new Segment(ind, bdr_patch_attr);
3583void NURBSExtension::Get3DBdrElementTopo(Array<Element *> &boundary) const
3587 NURBSPatchMap p2g(this);
3588 const KnotVector *kv[2];
3591 for (int b = 0; b < GetNBP(); b++)
3593 p2g.SetBdrPatchVertexMap(b, kv, okv);
3597 int bdr_patch_attr = patchTopo->GetBdrAttribute(b);
3599 for (int j = 0; j < ny; j++)
3601 int j_ = (okv[1] >= 0) ? j : (ny - 1 - j);
3602 for (int i = 0; i < nx; i++)
3604 if (activeBdrElem[g_be])
3606 int i_ = (okv[0] >= 0) ? i : (nx - 1 - i);
3607 ind[0] = activeVert[p2g(i_, j_ )];
3608 ind[1] = activeVert[p2g(i_+1,j_ )];
3609 ind[2] = activeVert[p2g(i_+1,j_+1)];
3610 ind[3] = activeVert[p2g(i_, j_+1)];
3612 boundary[l_be] = new Quadrilateral(ind, bdr_patch_attr);
3621void NURBSExtension::GenerateElementDofTable()
3623 activeDof.SetSize(GetNTotalDof());
3626 if (Dimension() == 1)
3628 Generate1DElementDofTable();
3630 else if (Dimension() == 2)
3632 Generate2DElementDofTable();
3636 Generate3DElementDofTable();
3639 SetPatchToElements();
3641 NumOfActiveDofs = 0;
3642 for (int d = 0; d < GetNTotalDof(); d++)
3646 activeDof[d] = NumOfActiveDofs;
3649 int *dof = el_dof->GetJ();
3650 int ndof = el_dof->Size_of_connections();
3651 for (int i = 0; i < ndof; i++)
3653 dof[i] = activeDof[dof[i]] - 1;
3657void NURBSExtension::Generate1DElementDofTable()
3661 const KnotVector *kv[2];
3662 NURBSPatchMap p2g(this);
3664 Array<Connection> el_dof_list;
3665 el_to_patch.SetSize(NumOfActiveElems);
3666 el_to_IJK.SetSize(NumOfActiveElems, 2);
3668 for (int p = 0; p < GetNP(); p++)
3670 p2g.SetPatchDofMap(p, kv);
3673 const int ord0 = kv[0]->GetOrder();
3674 for (int i = 0; i < kv[0]->GetNKS(); i++)
3676 if (kv[0]->isElement(i))
3680 Connection conn(el,0);
3681 for (int ii = 0; ii <= ord0; ii++)
3683 conn.to = DofMap(p2g(i+ii));
3684 activeDof[conn.to] = 1;
3685 el_dof_list.Append(conn);
3687 el_to_patch[el] = p;
3688 el_to_IJK(el,0) = i;
3696 // We must NOT sort el_dof_list in this case.
3697 el_dof = new Table(NumOfActiveElems, el_dof_list);
3700void NURBSExtension::Generate2DElementDofTable()
3704 const KnotVector *kv[2];
3705 NURBSPatchMap p2g(this);
3707 Array<Connection> el_dof_list;
3708 el_to_patch.SetSize(NumOfActiveElems);
3709 el_to_IJK.SetSize(NumOfActiveElems, 2);
3711 for (int p = 0; p < GetNP(); p++)
3713 p2g.SetPatchDofMap(p, kv);
3716 const int ord0 = kv[0]->GetOrder();
3717 const int ord1 = kv[1]->GetOrder();
3718 for (int j = 0; j < kv[1]->GetNKS(); j++)
3720 if (kv[1]->isElement(j))
3722 for (int i = 0; i < kv[0]->GetNKS(); i++)
3724 if (kv[0]->isElement(i))
3728 Connection conn(el,0);
3729 for (int jj = 0; jj <= ord1; jj++)
3731 for (int ii = 0; ii <= ord0; ii++)
3733 conn.to = DofMap(p2g(i+ii,j+jj));
3734 activeDof[conn.to] = 1;
3735 el_dof_list.Append(conn);
3738 el_to_patch[el] = p;
3739 el_to_IJK(el,0) = i;
3740 el_to_IJK(el,1) = j;
3750 // We must NOT sort el_dof_list in this case.
3751 el_dof = new Table(NumOfActiveElems, el_dof_list);
3754void NURBSExtension::Generate3DElementDofTable()
3758 const KnotVector *kv[3];
3759 NURBSPatchMap p2g(this);
3761 Array<Connection> el_dof_list;
3762 el_to_patch.SetSize(NumOfActiveElems);
3763 el_to_IJK.SetSize(NumOfActiveElems, 3);
3765 for (int p = 0; p < GetNP(); p++)
3767 p2g.SetPatchDofMap(p, kv);
3770 const int ord0 = kv[0]->GetOrder();
3771 const int ord1 = kv[1]->GetOrder();
3772 const int ord2 = kv[2]->GetOrder();
3773 for (int k = 0; k < kv[2]->GetNKS(); k++)
3775 if (kv[2]->isElement(k))
3777 for (int j = 0; j < kv[1]->GetNKS(); j++)
3779 if (kv[1]->isElement(j))
3781 for (int i = 0; i < kv[0]->GetNKS(); i++)
3783 if (kv[0]->isElement(i))
3787 Connection conn(el,0);
3788 for (int kk = 0; kk <= ord2; kk++)
3790 for (int jj = 0; jj <= ord1; jj++)
3792 for (int ii = 0; ii <= ord0; ii++)
3794 conn.to = DofMap(p2g(i+ii, j+jj, k+kk));
3795 activeDof[conn.to] = 1;
3796 el_dof_list.Append(conn);
3801 el_to_patch[el] = p;
3802 el_to_IJK(el,0) = i;
3803 el_to_IJK(el,1) = j;
3804 el_to_IJK(el,2) = k;
3816 // We must NOT sort el_dof_list in this case.
3817 el_dof = new Table(NumOfActiveElems, el_dof_list);
3820void NURBSExtension::GetPatchDofs(const int patch, Array<int> &dofs)
3822 const KnotVector *kv[3];
3823 NURBSPatchMap p2g(this);
3825 p2g.SetPatchDofMap(patch, kv);
3827 if (Dimension() == 1)
3829 const int nx = kv[0]->GetNCP();
3832 for (int i=0; i<nx; ++i)
3834 dofs[i] = DofMap(p2g(i));
3837 else if (Dimension() == 2)
3839 const int nx = kv[0]->GetNCP();
3840 const int ny = kv[1]->GetNCP();
3841 dofs.SetSize(nx * ny);
3843 for (int j=0; j<ny; ++j)
3844 for (int i=0; i<nx; ++i)
3846 dofs[i + (nx * j)] = DofMap(p2g(i, j));
3849 else if (Dimension() == 3)
3851 const int nx = kv[0]->GetNCP();
3852 const int ny = kv[1]->GetNCP();
3853 const int nz = kv[2]->GetNCP();
3854 dofs.SetSize(nx * ny * nz);
3856 for (int k=0; k<nz; ++k)
3857 for (int j=0; j<ny; ++j)
3858 for (int i=0; i<nx; ++i)
3860 dofs[i + (nx * (j + (k * ny)))] = DofMap(p2g(i, j, k));
3865 MFEM_ABORT("Only 1D/2D/3D supported currently in
NURBSExtension::GetPatchDofs
");
3869void NURBSExtension::GenerateBdrElementDofTable()
3871 if (Dimension() == 1)
3873 Generate1DBdrElementDofTable();
3875 else if (Dimension() == 2)
3877 Generate2DBdrElementDofTable();
3881 Generate3DBdrElementDofTable();
3884 SetPatchToBdrElements();
3886 int *dof = bel_dof->GetJ();
3887 int ndof = bel_dof->Size_of_connections();
3888 for (int i = 0; i < ndof; i++)
3890 dof[i] = activeDof[dof[i]] - 1;
3894void NURBSExtension::Generate1DBdrElementDofTable()
3897 int lbe = 0, okv[1];
3898 const KnotVector *kv[1];
3899 NURBSPatchMap p2g(this);
3901 Array<Connection> bel_dof_list;
3902 bel_to_patch.SetSize(NumOfActiveBdrElems);
3903 bel_to_IJK.SetSize(NumOfActiveBdrElems, 1);
3905 for (int b = 0; b < GetNBP(); b++)
3907 p2g.SetBdrPatchDofMap(b, kv, okv);
3909 if (activeBdrElem[gbe])
3911 Connection conn(lbe,0);
3912 conn.to = DofMap(p2g[0]);
3913 bel_dof_list.Append(conn);
3914 bel_to_patch[lbe] = b;
3915 bel_to_IJK(lbe,0) = 0;
3920 // We must NOT sort bel_dof_list in this case.
3921 bel_dof = new Table(NumOfActiveBdrElems, bel_dof_list);
3924void NURBSExtension::Generate2DBdrElementDofTable()
3927 int lbe = 0, okv[1];
3928 const KnotVector *kv[1];
3929 NURBSPatchMap p2g(this);
3931 Array<Connection> bel_dof_list;
3932 bel_to_patch.SetSize(NumOfActiveBdrElems);
3933 bel_to_IJK.SetSize(NumOfActiveBdrElems, 1);
3935 for (int b = 0; b < GetNBP(); b++)
3937 p2g.SetBdrPatchDofMap(b, kv, okv);
3938 const int nx = p2g.nx(); // NCP-1
3940 const int nks0 = kv[0]->GetNKS();
3941 const int ord0 = kv[0]->GetOrder();
3942 for (int i = 0; i < nks0; i++)
3944 if (kv[0]->isElement(i))
3946 if (activeBdrElem[gbe])
3948 Connection conn(lbe,0);
3949 for (int ii = 0; ii <= ord0; ii++)
3951 conn.to = DofMap(p2g[(okv[0] >= 0) ? (i+ii) : (nx-i-ii)]);
3952 bel_dof_list.Append(conn);
3954 bel_to_patch[lbe] = b;
3955 bel_to_IJK(lbe,0) = (okv[0] >= 0) ? i : (-1-i);
3962 // We must NOT sort bel_dof_list in this case.
3963 bel_dof = new Table(NumOfActiveBdrElems, bel_dof_list);
3967void NURBSExtension::Generate3DBdrElementDofTable()
3970 int lbe = 0, okv[2];
3971 const KnotVector *kv[2];
3972 NURBSPatchMap p2g(this);
3974 Array<Connection> bel_dof_list;
3975 bel_to_patch.SetSize(NumOfActiveBdrElems);
3976 bel_to_IJK.SetSize(NumOfActiveBdrElems, 2);
3978 for (int b = 0; b < GetNBP(); b++)
3980 p2g.SetBdrPatchDofMap(b, kv, okv);
3981 const int nx = p2g.nx(); // NCP0-1
3982 const int ny = p2g.ny(); // NCP1-1
3985 const int nks0 = kv[0]->GetNKS();
3986 const int ord0 = kv[0]->GetOrder();
3987 const int nks1 = kv[1]->GetNKS();
3988 const int ord1 = kv[1]->GetOrder();
3989 for (int j = 0; j < nks1; j++)
3991 if (kv[1]->isElement(j))
3993 for (int i = 0; i < nks0; i++)
3995 if (kv[0]->isElement(i))
3997 if (activeBdrElem[gbe])
3999 Connection conn(lbe,0);
4000 for (int jj = 0; jj <= ord1; jj++)
4002 const int jj_ = (okv[1] >= 0) ? (j+jj) : (ny-j-jj);
4003 for (int ii = 0; ii <= ord0; ii++)
4005 const int ii_ = (okv[0] >= 0) ? (i+ii) : (nx-i-ii);
4006 conn.to = DofMap(p2g(ii_, jj_));
4007 bel_dof_list.Append(conn);
4010 bel_to_patch[lbe] = b;
4011 bel_to_IJK(lbe,0) = (okv[0] >= 0) ? i : (-1-i);
4012 bel_to_IJK(lbe,1) = (okv[1] >= 0) ? j : (-1-j);
4021 // We must NOT sort bel_dof_list in this case.
4022 bel_dof = new Table(NumOfActiveBdrElems, bel_dof_list);
4025void NURBSExtension::GetVertexLocalToGlobal(Array<int> &lvert_vert)
4027 lvert_vert.SetSize(GetNV());
4028 for (int gv = 0; gv < GetGNV(); gv++)
4029 if (activeVert[gv] >= 0)
4031 lvert_vert[activeVert[gv]] = gv;
4035void NURBSExtension::GetElementLocalToGlobal(Array<int> &lelem_elem)
4037 lelem_elem.SetSize(GetNE());
4038 for (int le = 0, ge = 0; ge < GetGNE(); ge++)
4041 lelem_elem[le++] = ge;
4045void NURBSExtension::LoadFE(int i, const FiniteElement *FE) const
4047 const NURBSFiniteElement *NURBSFE =
4048 dynamic_cast<const NURBSFiniteElement *>(FE);
4050 if (NURBSFE->GetElement() != i)
4053 NURBSFE->SetIJK(el_to_IJK.GetRow(i));
4054 if (el_to_patch[i] != NURBSFE->GetPatch())
4056 GetPatchKnotVectors(el_to_patch[i], NURBSFE->KnotVectors());
4057 NURBSFE->SetPatch(el_to_patch[i]);
4058 NURBSFE->SetOrder();
4060 el_dof->GetRow(i, dofs);
4061 weights.GetSubVector(dofs, NURBSFE->Weights());
4062 NURBSFE->SetElement(i);
4066void NURBSExtension::LoadBE(int i, const FiniteElement *BE) const
4068 if (Dimension() == 1) { return; }
4070 const NURBSFiniteElement *NURBSFE =
4071 dynamic_cast<const NURBSFiniteElement *>(BE);
4073 if (NURBSFE->GetElement() != i)
4076 NURBSFE->SetIJK(bel_to_IJK.GetRow(i));
4077 if (bel_to_patch[i] != NURBSFE->GetPatch())
4079 GetBdrPatchKnotVectors(bel_to_patch[i], NURBSFE->KnotVectors());
4080 NURBSFE->SetPatch(bel_to_patch[i]);
4081 NURBSFE->SetOrder();
4083 bel_dof->GetRow(i, dofs);
4084 weights.GetSubVector(dofs, NURBSFE->Weights());
4085 NURBSFE->SetElement(i);
4089void NURBSExtension::ConvertToPatches(const Vector &Nodes)
4094 if (patches.Size() == 0)
4096 GetPatchNets(Nodes, Dimension());
4100void NURBSExtension::SetCoordsFromPatches(Vector &Nodes)
4102 if (patches.Size() == 0) { return; }
4104 SetSolutionVector(Nodes, Dimension());
4108void NURBSExtension::SetKnotsFromPatches()
4110 if (patches.Size() == 0)
4113 " No patches available!
");
4116 Array<KnotVector *> kv;
4118 for (int p = 0; p < patches.Size(); p++)
4120 GetPatchKnotVectors(p, kv);
4122 for (int i = 0; i < kv.Size(); i++)
4124 *kv[i] = *patches[p]->GetKV(i);
4129 SetOrdersFromKnotVectors();
4135 // all elements must be active
4136 NumOfActiveElems = NumOfElements;
4137 activeElem.SetSize(NumOfElements);
4140 GenerateActiveVertices();
4142 GenerateElementDofTable();
4143 GenerateActiveBdrElems();
4144 GenerateBdrElementDofTable();
4146 ConnectBoundaries();
4149void NURBSExtension::LoadSolution(std::istream &input, GridFunction &sol) const
4151 const FiniteElementSpace *fes = sol.FESpace();
4152 MFEM_VERIFY(fes->GetNURBSext() == this, "");
4154 sol.SetSize(fes->GetVSize());
4156 Array<const KnotVector *> kv(Dimension());
4157 NURBSPatchMap p2g(this);
4158 const int vdim = fes->GetVDim();
4160 for (int p = 0; p < GetNP(); p++)
4162 skip_comment_lines(input, '#');
4164 p2g.SetPatchDofMap(p, kv);
4165 const int nx = kv[0]->GetNCP();
4166 const int ny = kv[1]->GetNCP();
4167 const int nz = (kv.Size() == 2) ? 1 : kv[2]->GetNCP();
4168 for (int k = 0; k < nz; k++)
4170 for (int j = 0; j < ny; j++)
4172 for (int i = 0; i < nx; i++)
4174 const int ll = (kv.Size() == 2) ? p2g(i,j) : p2g(i,j,k);
4175 const int l = DofMap(ll);
4176 for (int vd = 0; vd < vdim; vd++)
4178 input >> sol(fes->DofToVDof(l,vd));
4186void NURBSExtension::PrintSolution(const GridFunction &sol, std::ostream &os)
4189 const FiniteElementSpace *fes = sol.FESpace();
4190 MFEM_VERIFY(fes->GetNURBSext() == this, "");
4192 Array<const KnotVector *> kv(Dimension());
4193 NURBSPatchMap p2g(this);
4194 const int vdim = fes->GetVDim();
4196 for (int p = 0; p < GetNP(); p++)
4198 os << "\n# patch
" << p << "\n\n
";
4200 p2g.SetPatchDofMap(p, kv);
4201 const int nx = kv[0]->GetNCP();
4202 const int ny = kv[1]->GetNCP();
4203 const int nz = (kv.Size() == 2) ? 1 : kv[2]->GetNCP();
4204 for (int k = 0; k < nz; k++)
4206 for (int j = 0; j < ny; j++)
4208 for (int i = 0; i < nx; i++)
4210 const int ll = (kv.Size() == 2) ? p2g(i,j) : p2g(i,j,k);
4211 const int l = DofMap(ll);
4212 os << sol(fes->DofToVDof(l,0));
4213 for (int vd = 1; vd < vdim; vd++)
4215 os << ' ' << sol(fes->DofToVDof(l,vd));
4224void NURBSExtension::DegreeElevate(int rel_degree, int degree)
4226 for (int p = 0; p < patches.Size(); p++)
4228 for (int dir = 0; dir < patches[p]->GetNKV(); dir++)
4230 int oldd = patches[p]->GetKV(dir)->GetOrder();
4231 int newd = std::min(oldd + rel_degree, degree);
4234 patches[p]->DegreeElevate(dir, newd - oldd);
4240void NURBSExtension::UniformRefinement(Array<int> const& rf)
4242 for (int p = 0; p < patches.Size(); p++)
4244 patches[p]->UniformRefinement(rf);
4248void NURBSExtension::UniformRefinement(int rf)
4250 Array<int> rf_array(Dimension());
4252 UniformRefinement(rf_array);
4255void NURBSExtension::Coarsen(Array<int> const& cf, real_t tol)
4257 // First, mark all knot vectors on all patches as not coarse. This prevents
4258 // coarsening the same knot vector twice.
4259 for (int p = 0; p < patches.Size(); p++)
4261 patches[p]->SetKnotVectorsCoarse(false);
4264 for (int p = 0; p < patches.Size(); p++)
4266 patches[p]->Coarsen(cf, tol);
4270void NURBSExtension::Coarsen(int cf, real_t tol)
4272 Array<int> cf_array(Dimension());
4274 Coarsen(cf_array, tol);
4277void NURBSExtension::GetCoarseningFactors(Array<int> & f) const
4280 for (auto patch : patches)
4283 patch->GetCoarseningFactors(pf);
4286 f = pf; // Initialize
4290 MFEM_VERIFY(f.Size() == pf.Size(), "");
4291 for (int i=0; i<f.Size(); ++i)
4293 MFEM_VERIFY(f[i] == pf[i] || f[i] == 1 || pf[i] == 1,
4294 "Inconsistent patch coarsening factors
");
4295 if (f[i] == 1 && pf[i] != 1)
4304void NURBSExtension::KnotInsert(Array<KnotVector *> &kv)
4310 Array<KnotVector *> pkv(Dimension());
4312 for (int p = 0; p < patches.Size(); p++)
4316 pkv[0] = kv[KnotInd(p)];
4318 else if (Dimension()==2)
4320 patchTopo->GetElementEdges(p, edges, orient);
4321 pkv[0] = kv[KnotInd(edges[0])];
4322 pkv[1] = kv[KnotInd(edges[1])];
4324 else if (Dimension()==3)
4326 patchTopo->GetElementEdges(p, edges, orient);
4327 pkv[0] = kv[KnotInd(edges[0])];
4328 pkv[1] = kv[KnotInd(edges[3])];
4329 pkv[2] = kv[KnotInd(edges[8])];
4332 // Check whether inserted knots should be flipped before inserting.
4333 // Knotvectors are stored in a different array pkvc such that the original
4334 // knots which are inserted are not changed.
4335 // We need those knots for multiple patches so they have to remain original
4336 CheckKVDirection(p, kvdir);
4338 Array<KnotVector *> pkvc(Dimension());
4339 for (int d = 0; d < Dimension(); d++)
4341 pkvc[d] = new KnotVector(*(pkv[d]));
4349 patches[p]->KnotInsert(pkvc);
4350 for (int d = 0; d < Dimension(); d++) { delete pkvc[d]; }
4354void NURBSExtension::KnotInsert(Array<Vector *> &kv)
4360 Array<Vector *> pkv(Dimension());
4362 for (int p = 0; p < patches.Size(); p++)
4366 pkv[0] = kv[KnotInd(p)];
4368 else if (Dimension()==2)
4370 patchTopo->GetElementEdges(p, edges, orient);
4371 pkv[0] = kv[KnotInd(edges[0])];
4372 pkv[1] = kv[KnotInd(edges[1])];
4374 else if (Dimension()==3)
4376 patchTopo->GetElementEdges(p, edges, orient);
4377 pkv[0] = kv[KnotInd(edges[0])];
4378 pkv[1] = kv[KnotInd(edges[3])];
4379 pkv[2] = kv[KnotInd(edges[8])];
4382 // Check whether inserted knots should be flipped before inserting.
4383 // Knotvectors are stored in a different array pkvc such that the original
4384 // knots which are inserted are not changed.
4385 CheckKVDirection(p, kvdir);
4387 Array<Vector *> pkvc(Dimension());
4388 for (int d = 0; d < Dimension(); d++)
4390 pkvc[d] = new Vector(*(pkv[d]));
4394 // Find flip point, for knotvectors that do not have the domain [0:1]
4395 KnotVector *kva = knotVectorsCompr[Dimension()*p+d];
4396 real_t apb = (*kva)[0] + (*kva)[kva->Size()-1];
4399 int size = pkvc[d]->Size();
4400 int ns = ceil(size/2.0);
4401 for (int j = 0; j < ns; j++)
4403 real_t tmp = apb - pkvc[d]->Elem(j);
4404 pkvc[d]->Elem(j) = apb - pkvc[d]->Elem(size-1-j);
4405 pkvc[d]->Elem(size-1-j) = tmp;
4410 patches[p]->KnotInsert(pkvc);
4412 for (int i = 0; i < Dimension(); i++) { delete pkvc[i]; }
4416void NURBSExtension::KnotRemove(Array<Vector *> &kv, real_t tol)
4422 Array<Vector *> pkv(Dimension());
4424 for (int p = 0; p < patches.Size(); p++)
4428 pkv[0] = kv[KnotInd(p)];
4430 else if (Dimension()==2)
4432 patchTopo->GetElementEdges(p, edges, orient);
4433 pkv[0] = kv[KnotInd(edges[0])];
4434 pkv[1] = kv[KnotInd(edges[1])];
4436 else if (Dimension()==3)
4438 patchTopo->GetElementEdges(p, edges, orient);
4439 pkv[0] = kv[KnotInd(edges[0])];
4440 pkv[1] = kv[KnotInd(edges[3])];
4441 pkv[2] = kv[KnotInd(edges[8])];
4444 // Check whether knots should be flipped before removing.
4445 CheckKVDirection(p, kvdir);
4447 Array<Vector *> pkvc(Dimension());
4448 for (int d = 0; d < Dimension(); d++)
4450 pkvc[d] = new Vector(*(pkv[d]));
4454 // Find flip point, for knotvectors that do not have the domain [0:1]
4455 KnotVector *kva = knotVectorsCompr[Dimension()*p+d];
4456 real_t apb = (*kva)[0] + (*kva)[kva->Size()-1];
4459 int size = pkvc[d]->Size();
4460 int ns = ceil(size/2.0);
4461 for (int j = 0; j < ns; j++)
4463 real_t tmp = apb - pkvc[d]->Elem(j);
4464 pkvc[d]->Elem(j) = apb - pkvc[d]->Elem(size-1-j);
4465 pkvc[d]->Elem(size-1-j) = tmp;
4470 patches[p]->KnotRemove(pkvc, tol);
4472 for (int i = 0; i < Dimension(); i++) { delete pkvc[i]; }
4476void NURBSExtension::GetPatchNets(const Vector &coords, int vdim)
4478 if (Dimension() == 1)
4480 Get1DPatchNets(coords, vdim);
4482 else if (Dimension() == 2)
4484 Get2DPatchNets(coords, vdim);
4488 Get3DPatchNets(coords, vdim);
4492void NURBSExtension::Get1DPatchNets(const Vector &coords, int vdim)
4494 Array<const KnotVector *> kv(1);
4495 NURBSPatchMap p2g(this);
4497 patches.SetSize(GetNP());
4498 for (int p = 0; p < GetNP(); p++)
4500 p2g.SetPatchDofMap(p, kv);
4501 patches[p] = new NURBSPatch(kv, vdim+1);
4502 NURBSPatch &Patch = *patches[p];
4504 for (int i = 0; i < kv[0]->GetNCP(); i++)
4506 const int l = DofMap(p2g(i));
4507 for (int d = 0; d < vdim; d++)
4509 Patch(i,d) = coords(l*vdim + d)*weights(l);
4511 Patch(i,vdim) = weights(l);
4517void NURBSExtension::Get2DPatchNets(const Vector &coords, int vdim)
4519 Array<const KnotVector *> kv(2);
4520 NURBSPatchMap p2g(this);
4522 patches.SetSize(GetNP());
4523 for (int p = 0; p < GetNP(); p++)
4525 p2g.SetPatchDofMap(p, kv);
4526 patches[p] = new NURBSPatch(kv, vdim+1);
4527 NURBSPatch &Patch = *patches[p];
4529 for (int j = 0; j < kv[1]->GetNCP(); j++)
4531 for (int i = 0; i < kv[0]->GetNCP(); i++)
4533 const int l = DofMap(p2g(i,j));
4534 for (int d = 0; d < vdim; d++)
4536 Patch(i,j,d) = coords(l*vdim + d)*weights(l);
4538 Patch(i,j,vdim) = weights(l);
4544void NURBSExtension::Get3DPatchNets(const Vector &coords, int vdim)
4546 Array<const KnotVector *> kv(3);
4547 NURBSPatchMap p2g(this);
4549 patches.SetSize(GetNP());
4550 for (int p = 0; p < GetNP(); p++)
4552 p2g.SetPatchDofMap(p, kv);
4553 patches[p] = new NURBSPatch(kv, vdim+1);
4554 NURBSPatch &Patch = *patches[p];
4556 for (int k = 0; k < kv[2]->GetNCP(); k++)
4558 for (int j = 0; j < kv[1]->GetNCP(); j++)
4560 for (int i = 0; i < kv[0]->GetNCP(); i++)
4562 const int l = DofMap(p2g(i,j,k));
4563 for (int d = 0; d < vdim; d++)
4565 Patch(i,j,k,d) = coords(l*vdim + d)*weights(l);
4567 Patch(i,j,k,vdim) = weights(l);
4574void NURBSExtension::SetSolutionVector(Vector &coords, int vdim)
4576 if (Dimension() == 1)
4578 Set1DSolutionVector(coords, vdim);
4580 else if (Dimension() == 2)
4582 Set2DSolutionVector(coords, vdim);
4586 Set3DSolutionVector(coords, vdim);
4590void NURBSExtension::Set1DSolutionVector(Vector &coords, int vdim)
4592 Array<const KnotVector *> kv(1);
4593 NURBSPatchMap p2g(this);
4595 weights.SetSize(GetNDof());
4596 for (int p = 0; p < GetNP(); p++)
4598 p2g.SetPatchDofMap(p, kv);
4599 NURBSPatch &patch = *patches[p];
4600 MFEM_ASSERT(vdim+1 == patch.GetNC(), "");
4602 for (int i = 0; i < kv[0]->GetNCP(); i++)
4604 const int l = p2g(i);
4605 for (int d = 0; d < vdim; d++)
4607 coords(l*vdim + d) = patch(i,d)/patch(i,vdim);
4609 weights(l) = patch(i,vdim);
4617void NURBSExtension::Set2DSolutionVector(Vector &coords, int vdim)
4619 Array<const KnotVector *> kv(2);
4620 NURBSPatchMap p2g(this);
4622 weights.SetSize(GetNDof());
4623 for (int p = 0; p < GetNP(); p++)
4625 p2g.SetPatchDofMap(p, kv);
4626 NURBSPatch &patch = *patches[p];
4627 MFEM_ASSERT(vdim+1 == patch.GetNC(), "");
4629 for (int j = 0; j < kv[1]->GetNCP(); j++)
4631 for (int i = 0; i < kv[0]->GetNCP(); i++)
4633 const int l = p2g(i,j);
4634 for (int d = 0; d < vdim; d++)
4636 coords(l*vdim + d) = patch(i,j,d)/patch(i,j,vdim);
4638 weights(l) = patch(i,j,vdim);
4645void NURBSExtension::Set3DSolutionVector(Vector &coords, int vdim)
4647 Array<const KnotVector *> kv(3);
4648 NURBSPatchMap p2g(this);
4650 weights.SetSize(GetNDof());
4651 for (int p = 0; p < GetNP(); p++)
4653 p2g.SetPatchDofMap(p, kv);
4654 NURBSPatch &patch = *patches[p];
4655 MFEM_ASSERT(vdim+1 == patch.GetNC(), "");
4657 for (int k = 0; k < kv[2]->GetNCP(); k++)
4659 for (int j = 0; j < kv[1]->GetNCP(); j++)
4661 for (int i = 0; i < kv[0]->GetNCP(); i++)
4663 const int l = p2g(i,j,k);
4664 for (int d = 0; d < vdim; d++)
4666 coords(l*vdim + d) = patch(i,j,k,d)/patch(i,j,k,vdim);
4668 weights(l) = patch(i,j,k,vdim);
4676void NURBSExtension::GetElementIJK(int elem, Array<int> & ijk)
4678 MFEM_VERIFY(ijk.Size() == el_to_IJK.NumCols(), "");
4679 el_to_IJK.GetRow(elem, ijk);
4682void NURBSExtension::SetPatchToElements()
4684 const int np = GetNP();
4685 patch_to_el.resize(np);
4687 for (int e=0; e<el_to_patch.Size(); ++e)
4689 patch_to_el[el_to_patch[e]].Append(e);
4693void NURBSExtension::SetPatchToBdrElements()
4695 const int nbp = GetNBP();
4696 patch_to_bel.resize(nbp);
4698 for (int e=0; e<bel_to_patch.Size(); ++e)
4700 patch_to_bel[bel_to_patch[e]].Append(e);
4704const Array<int>& NURBSExtension::GetPatchElements(int patch)
4706 MFEM_ASSERT(patch_to_el.size() > 0, "patch_to_el not set
");
4708 return patch_to_el[patch];
4711const Array<int>& NURBSExtension::GetPatchBdrElements(int patch)
4713 MFEM_ASSERT(patch_to_bel.size() > 0, "patch_to_el not set
");
4715 return patch_to_bel[patch];
4719ParNURBSExtension::ParNURBSExtension(const ParNURBSExtension &orig)
4720 : NURBSExtension(orig),
4721 partitioning(orig.partitioning ? new int[orig.GetGNE()] : NULL),
4723 ldof_group(orig.ldof_group)
4725 // Copy the partitioning, if not NULL
4728 std::memcpy(partitioning, orig.partitioning, orig.GetGNE()*sizeof(int));
4732ParNURBSExtension::ParNURBSExtension(MPI_Comm comm, NURBSExtension *parent,
4733 int *part, const Array<bool> &active_bel)
4736 if (parent->NumOfActiveElems < parent->NumOfElements)
4738 // SetActive (BuildGroups?) and the way the weights are copied
4739 // do not support this case
4741 " all elements in the parent must be active!
");
4744 patchTopo = parent->patchTopo;
4745 // steal ownership of patchTopo from the 'parent' NURBS extension
4746 if (!parent->own_topo)
4749 " parent does not own the patch topology!
");
4752 parent->own_topo = 0;
4754 parent->edge_to_knot.Copy(edge_to_knot);
4756 parent->GetOrders().Copy(mOrders);
4757 mOrder = parent->GetOrder();
4759 NumOfKnotVectors = parent->GetNKV();
4760 knotVectors.SetSize(NumOfKnotVectors);
4761 for (int i = 0; i < NumOfKnotVectors; i++)
4763 knotVectors[i] = new KnotVector(*parent->GetKnotVector(i));
4765 CreateComprehensiveKV();
4771 // copy 'part' to 'partitioning'
4772 partitioning = new int[GetGNE()];
4773 for (int i = 0; i < GetGNE(); i++)
4775 partitioning[i] = part[i];
4777 SetActive(partitioning, active_bel);
4779 GenerateActiveVertices();
4780 GenerateElementDofTable();
4781 // GenerateActiveBdrElems(); // done by SetActive for now
4782 GenerateBdrElementDofTable();
4784 Table *serial_elem_dof = parent->GetElementDofTable();
4785 BuildGroups(partitioning, *serial_elem_dof);
4787 weights.SetSize(GetNDof());
4788 // copy weights from parent
4789 for (int gel = 0, lel = 0; gel < GetGNE(); gel++)
4791 if (activeElem[gel])
4793 int ndofs = el_dof->RowSize(lel);
4794 int *ldofs = el_dof->GetRow(lel);
4795 int *gdofs = serial_elem_dof->GetRow(gel);
4796 for (int i = 0; i < ndofs; i++)
4798 weights(ldofs[i]) = parent->weights(gdofs[i]);
4805ParNURBSExtension::ParNURBSExtension(NURBSExtension *parent,
4806 const ParNURBSExtension *par_parent)
4807 : gtopo(par_parent->gtopo.GetComm())
4809 // steal all data from parent
4810 mOrder = parent->mOrder;
4811 Swap(mOrders, parent->mOrders);
4813 patchTopo = parent->patchTopo;
4814 own_topo = parent->own_topo;
4815 parent->own_topo = 0;
4817 Swap(edge_to_knot, parent->edge_to_knot);
4819 NumOfKnotVectors = parent->NumOfKnotVectors;
4820 Swap(knotVectors, parent->knotVectors);
4821 Swap(knotVectorsCompr, parent->knotVectorsCompr);
4823 NumOfVertices = parent->NumOfVertices;
4824 NumOfElements = parent->NumOfElements;
4825 NumOfBdrElements = parent->NumOfBdrElements;
4826 NumOfDofs = parent->NumOfDofs;
4828 Swap(v_meshOffsets, parent->v_meshOffsets);
4829 Swap(e_meshOffsets, parent->e_meshOffsets);
4830 Swap(f_meshOffsets, parent->f_meshOffsets);
4831 Swap(p_meshOffsets, parent->p_meshOffsets);
4833 Swap(v_spaceOffsets, parent->v_spaceOffsets);
4834 Swap(e_spaceOffsets, parent->e_spaceOffsets);
4835 Swap(f_spaceOffsets, parent->f_spaceOffsets);
4836 Swap(p_spaceOffsets, parent->p_spaceOffsets);
4838 Swap(d_to_d, parent->d_to_d);
4839 Swap(master, parent->master);
4840 Swap(slave, parent->slave);
4842 NumOfActiveVertices = parent->NumOfActiveVertices;
4843 NumOfActiveElems = parent->NumOfActiveElems;
4844 NumOfActiveBdrElems = parent->NumOfActiveBdrElems;
4845 NumOfActiveDofs = parent->NumOfActiveDofs;
4847 Swap(activeVert, parent->activeVert);
4848 Swap(activeElem, parent->activeElem);
4849 Swap(activeBdrElem, parent->activeBdrElem);
4850 Swap(activeDof, parent->activeDof);
4852 el_dof = parent->el_dof;
4853 bel_dof = parent->bel_dof;
4854 parent->el_dof = parent->bel_dof = NULL;
4856 Swap(el_to_patch, parent->el_to_patch);
4857 Swap(bel_to_patch, parent->bel_to_patch);
4858 Swap(el_to_IJK, parent->el_to_IJK);
4859 Swap(bel_to_IJK, parent->bel_to_IJK);
4861 Swap(weights, parent->weights);
4862 MFEM_VERIFY(!parent->HavePatches(), "");
4866 partitioning = NULL;
4868 MFEM_VERIFY(par_parent->partitioning,
4871 // Support for the case when 'parent' is not a local NURBSExtension, i.e.
4872 // NumOfActiveElems is not the same as in 'par_parent'. In that case, we
4873 // assume 'parent' is a global NURBSExtension, i.e. all elements are active.
4874 bool extract_weights = false;
4875 if (NumOfActiveElems != par_parent->NumOfActiveElems)
4877 MFEM_ASSERT(NumOfActiveElems == NumOfElements, "internal error
");
4879 SetActive(par_parent->partitioning, par_parent->activeBdrElem);
4880 GenerateActiveVertices();
4882 el_to_patch.DeleteAll();
4883 el_to_IJK.DeleteAll();
4884 GenerateElementDofTable();
4885 // GenerateActiveBdrElems(); // done by SetActive for now
4887 bel_to_patch.DeleteAll();
4888 bel_to_IJK.DeleteAll();
4889 GenerateBdrElementDofTable();
4890 extract_weights = true;
4893 Table *glob_elem_dof = GetGlobalElementDofTable();
4894 BuildGroups(par_parent->partitioning, *glob_elem_dof);
4895 if (extract_weights)
4897 Vector glob_weights;
4898 Swap(weights, glob_weights);
4899 weights.SetSize(GetNDof());
4900 // Copy the local 'weights' from the 'glob_weights'.
4901 // Assumption: the local element ids follow the global ordering.
4902 for (int gel = 0, lel = 0; gel < GetGNE(); gel++)
4904 if (activeElem[gel])
4906 int ndofs = el_dof->RowSize(lel);
4907 int *ldofs = el_dof->GetRow(lel);
4908 int *gdofs = glob_elem_dof->GetRow(gel);
4909 for (int i = 0; i < ndofs; i++)
4911 weights(ldofs[i]) = glob_weights(gdofs[i]);
4917 delete glob_elem_dof;
4920Table *ParNURBSExtension::GetGlobalElementDofTable()
4922 if (Dimension() == 1)
4924 return Get1DGlobalElementDofTable();
4926 else if (Dimension() == 2)
4928 return Get2DGlobalElementDofTable();
4932 return Get3DGlobalElementDofTable();
4936Table *ParNURBSExtension::Get1DGlobalElementDofTable()
4939 const KnotVector *kv[1];
4940 NURBSPatchMap p2g(this);
4941 Array<Connection> gel_dof_list;
4943 for (int p = 0; p < GetNP(); p++)
4945 p2g.SetPatchDofMap(p, kv);
4948 const int ord0 = kv[0]->GetOrder();
4950 for (int i = 0; i < kv[0]->GetNKS(); i++)
4952 if (kv[0]->isElement(i))
4954 Connection conn(el,0);
4955 for (int ii = 0; ii <= ord0; ii++)
4957 conn.to = DofMap(p2g(i+ii));
4958 gel_dof_list.Append(conn);
4964 // We must NOT sort gel_dof_list in this case.
4965 return (new Table(GetGNE(), gel_dof_list));
4968Table *ParNURBSExtension::Get2DGlobalElementDofTable()
4971 const KnotVector *kv[2];
4972 NURBSPatchMap p2g(this);
4973 Array<Connection> gel_dof_list;
4975 for (int p = 0; p < GetNP(); p++)
4977 p2g.SetPatchDofMap(p, kv);
4980 const int ord0 = kv[0]->GetOrder();
4981 const int ord1 = kv[1]->GetOrder();
4982 for (int j = 0; j < kv[1]->GetNKS(); j++)
4984 if (kv[1]->isElement(j))
4986 for (int i = 0; i < kv[0]->GetNKS(); i++)
4988 if (kv[0]->isElement(i))
4990 Connection conn(el,0);
4991 for (int jj = 0; jj <= ord1; jj++)
4993 for (int ii = 0; ii <= ord0; ii++)
4995 conn.to = DofMap(p2g(i+ii,j+jj));
4996 gel_dof_list.Append(conn);
5005 // We must NOT sort gel_dof_list in this case.
5006 return (new Table(GetGNE(), gel_dof_list));
5009Table *ParNURBSExtension::Get3DGlobalElementDofTable()
5012 const KnotVector *kv[3];
5013 NURBSPatchMap p2g(this);
5014 Array<Connection> gel_dof_list;
5016 for (int p = 0; p < GetNP(); p++)
5018 p2g.SetPatchDofMap(p, kv);
5021 const int ord0 = kv[0]->GetOrder();
5022 const int ord1 = kv[1]->GetOrder();
5023 const int ord2 = kv[2]->GetOrder();
5024 for (int k = 0; k < kv[2]->GetNKS(); k++)
5026 if (kv[2]->isElement(k))
5028 for (int j = 0; j < kv[1]->GetNKS(); j++)
5030 if (kv[1]->isElement(j))
5032 for (int i = 0; i < kv[0]->GetNKS(); i++)
5034 if (kv[0]->isElement(i))
5036 Connection conn(el,0);
5037 for (int kk = 0; kk <= ord2; kk++)
5039 for (int jj = 0; jj <= ord1; jj++)
5041 for (int ii = 0; ii <= ord0; ii++)
5043 conn.to = DofMap(p2g(i+ii,j+jj,k+kk));
5044 gel_dof_list.Append(conn);
5056 // We must NOT sort gel_dof_list in this case.
5057 return (new Table(GetGNE(), gel_dof_list));
5060void ParNURBSExtension::SetActive(const int *partitioning_,
5061 const Array<bool> &active_bel)
5063 activeElem.SetSize(GetGNE());
5065 NumOfActiveElems = 0;
5066 const int MyRank = gtopo.MyRank();
5067 for (int i = 0; i < GetGNE(); i++)
5068 if (partitioning_[i] == MyRank)
5070 activeElem[i] = true;
5074 active_bel.Copy(activeBdrElem);
5075 NumOfActiveBdrElems = 0;
5076 for (int i = 0; i < GetGNBE(); i++)
5077 if (activeBdrElem[i])
5079 NumOfActiveBdrElems++;
5083void ParNURBSExtension::BuildGroups(const int *partitioning_,
5084 const Table &elem_dof)
5088 ListOfIntegerSets groups;
5091 Transpose(elem_dof, dof_proc); // dof_proc is dof_elem
5092 // convert elements to processors
5093 for (int i = 0; i < dof_proc.Size_of_connections(); i++)
5095 dof_proc.GetJ()[i] = partitioning_[dof_proc.GetJ()[i]];
5098 // the first group is the local one
5099 int MyRank = gtopo.MyRank();
5100 group.Recreate(1, &MyRank);
5101 groups.Insert(group);
5104 ldof_group.SetSize(GetNDof());
5105 for (int d = 0; d < GetNTotalDof(); d++)
5108 group.Recreate(dof_proc.RowSize(d), dof_proc.GetRow(d));
5109 ldof_group[dof] = groups.Insert(group);
5114 gtopo.Create(groups, 1822);
5116#endif // MFEM_USE_MPI
5119void NURBSPatchMap::GetPatchKnotVectors(int p, const KnotVector *kv[])
5121 Ext->patchTopo->GetElementVertices(p, verts);
5123 if (Ext->Dimension() == 1)
5125 kv[0] = Ext->knotVectorsCompr[Ext->Dimension()*p];
5127 else if (Ext->Dimension() == 2)
5129 Ext->patchTopo->GetElementEdges(p, edges, oedge);
5131 kv[0] = Ext->knotVectorsCompr[Ext->Dimension()*p];
5132 kv[1] = Ext->knotVectorsCompr[Ext->Dimension()*p + 1];
5134 else if (Ext->Dimension() == 3)
5136 Ext->patchTopo->GetElementEdges(p, edges, oedge);
5137 Ext->patchTopo->GetElementFaces(p, faces, oface);
5139 kv[0] = Ext->knotVectorsCompr[Ext->Dimension()*p];
5140 kv[1] = Ext->knotVectorsCompr[Ext->Dimension()*p + 1];
5141 kv[2] = Ext->knotVectorsCompr[Ext->Dimension()*p + 2];
5146void NURBSPatchMap::GetBdrPatchKnotVectors(int p, const KnotVector *kv[],
5149 Ext->patchTopo->GetBdrElementVertices(p, verts);
5151 if (Ext->Dimension() == 2)
5153 Ext->patchTopo->GetBdrElementEdges(p, edges, oedge);
5154 kv[0] = Ext->KnotVec(edges[0], oedge[0], &okv[0]);
5157 else if (Ext->Dimension() == 3)
5160 Ext->patchTopo->GetBdrElementEdges(p, edges, oedge);
5161 Ext->patchTopo->GetBdrElementFace(p, &faces[0], &opatch);
5163 kv[0] = Ext->KnotVec(edges[0], oedge[0], &okv[0]);
5164 kv[1] = Ext->KnotVec(edges[1], oedge[1], &okv[1]);
5169void NURBSPatchMap::SetPatchVertexMap(int p, const KnotVector *kv[])
5171 GetPatchKnotVectors(p, kv);
5173 I = kv[0]->GetNE() - 1;
5175 for (int i = 0; i < verts.Size(); i++)
5177 verts[i] = Ext->v_meshOffsets[verts[i]];
5180 if (Ext->Dimension() >= 2)
5182 J = kv[1]->GetNE() - 1;
5183 for (int i = 0; i < edges.Size(); i++)
5185 edges[i] = Ext->e_meshOffsets[edges[i]];
5188 if (Ext->Dimension() == 3)
5190 K = kv[2]->GetNE() - 1;
5192 for (int i = 0; i < faces.Size(); i++)
5194 faces[i] = Ext->f_meshOffsets[faces[i]];
5198 pOffset = Ext->p_meshOffsets[p];
5201void NURBSPatchMap::SetPatchDofMap(int p, const KnotVector *kv[])
5203 GetPatchKnotVectors(p, kv);
5205 I = kv[0]->GetNCP() - 2;
5207 for (int i = 0; i < verts.Size(); i++)
5209 verts[i] = Ext->v_spaceOffsets[verts[i]];
5211 if (Ext->Dimension() >= 2)
5213 J = kv[1]->GetNCP() - 2;
5214 for (int i = 0; i < edges.Size(); i++)
5216 edges[i] = Ext->e_spaceOffsets[edges[i]];
5219 if (Ext->Dimension() == 3)
5221 K = kv[2]->GetNCP() - 2;
5223 for (int i = 0; i < faces.Size(); i++)
5225 faces[i] = Ext->f_spaceOffsets[faces[i]];
5229 pOffset = Ext->p_spaceOffsets[p];
5232void NURBSPatchMap::SetBdrPatchVertexMap(int p, const KnotVector *kv[],
5235 GetBdrPatchKnotVectors(p, kv, okv);
5237 for (int i = 0; i < verts.Size(); i++)
5239 verts[i] = Ext->v_meshOffsets[verts[i]];
5242 if (Ext->Dimension() == 1)
5246 else if (Ext->Dimension() == 2)
5248 I = kv[0]->GetNE() - 1;
5249 pOffset = Ext->e_meshOffsets[edges[0]];
5251 else if (Ext->Dimension() == 3)
5253 I = kv[0]->GetNE() - 1;
5254 J = kv[1]->GetNE() - 1;
5256 for (int i = 0; i < edges.Size(); i++)
5258 edges[i] = Ext->e_meshOffsets[edges[i]];
5261 pOffset = Ext->f_meshOffsets[faces[0]];
5265void NURBSPatchMap::SetBdrPatchDofMap(int p, const KnotVector *kv[], int *okv)
5267 GetBdrPatchKnotVectors(p, kv, okv);
5269 for (int i = 0; i < verts.Size(); i++)
5271 verts[i] = Ext->v_spaceOffsets[verts[i]];
5274 if (Ext->Dimension() == 1)
5278 else if (Ext->Dimension() == 2)
5280 I = kv[0]->GetNCP() - 2;
5281 pOffset = Ext->e_spaceOffsets[edges[0]];
5283 else if (Ext->Dimension() == 3)
5285 I = kv[0]->GetNCP() - 2;
5286 J = kv[1]->GetNCP() - 2;
5288 for (int i = 0; i < edges.Size(); i++)
5290 edges[i] = Ext->e_spaceOffsets[edges[i]];
5293 pOffset = Ext->f_spaceOffsets[faces[0]];
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
void CalcDnShape(Vector &gradn, int n, int i, real_t xi) const
KnotVector & operator=(const KnotVector &kv)
void UniformRefinement(Vector &newknots, int rf) const
Refine uniformly with refinement factor rf.
bool isElement(int i) const
void CalcShape(Vector &shape, int i, real_t xi) const
void GetElements()
Count the number of elements.
KnotVector * DegreeElevate(int t) const
void Refinement(Vector &newknots, int rf) const
Refine with refinement factor rf.
KnotVector()
Create KnotVector.
static const int MaxOrder
void CalcD2Shape(Vector &grad2, int i, real_t xi) const
void CalcDShape(Vector &grad, int i, real_t xi) const
void Difference(const KnotVector &kv, Vector &diff) const
Finds the knots in the larger of this and kv, not contained in the other.
int GetCoarseningFactor() const
Vector GetFineKnots(const int cf) const
void Print(std::ostream &os) const
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)