53 const std::string &basename,
bool visualization =
false,
54 int x = 0,
int y = 0,
int w = 500,
int h = 500);
58class SurfaceInterpolator
62 SurfaceInterpolator(
int num_elem_x,
int num_elem_y,
int order);
69 void SampleSurface(
int num_elem_x,
int num_elem_y,
bool compareOriginal,
74 void WriteNURBSMesh(
const std::string &basename,
bool visualization =
false,
75 int x = 0,
int y = 0,
int w = 500,
int h = 500);
89 static constexpr int dim = 3;
93 std::vector<Vector> ugrid;
95 std::vector<KnotVector> kv;
97 std::unique_ptr<NURBSPatch> patch;
100 std::vector<Mesh> cmesh;
104int main(
int argc,
char *argv[])
113 bool visualization =
true;
114 bool compareOriginal =
false;
118 args.
AddOption(&example,
"-ex",
"--example",
121 "Number of elements in x");
123 "Number of elements in y");
125 "Number of resampled elements in x");
127 "Number of resampled elements in y");
129 "NURBS finite element order (polynomial degree)");
130 args.
AddOption(&visualization,
"-vis",
"--visualization",
"-no-vis",
131 "--no-visualization",
132 "Enable or disable GLVis visualization.");
133 args.
AddOption(&compareOriginal,
"-orig",
"--compare-original",
"-no-orig",
134 "--no-compare-original",
135 "Compare to the original mesh?");
136 args.
AddOption(&jitter,
"-j",
"--jitter",
137 "Relative jittering in (0,1) to add to the input point "
138 "coordinates on a uniform nx x ny grid (0 by default)");
147 if (compareOriginal && (fnx != nx || fny != ny))
149 cout <<
"Comparing to the original mesh requires the same number of "
155 cout <<
"Input Surface: " << nx <<
" x " << ny <<
" linear elements\n";
156 cout <<
"NURBS Surface: " << nx + 1 - order <<
" x " << ny + 1 - order
157 <<
" knot elements of order " << order <<
"\n";
158 cout <<
"Output Surface: " << fnx <<
" x " << fny <<
" linear elements\n";
161 constexpr int dim = 3;
167 SurfaceInterpolator surf(nx, ny, order);
168 surf.CreateSurface(input3D);
173 surf.SampleSurface(fnx, fny, compareOriginal, output3D);
176 WriteLinearMesh(nx, ny, input3D,
"Input-Surface", visualization, 0, 0);
177 surf.WriteNURBSMesh(
"NURBS-Surface", visualization, 502, 0);
178 WriteLinearMesh(fnx, fny, output3D,
"Output-Surface", visualization, 1004, 0);
188 z = sin(2.0 * M_PI *
u) * sin(2.0 * M_PI * v);
195 constexpr real_t pi_4 = M_PI * 0.25;
196 constexpr real_t phi0 = -3*pi_4;
197 constexpr real_t phi1 = 3*pi_4;
198 constexpr real_t theta0 = pi_4;
199 constexpr real_t theta1 = 3 * pi_4;
201 const real_t phi = (phi0 * (1.0 - v)) + (phi1 * v);
202 const real_t theta = (theta0 * (1.0 -
u)) + (theta1 *
u);
203 x = r * sin(theta) * cos(phi);
204 y = r * sin(theta) * sin(phi);
211 x =
u * cos(2.0 * M_PI * v);
212 y =
u * sin(2.0 * M_PI * v);
219 constexpr int twists = 1;
220 const real_t a = 1.0 + 0.5 * ((2.0 * v) - 1.0) * cos(2.0 * M_PI * twists *
u);
221 x =
a * cos(2.0 * M_PI *
u);
222 y =
a * sin(2.0 * M_PI *
u);
223 z = 0.5 * (2.0 * v - 1.0) * sin(2.0 * M_PI * twists *
u);
229 const real_t m = 13.2 * ((2.0 *
u) - 1.0);
230 const real_t n = 37.4 * ((2.0 * v) - 1.0);
234 const real_t denom =
b * (pow(w*cosh(
b*m),2) + pow(
b*sin(w*n),2));
235 x = -m + (2*r*cosh(
b*m)*sinh(
b*m)) / denom;
236 y = (2*w*cosh(
b*m)*(-(w*cos(n)*cos(w*n)) - sin(n)*sin(w*n))) / denom;
237 z = (2*w*cosh(
b*m)*(-(w*sin(n)*cos(w*n)) + cos(n)*sin(w*n))) / denom;
266 int seed = (int)time(0);
267 srand((
unsigned)seed);
269 real_t h0 = grid[0][1]-grid[0][0], h1 = grid[1][1]-grid[1][0];
270 for (
int i = 0; i < grid[0].Size(); i++)
272 for (
int j = 0; j < grid[1].Size(); j++)
274 if (i != 0 && i != grid[0].Size()-1 && j != 0 && j != grid[1].Size()-1)
278 v3D(i, j, 0), v3D(i, j, 1), v3D(i, j, 2));
283 v3D(i, j, 0), v3D(i, j, 1), v3D(i, j, 2));
293 std::vector<Vector> uniformGrid(2);
294 for (
int i = 0; i < 2; ++i)
296 const int n = (i == 0) ? nx : ny;
298 uniformGrid[i].SetSize(n + 1);
299 for (
int j = 0; j <= n; ++j) { uniformGrid[i][j] = j * h; }
307 const std::string &basename,
bool visualization,
308 int x,
int y,
int w,
int h)
310 const int nv = (nx + 1) * (ny + 1);
311 const int nelem = nx * ny;
312 constexpr int dim = 3;
314 Mesh lmesh(2, nv, nelem, 0,
dim);
317 for (
int i = 0; i <= nx; ++i)
319 for (
int j = 0; j <= ny; ++j)
321 for (
int k = 0; k <
dim; ++k) { vertex[k] = v(i, j, k); }
328 auto vID = [&](
int i,
int j)
330 return j + (i * (ny + 1));
333 for (
int i = 0; i < nx; ++i)
335 for (
int j = 0; j < ny; ++j)
337 verts[0] = vID(i, j);
338 verts[1] = vID(i+1, j);
339 verts[2] = vID(i+1, j+1);
340 verts[3] = vID(i, j+1);
350 ofstream mesh_ofs(basename +
".mesh");
351 mesh_ofs.precision(8);
352 lmesh.
Print(mesh_ofs);
357 constexpr int visport = 19916;
359 sol_sock.precision(8);
360 sol_sock <<
"mesh\n" << lmesh
361 <<
"window_title '" << basename <<
"'"
362 <<
"window_geometry "
363 << x <<
" " << y <<
" " << w <<
" " << h <<
"\n"
364 <<
"keys PPPPPPPPAattttt******\n"
375 for (
int i = 0; i <= nx; ++i)
377 for (
int j = 0; j <= ny; ++j)
379 const real_t err_ij = std::abs(
a(i, j, c) -
b(i, j, 2));
380 maxErr = std::max(maxErr, err_ij);
384 cout <<
"Max error: " << maxErr <<
" for coordinate " << c << endl;
390 const Array<int> &nks,
const std::vector<Vector> &ugrid,
405 for (
int i = 0; i <= nx; ++i)
407 const real_t xref = uniform ? i * hx : ugrid[0][i];
408 const int nurbsElem0 = std::min((
int) (xref / hxks), nks[0] - 1);
409 const real_t ipx = (xref - (nurbsElem0 * hxks)) / hxks;
412 for (
int j = 0; j <= ny; ++j)
414 const real_t yref = uniform ? j * hy : ugrid[1][j];
415 const int nurbsElem1 = std::min((
int) (yref / hyks), nks[1] - 1);
416 const real_t ipy = (yref - (nurbsElem1 * hyks)) / hyks;
419 const int nurbsElem = nurbsElem0 + (nurbsElem1 * nks[0]);
420 nodes->GetVectorValue(nurbsElem, ip, vertex);
422 for (
int k = 0; k < 3; ++k)
424 vpos(i, j, k) = vertex[k];
431SurfaceInterpolator::SurfaceInterpolator(
int num_elem_x,
int num_elem_y,
433 nx(num_elem_x), ny(num_elem_y), orderNURBS(order),
440 for (
int i = 0; i <
dim; ++i)
442 nks[i] = ncp[i] - order;
447 intervals = 1.0 / (
real_t) nks[i];
448 continuity = order - 1;
450 continuity[nks[i]] = -1;
452 kv.emplace_back(order, intervals, continuity);
455 patch.reset(
new NURBSPatch(&kv[0], &kv[1], &kv[2],
dim + 1));
457 hx = 1.0 / (
real_t) (ncp[0] - 1);
458 hy = 1.0 / (
real_t) (ncp[1] - 1);
459 hz = 1.0 / (
real_t) (ncp[2] - 1);
463 for (
int i = 0; i < 2; ++i)
465 kv[i].FindMaxima(i_args, xi_args, ugrid[i]);
472 for (
int c = 0; c <
dim; ++c)
474 ComputeNURBS(c, input3D);
475 cmesh.emplace_back(mesh);
481void SurfaceInterpolator::SampleSurface(
int num_elem_x,
int num_elem_y,
482 bool compareOriginal,
486 for (
int c = 0; c <
dim; ++c)
488 SampleNURBS(
true, num_elem_x, num_elem_y, cmesh[c], nks, ugrid, vpos);
492 SampleNURBS(
false, num_elem_x, num_elem_y, cmesh[c], nks, ugrid, vpos);
496 for (
int i = 0; i <= num_elem_x; ++i)
498 for (
int j = 0; j <= num_elem_y; ++j)
500 output3D(i,j,c) = vpos(i,j,2);
506void SurfaceInterpolator::ComputeNURBS(
int coordinate,
512 for (
int k = 0; k < ncp[2]; ++k)
521 for (
int i = 0; i <
dim; ++i) { x[i]->
SetSize(ncp[0]); }
524 for (
int j = 0; j < ncp[1]; ++j)
526 for (
int i = 0; i < ncp[0]; i++)
528 (*x[0])[i] = ugrid[0][i];
529 (*x[1])[i] = ugrid[1][j];
531 const real_t s_ij = input3D(i, j, coordinate);
532 (*x[2])[i] = -1.0 + z + s_ij;
535 const bool reuse_factorization = j > 0;
536 kv[0].FindInterpolant(x, reuse_factorization);
538 for (
int i = 0; i < ncp[0]; i++)
540 (*patch)(i,j,k,0) = (*x[0])[i];
541 (*patch)(i,j,k,1) = (*x[1])[i];
542 (*patch)(i,j,k,2) = (*x[2])[i];
543 (*patch)(i,j,k,3) = 1.0;
548 for (
int i = 0; i <
dim; ++i) { x[i]->
SetSize(ncp[1]); }
551 for (
int i = 0; i < ncp[0]; i++)
553 for (
int j = 0; j < ncp[1]; ++j)
555 (*x[0])[j] = (*patch)(i,j,k,0);
556 (*x[1])[j] = (*patch)(i,j,k,1);
557 (*x[2])[j] = (*patch)(i,j,k,2);
560 const bool reuse_factorization = i > 0;
561 kv[1].FindInterpolant(x, reuse_factorization);
563 for (
int j = 0; j < ncp[1]; ++j)
565 (*patch)(i,j,k,0) = (*x[0])[j];
566 (*patch)(i,j,k,1) = (*x[1])[j];
567 (*patch)(i,j,k,2) = (*x[2])[j];
572 for (
auto p : x) {
delete p; }
575 patches[0] = patch.get();
579 mesh =
Mesh(nurbsExt);
582void SurfaceInterpolator::WriteNURBSMesh(
const std::string &basename,
584 int x,
int y,
int w,
int h)
589 patches[0] = &patch2D;
592 cmesh[0].NURBSext->GetPatchDofs(0, dofs);
594 MFEM_VERIFY(dofs.
Size() == (nx + 1) * (ny + 1) * (orderNURBS + 1),
"");
596 for (
int j = 0; j < ncp[1]; ++j)
598 for (
int i = 0; i < ncp[0]; i++)
600 const int dof = dofs[i + (ncp[0] * (j + (ncp[1] * orderNURBS)))];
601 for (
int k = 0; k < 2; ++k) { patch2D(i,j,k) = (*nodes)[
dim*dof + k]; }
602 patch2D(i,j,2) = 1.0;
607 Mesh mesh2D(nurbsExt);
613 const int n = mesh2D.GetNodes()->Size() / (
dim - 1);
614 MFEM_VERIFY((dim - 1) * n == mesh2D.GetNodes()->Size(),
"");
615 MFEM_VERIFY(dim * n == nodes2D.Size(),
"");
618 mesh2D.NURBSext->GetPatchDofs(0, dofs2D);
620 for (
int k = 0; k <
dim; ++k)
624 for (
int j = 0; j < ncp[1]; ++j)
626 for (
int i = 0; i < ncp[0]; i++)
628 const int dof = dofs[i + (ncp[0] * (j + (ncp[1] * orderNURBS)))];
629 const int dof2D = dofs2D[i + (ncp[0] * j)];
630 nodes2D[(
dim*dof2D) + k] = nodes_k[dim*dof + 2];
636 mesh2D.NewNodes(nodes2D);
638 ofstream mesh_ofs(basename +
".mesh");
639 mesh_ofs.precision(8);
640 mesh2D.Print(mesh_ofs);
645 constexpr int visport = 19916;
647 sol_sock.precision(8);
648 sol_sock <<
"mesh\n" << mesh2D
649 <<
"window_title '" << basename <<
"'"
650 <<
"window_geometry "
651 << x <<
" " << y <<
" " << w <<
" " << h <<
"\n"
652 <<
"keys PPPPPPPPAattttt******\n"
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Abstract data type element.
virtual void SetVertices(const Array< int > &v)=0
Set the indices defining the vertices.
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Class for grid function - Vector with associated FE space.
Class for integration point with weight.
Element * NewElement(int geom)
void FinalizeTopology(bool generate_bdr=true)
Finalize the construction of the secondary topology (connectivity) data of a Mesh.
virtual void Print(std::ostream &os=mfem::out, const std::string &comments="") const
Print the mesh to the given stream using the default MFEM mesh format.
int AddVertex(real_t x, real_t y=0.0, real_t z=0.0)
int AddElement(Element *elem)
static Mesh MakeCartesian3D(int nx, int ny, int nz, Element::Type type, real_t sx=1.0, real_t sy=1.0, real_t sz=1.0, bool sfc_ordering=true)
Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz], divided into nx*ny*nz hexahedra if type =...
void GetNodes(Vector &node_coord) const
static Mesh MakeCartesian2D(int nx, int ny, Element::Type type, bool generate_edges=false, real_t sx=1.0, real_t sy=1.0, bool sfc_ordering=true)
Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny quadrilaterals if type = QUADRILATER...
NURBSExtension generally contains multiple NURBSPatch objects spanning an entire Mesh....
A NURBS patch can be 1D, 2D, or 3D, and is defined as a tensor product of KnotVectors.
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
void PrintUsage(std::ostream &out) const
Print the usage message.
void PrintOptions(std::ostream &out) const
Print the options.
void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, bool required=false)
Add a boolean option and set 'var' to receive the value. Enable/disable tags are used to set the bool...
bool Good() const
Return true if the command line options were parsed successfully.
real_t u(const Vector &xvec)
real_t rand_real()
Generate a random real_t number in the interval [0,1) using rand().
real_t p(const Vector &x, real_t t)
void Function4(real_t u, real_t v, real_t &x, real_t &y, real_t &z)
void SurfaceExample(int example, const std::vector< Vector > &grid, Array3D< real_t > &v3D, real_t jitter)
void WriteLinearMesh(int nx, int ny, const Array3D< real_t > &v, const std::string &basename, bool visualization=false, int x=0, int y=0, int w=500, int h=500)
void Function5(real_t u, real_t v, real_t &x, real_t &y, real_t &z)
void Function3(real_t u, real_t v, real_t &x, real_t &y, real_t &z)
void Function2(real_t u, real_t v, real_t &x, real_t &y, real_t &z)
void Function1(real_t u, real_t v, real_t &x, real_t &y, real_t &z)
void SurfaceFunction(int example, real_t u, real_t v, real_t &x, real_t &y, real_t &z)
void CheckError(const Array3D< real_t > &a, const Array3D< real_t > &b, int c, int nx, int ny)
void SampleNURBS(bool uniform, int nx, int ny, const Mesh &mesh, const Array< int > &nks, const std::vector< Vector > &ugrid, Array3D< real_t > &vpos)
void SurfaceGridExample(int example, int nx, int ny, Array3D< real_t > &vertices, real_t jitter)
std::array< int, NCMesh::MaxFaceNodes > nodes