MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
nurbs_surface.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11//
12// --------------------------------------------------------
13// NURBS Surface: Interpolate a 3D Surface in a NURBS Patch
14// --------------------------------------------------------
15//
16// Compile with: make nurbs_surface
17//
18// Sample runs: nurbs_surface -o 3 -nx 10 -ny 10 -fnx 10 -fny 10 -ex 1 -orig
19// nurbs_surface -o 3 -nx 10 -ny 10 -fnx 40 -fny 40 -ex 1
20// nurbs_surface -o 3 -nx 20 -ny 20 -fnx 10 -fny 10 -ex 1
21// nurbs_surface -o 3 -nx 20 -ny 20 -fnx 40 -fny 40 -ex 1 -j 0.5
22// nurbs_surface -o 3 -nx 10 -ny 10 -fnx 10 -fny 10 -ex 2 -orig
23// nurbs_surface -o 3 -nx 10 -ny 10 -fnx 40 -fny 40 -ex 2
24// nurbs_surface -o 3 -nx 20 -ny 20 -fnx 10 -fny 10 -ex 2
25// nurbs_surface -o 3 -nx 10 -ny 10 -fnx 10 -fny 10 -ex 3 -orig
26// nurbs_surface -o 3 -nx 10 -ny 10 -fnx 40 -fny 40 -ex 3
27// nurbs_surface -o 3 -nx 20 -ny 20 -fnx 10 -fny 10 -ex 3
28// nurbs_surface -o 3 -nx 20 -ny 10 -fnx 20 -fny 10 -ex 4 -orig
29// * nurbs_surface -o 3 -nx 20 -ny 10 -fnx 80 -fny 40 -ex 4
30// * nurbs_surface -o 3 -nx 40 -ny 20 -fnx 20 -fny 10 -ex 4
31// * nurbs_surface -o 3 -nx 100 -ny 100 -fnx 100 -fny 100 -ex 5 -orig
32// * nurbs_surface -o 3 -nx 100 -ny 100 -fnx 400 -fny 400 -ex 5
33// * nurbs_surface -o 3 -nx 200 -ny 200 -fnx 100 -fny 100 -ex 5
34//
35// Description: This example demonstrates the use of MFEM to interpolate an
36// input surface point grid in 3D using a NURBS surface. The NURBS
37// surface can then be sampled to generate an output mesh of
38// arbitrary resolution while staying close to the input geometry.
39
40#include "mfem.hpp"
41#include <fstream>
42#include <iostream>
43
44using namespace std;
45using namespace mfem;
46
47// Example data for 3D point grid on surface, given by an analytic function.
48void SurfaceGridExample(int example, int nx, int ny, Array3D<real_t> &vertices,
49 real_t jitter);
50
51// Write a linear surface mesh with given vertex positions in v.
52void WriteLinearMesh(int nx, int ny, const Array3D<real_t> &v,
53 const std::string &basename, bool visualization = false,
54 int x = 0, int y = 0, int w = 500, int h = 500);
55
56// Given an input grid of 3D points on a surface, this class computes a NURBS
57// surface of given order that interpolates the vertices of the input grid.
58class SurfaceInterpolator
59{
60public:
61 /// Constructor for a given 2D point grid size and NURBS order.
62 SurfaceInterpolator(int num_elem_x, int num_elem_y, int order);
63
64 /// Create a surface interpolating the 2D grid of 3D points in @a input3D.
65 void CreateSurface(const Array3D<real_t> &input3D);
66
67 /// Sample the surface with the given grid size, storing points in
68 /// @a output3D.
69 void SampleSurface(int num_elem_x, int num_elem_y, bool compareOriginal,
70 Array3D<real_t> &output3D);
71
72 /** @brief Write the NURBS surface mesh to file, defined coordinate-wise by
73 the entries of @a cmesh. */
74 void WriteNURBSMesh(const std::string &basename, bool visualization = false,
75 int x = 0, int y = 0, int w = 500, int h = 500);
76
77protected:
78 /** @brief Compute the NURBS mesh interpolating the given coordinate of the
79 grid of 3D points in @a input3D. */
80 void ComputeNURBS(int coordinate, const Array3D<real_t> &input3D);
81
82private:
83 int nx, ny; // Number of elements in two directions of the surface grid
84 int orderNURBS; // NURBS degree
85 real_t hx, hy, hz; // Grid size in reference space
86
87 Array3D<real_t> initial3D; // Initial grid of points
88
89 static constexpr int dim = 3;
90 Array<int> ncp; // Number of control points in each direction
91 Array<int> nks; // Number of knot-spans in each direction
92
93 std::vector<Vector> ugrid; // Parameter space [0,1]^2 grid point coordinates
94
95 std::vector<KnotVector> kv; // KnotVectors in each direction
96
97 std::unique_ptr<NURBSPatch> patch; // Pointer to the only patch in the mesh
98
99 Mesh mesh; // NURBS mesh representing the surface
100 std::vector<Mesh> cmesh; // NURBS meshes representing point components
101};
102
103
104int main(int argc, char *argv[])
105{
106 // Parse command-line options
107 int nx = 4;
108 int ny = 4;
109 int fnx = 40;
110 int fny = 40;
111 int order = 3;
112 int example = 1;
113 bool visualization = true;
114 bool compareOriginal = false;
115 real_t jitter = 0.0;
116
117 OptionsParser args(argc, argv);
118 args.AddOption(&example, "-ex", "--example",
119 "Example data");
120 args.AddOption(&nx, "-nx", "--nx",
121 "Number of elements in x");
122 args.AddOption(&ny, "-ny", "--ny",
123 "Number of elements in y");
124 args.AddOption(&fnx, "-fnx", "--fnx",
125 "Number of resampled elements in x");
126 args.AddOption(&fny, "-fny", "--fny",
127 "Number of resampled elements in y");
128 args.AddOption(&order, "-o", "--order",
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)");
139 args.Parse();
140 if (!args.Good())
141 {
142 args.PrintUsage(cout);
143 return 1;
144 }
145 args.PrintOptions(cout);
146
147 if (compareOriginal && (fnx != nx || fny != ny))
148 {
149 cout << "Comparing to the original mesh requires the same number of "
150 << "samples!\n";
151 return 1;
152 }
153
154 // Dimensions of the 3 surfaces (Input, NURBS, Output)
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";
159
160 // Set the vertex coordinates of the initial linear mesh
161 constexpr int dim = 3;
162 Array3D<real_t> input3D(nx + 1, ny + 1, dim);
163 SurfaceGridExample(example, nx, ny, input3D, jitter);
164
165 // Create a NURBS surface for the given nx, ny and order parameters that
166 // interpolates the input vertex coordinates
167 SurfaceInterpolator surf(nx, ny, order);
168 surf.CreateSurface(input3D);
169
170 // Compute the vertex coordinates of the output linear mesh by sampling the
171 // values from the NURBS surface
172 Array3D<real_t> output3D(fnx + 1, fny + 1, dim);
173 surf.SampleSurface(fnx, fny, compareOriginal, output3D);
174
175 // Save and optionally visualize the 3 surfaces (Input, NURBS, Output)
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);
179
180 return 0;
181}
182
183// f(x,y) = sin(2 * pi * x) * sin(2 * pi * y)
185{
186 x = u;
187 y = v;
188 z = sin(2.0 * M_PI * u) * sin(2.0 * M_PI * v);
189}
190
191// Part of the parametric surface of a sphere, using spherical coordinates.
193{
194 constexpr real_t r = 1.0;
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;
200
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);
205 z = r * cos(theta);
206}
207
208// Helicoid surface
210{
211 x = u * cos(2.0 * M_PI * v);
212 y = u * sin(2.0 * M_PI * v);
213 z = v;
214}
215
216// Mobius strip
218{
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);
224}
225
226// Breather surface
228{
229 const real_t m = 13.2 * ((2.0 * u) - 1.0);
230 const real_t n = 37.4 * ((2.0 * v) - 1.0);
231 constexpr real_t b = 0.4;
232 constexpr real_t r = 1.0 - (b*b);
233 const real_t w = sqrt(r);
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;
238}
239
240void SurfaceFunction(int example, real_t u, real_t v,
241 real_t &x, real_t &y, real_t &z)
242{
243 switch (example)
244 {
245 case 1:
246 Function1(u, v, x, y, z);
247 break;
248 case 2:
249 Function2(u, v, x, y, z);
250 break;
251 case 3:
252 Function3(u, v, x, y, z);
253 break;
254 case 4:
255 Function4(u, v, x, y, z);
256 break;
257 default:
258 Function5(u, v, x, y, z);
259 };
260}
261
262// Example data for 3D point grid on surface, given by an analytic function.
263void SurfaceExample(int example, const std::vector<Vector> &grid,
264 Array3D<real_t> &v3D, real_t jitter)
265{
266 int seed = (int)time(0);
267 srand((unsigned)seed);
268
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++)
271 {
272 for (int j = 0; j < grid[1].Size(); j++)
273 {
274 if (i != 0 && i != grid[0].Size()-1 && j != 0 && j != grid[1].Size()-1)
275 {
276 SurfaceFunction(example, grid[0][i] + rand_real()*h0*jitter,
277 grid[1][j] + rand_real()*h1*jitter,
278 v3D(i, j, 0), v3D(i, j, 1), v3D(i, j, 2));
279 }
280 else
281 {
282 SurfaceFunction(example, grid[0][i], grid[1][j],
283 v3D(i, j, 0), v3D(i, j, 1), v3D(i, j, 2));
284 }
285 }
286 }
287}
288
289void SurfaceGridExample(int example, int nx, int ny, Array3D<real_t> &vertices,
290 real_t jitter = 0)
291{
292 // Define a uniform grid of the reference parameter space [0,1]^2
293 std::vector<Vector> uniformGrid(2);
294 for (int i = 0; i < 2; ++i)
295 {
296 const int n = (i == 0) ? nx : ny;
297 const real_t h = 1.0 / n;
298 uniformGrid[i].SetSize(n + 1);
299 for (int j = 0; j <= n; ++j) { uniformGrid[i][j] = j * h; }
300 }
301
302 SurfaceExample(example, uniformGrid, vertices, jitter);
303}
304
305// Write a linear surface mesh with given vertex positions in v.
306void WriteLinearMesh(int nx, int ny, const Array3D<real_t> &v,
307 const std::string &basename, bool visualization,
308 int x, int y, int w, int h)
309{
310 const int nv = (nx + 1) * (ny + 1);
311 const int nelem = nx * ny;
312 constexpr int dim = 3; // Spatial dimension
313
314 Mesh lmesh(2, nv, nelem, 0, dim);
315 Vector vertex(dim);
316
317 for (int i = 0; i <= nx; ++i)
318 {
319 for (int j = 0; j <= ny; ++j)
320 {
321 for (int k = 0; k < dim; ++k) { vertex[k] = v(i, j, k); }
322 lmesh.AddVertex(vertex);
323 }
324 }
325
326 Array<int> verts(4);
327
328 auto vID = [&](int i, int j)
329 {
330 return j + (i * (ny + 1));
331 };
332
333 for (int i = 0; i < nx; ++i)
334 {
335 for (int j = 0; j < ny; ++j)
336 {
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);
341
343 el->SetVertices(verts);
344 lmesh.AddElement(el);
345 }
346 }
347
348 lmesh.FinalizeTopology();
349
350 ofstream mesh_ofs(basename + ".mesh");
351 mesh_ofs.precision(8);
352 lmesh.Print(mesh_ofs);
353
354 if (visualization)
355 {
356 char vishost[] = "localhost";
357 constexpr int visport = 19916;
358 socketstream sol_sock(vishost, visport);
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"
365 << flush;
366 }
367}
368
369
370// Compute error of interpolation with respect to an input grid of point data.
371void CheckError(const Array3D<real_t> &a, const Array3D<real_t> &b, int c,
372 int nx, int ny)
373{
374 real_t maxErr = 0.0;
375 for (int i = 0; i <= nx; ++i)
376 {
377 for (int j = 0; j <= ny; ++j)
378 {
379 const real_t err_ij = std::abs(a(i, j, c) - b(i, j, 2));
380 maxErr = std::max(maxErr, err_ij);
381 }
382 }
383
384 cout << "Max error: " << maxErr << " for coordinate " << c << endl;
385}
386
387
388// Sample a NURBS mesh to generate a first-order mesh.
389void SampleNURBS(bool uniform, int nx, int ny, const Mesh &mesh,
390 const Array<int> &nks, const std::vector<Vector> &ugrid,
391 Array3D<real_t> &vpos)
392{
393 const GridFunction *nodes = mesh.GetNodes();
394
395 const real_t hx = 1.0 / (real_t) nx;
396 const real_t hy = 1.0 / (real_t) ny;
397
398 const real_t hxks = 1.0 / (real_t) nks[0];
399 const real_t hyks = 1.0 / (real_t) nks[1];
400
401 Vector vertex;
403
404 ip.z = 1.0;
405 for (int i = 0; i <= nx; ++i)
406 {
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;
410 ip.x = ipx;
411
412 for (int j = 0; j <= ny; ++j)
413 {
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;
417 ip.y = ipy;
418
419 const int nurbsElem = nurbsElem0 + (nurbsElem1 * nks[0]);
420 nodes->GetVectorValue(nurbsElem, ip, vertex);
421
422 for (int k = 0; k < 3; ++k)
423 {
424 vpos(i, j, k) = vertex[k];
425 }
426 }
427 }
428}
429
430
431SurfaceInterpolator::SurfaceInterpolator(int num_elem_x, int num_elem_y,
432 int order) :
433 nx(num_elem_x), ny(num_elem_y), orderNURBS(order),
434 ncp(dim), nks(dim), ugrid(dim - 1)
435{
436 ncp[0] = nx + 1;
437 ncp[1] = ny + 1;
438 ncp[2] = order + 1;
439
440 for (int i = 0; i < dim; ++i)
441 {
442 nks[i] = ncp[i] - order;
443
444 Vector intervals(nks[i]);
445 Array<int> continuity(nks[i] + 1);
446
447 intervals = 1.0 / (real_t) nks[i];
448 continuity = order - 1;
449 continuity[0] = -1;
450 continuity[nks[i]] = -1;
451
452 kv.emplace_back(order, intervals, continuity);
453 }
454
455 patch.reset(new NURBSPatch(&kv[0], &kv[1], &kv[2], dim + 1));
456
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);
460
461 Vector xi_args;
462 Array<int> i_args;
463 for (int i = 0; i < 2; ++i)
464 {
465 kv[i].FindMaxima(i_args, xi_args, ugrid[i]);
466 }
467}
468
469void SurfaceInterpolator::CreateSurface(const Array3D<real_t> &input3D)
470{
471 cmesh.clear();
472 for (int c = 0; c < dim; ++c) // Loop over coordinates
473 {
474 ComputeNURBS(c, input3D);
475 cmesh.emplace_back(mesh);
476 }
477
478 initial3D = input3D;
479}
480
481void SurfaceInterpolator::SampleSurface(int num_elem_x, int num_elem_y,
482 bool compareOriginal,
483 Array3D<real_t> &output3D)
484{
485 Array3D<real_t> vpos(num_elem_x + 1, num_elem_y + 1, dim);
486 for (int c = 0; c < dim; ++c) // Loop over coordinates
487 {
488 SampleNURBS(true, num_elem_x, num_elem_y, cmesh[c], nks, ugrid, vpos);
489
490 if (compareOriginal)
491 {
492 SampleNURBS(false, num_elem_x, num_elem_y, cmesh[c], nks, ugrid, vpos);
493 CheckError(initial3D, vpos, c, nx, ny);
494 }
495
496 for (int i = 0; i <= num_elem_x; ++i)
497 {
498 for (int j = 0; j <= num_elem_y; ++j)
499 {
500 output3D(i,j,c) = vpos(i,j,2);
501 }
502 }
503 }
504}
505
506void SurfaceInterpolator::ComputeNURBS(int coordinate,
507 const Array3D<real_t> &input3D)
508{
510 for (int i = 0; i < dim; ++i) { x.Append(new Vector(ncp[0])); }
511
512 for (int k = 0; k < ncp[2]; ++k)
513 {
514 const real_t z = k * hz;
515
516 // For each horizontal slice (fixed k), interpolate a 2D surface by
517 // sweeping curve interpolations in each direction. See Algorithm A9.4 of
518 // "The NURBS Book" - 2nd ed - Piegl and Tiller.
519
520 // Resize for sweep in first direction
521 for (int i = 0; i < dim; ++i) { x[i]->SetSize(ncp[0]); }
522
523 // Sweep in the first direction
524 for (int j = 0; j < ncp[1]; ++j)
525 {
526 for (int i = 0; i < ncp[0]; i++)
527 {
528 (*x[0])[i] = ugrid[0][i];
529 (*x[1])[i] = ugrid[1][j];
530
531 const real_t s_ij = input3D(i, j, coordinate);
532 (*x[2])[i] = -1.0 + z + s_ij;
533 }
534
535 const bool reuse_factorization = j > 0;
536 kv[0].FindInterpolant(x, reuse_factorization);
537
538 for (int i = 0; i < ncp[0]; i++)
539 {
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; // weight
544 }
545 }
546
547 // Resize for sweep in second direction
548 for (int i = 0; i < dim; ++i) { x[i]->SetSize(ncp[1]); }
549
550 // Do another sweep in the second direction
551 for (int i = 0; i < ncp[0]; i++)
552 {
553 for (int j = 0; j < ncp[1]; ++j)
554 {
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);
558 }
559
560 const bool reuse_factorization = i > 0;
561 kv[1].FindInterpolant(x, reuse_factorization);
562
563 for (int j = 0; j < ncp[1]; ++j)
564 {
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];
568 }
569 }
570 }
571
572 for (auto p : x) { delete p; }
573
574 Array<const NURBSPatch*> patches(1);
575 patches[0] = patch.get();
576 Mesh patch_topology = Mesh::MakeCartesian3D(1, 1, 1, Element::HEXAHEDRON);
577 NURBSExtension nurbsExt(&patch_topology, patches);
578
579 mesh = Mesh(nurbsExt);
580}
581
582void SurfaceInterpolator::WriteNURBSMesh(const std::string &basename,
583 bool visualization,
584 int x, int y, int w, int h)
585{
586 GridFunction *nodes = cmesh[0].GetNodes();
587 NURBSPatch patch2D(&kv[0], &kv[1], dim);
588 Array<const NURBSPatch*> patches(1);
589 patches[0] = &patch2D;
590 Mesh patch_topology = Mesh::MakeCartesian2D(1, 1, Element::QUADRILATERAL);
591 Array<int> dofs;
592 cmesh[0].NURBSext->GetPatchDofs(0, dofs);
593
594 MFEM_VERIFY(dofs.Size() == (nx + 1) * (ny + 1) * (orderNURBS + 1), "");
595
596 for (int j = 0; j < ncp[1]; ++j)
597 {
598 for (int i = 0; i < ncp[0]; i++)
599 {
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; // weight
603 }
604 }
605
606 NURBSExtension nurbsExt(&patch_topology, patches);
607 Mesh mesh2D(nurbsExt);
608
609 FiniteElementCollection *fec = nodes->OwnFEC();
610 FiniteElementSpace fespace(&mesh2D, fec, dim, Ordering::byVDIM);
611 GridFunction nodes2D(&fespace);
612
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(), "");
616
617 Array<int> dofs2D;
618 mesh2D.NURBSext->GetPatchDofs(0, dofs2D);
619
620 for (int k = 0; k < dim; ++k)
621 {
622 const GridFunction &nodes_k = *cmesh[k].GetNodes();
623
624 for (int j = 0; j < ncp[1]; ++j)
625 {
626 for (int i = 0; i < ncp[0]; i++)
627 {
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];
631 }
632 }
633 }
634
635 // Make mesh2D into a surface mesh with nodes given by nodes2D
636 mesh2D.NewNodes(nodes2D);
637
638 ofstream mesh_ofs(basename + ".mesh");
639 mesh_ofs.precision(8);
640 mesh2D.Print(mesh_ofs);
641
642 if (visualization)
643 {
644 char vishost[] = "localhost";
645 constexpr int visport = 19916;
646 socketstream sol_sock(vishost, visport);
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"
653 << flush;
654 }
655}
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:840
int Size() const
Return the logical size of the array.
Definition array.hpp:166
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:912
Abstract data type element.
Definition element.hpp:29
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...
Definition fe_coll.hpp:27
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:208
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:32
Class for integration point with weight.
Definition intrules.hpp:35
Mesh data type.
Definition mesh.hpp:65
Element * NewElement(int geom)
Definition mesh.cpp:4818
void FinalizeTopology(bool generate_bdr=true)
Finalize the construction of the secondary topology (connectivity) data of a Mesh.
Definition mesh.cpp:3502
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.
Definition mesh.hpp:2567
int AddVertex(real_t x, real_t y=0.0, real_t z=0.0)
Definition mesh.cpp:2000
int AddElement(Element *elem)
Definition mesh.cpp:2363
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 =...
Definition mesh.cpp:4627
void GetNodes(Vector &node_coord) const
Definition mesh.cpp:9627
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...
Definition mesh.cpp:4617
NURBSExtension generally contains multiple NURBSPatch objects spanning an entire Mesh....
Definition nurbs.hpp:474
A NURBS patch can be 1D, 2D, or 3D, and is defined as a tensor product of KnotVectors.
Definition nurbs.hpp:226
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...
Definition optparser.hpp:82
bool Good() const
Return true if the command line options were parsed successfully.
Vector data type.
Definition vector.hpp:82
int dim
Definition ex24.cpp:53
int main()
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
real_t rand_real()
Generate a random real_t number in the interval [0,1) using rand().
Definition vector.hpp:61
float real_t
Definition config.hpp:46
const char vishost[]
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