1 // Copyright (c) 2017-2021, Lawrence Livermore National Security, LLC and
2 // other Axom Project Developers. See the top-level LICENSE file for details.
3 //
4 // SPDX-License-Identifier: (BSD-3-Clause)
5 
6 #include "axom/core.hpp"  // for axom macros
7 #include "axom/mint.hpp"  // for Mint classes & functions
8 
9 // Sidre includes
10 #ifdef AXOM_MINT_USE_SIDRE
11   #include "axom/sidre/core/sidre.hpp"
12 namespace sidre = axom::sidre;
13 #endif
14 
15 // C/C++ includes
16 #include <cmath>  // for definition of M_PI, exp()
17 
18 // namespace aliases
19 namespace mint = axom::mint;
20 namespace numerics = axom::numerics;
21 
22 /*!
23  * \file
24  *
25  * \brief Various code snippets/examples used for the Mint tutorial section.
26  *
27  * \note These examples are designed to illustrate specific Mint
28  *  concepts and capabilities. Consult the Tutorial section of Mint's
29  *  User Guide for more details.
30  *
31  */
32 
33 //------------------------------------------------------------------------------
34 //    TUTORIAL FUNCTIONS
35 //------------------------------------------------------------------------------
vtk_output(mint::Mesh * mesh,const std::string fileName)36 void vtk_output(mint::Mesh* mesh, const std::string fileName)
37 {
38   // sphinx_tutorial_vtk_output_start
39 
40   mint::write_vtk(mesh, fileName);
41 
42   // sphinx_tutorial_vtk_output_end
43 }
44 
45 //------------------------------------------------------------------------------
node_traversals()46 void node_traversals()
47 {
48   using exec_policy = axom::SEQ_EXEC;
49   using IndexType = axom::IndexType;
50 
51   const double lo[] = {-5.0, -5.0};
52   const double hi[] = {5.0, 5.0};
53   mint::UniformMesh mesh(lo, hi, 50, 50);
54 
55   mesh.createField<double>("xold", mint::NODE_CENTERED);
56   mesh.createField<double>("yold", mint::NODE_CENTERED);
57   mesh.createField<double>("vx", mint::NODE_CENTERED);
58   mesh.createField<double>("vy", mint::NODE_CENTERED);
59   mesh.createField<double>("vmag", mint::NODE_CENTERED);
60   mesh.createField<IndexType>("ID", mint::NODE_CENTERED);
61 
62   // Index example
63   {
64     // sphinx_tutorial_for_all_nodes_index_start
65 
66     const double* vx = mesh.getFieldPtr<double>("vx", mint::NODE_CENTERED);
67     const double* vy = mesh.getFieldPtr<double>("vy", mint::NODE_CENTERED);
68 
69     double* vmag = mesh.getFieldPtr<double>("vmag", mint::NODE_CENTERED);
70 
71     mint::for_all_nodes<exec_policy>(
72       &mesh,
73       AXOM_LAMBDA(IndexType nodeIdx) {
74         const double vx2 = vx[nodeIdx] * vx[nodeIdx];
75         const double vy2 = vy[nodeIdx] * vy[nodeIdx];
76         vmag[nodeIdx] = sqrt(vx2 + vy2);
77       });
78 
79     // sphinx_tutorial_for_all_nodes_index_end
80   }
81 
82   // IJ examples
83   {
84     // sphinx_tutorial_for_all_nodes_ij_start
85 
86     const IndexType jp = mesh.nodeJp();
87 
88     IndexType* ID = mesh.getFieldPtr<IndexType>("ID", mint::NODE_CENTERED);
89     mint::for_all_nodes<exec_policy, mint::xargs::ij>(
90       &mesh,
91       AXOM_LAMBDA(IndexType nodeIdx, IndexType i, IndexType j) {
92         ID[nodeIdx] = i + j * jp;
93       });
94 
95     // sphinx_tutorial_for_all_nodes_ij_end
96   }
97 
98   // XY example
99   {
100     // sphinx_tutorial_for_all_nodes_xy_start
101 
102     double invdt = 0.5;
103 
104     const double* xold = mesh.getFieldPtr<double>("xold", mint::NODE_CENTERED);
105     const double* yold = mesh.getFieldPtr<double>("yold", mint::NODE_CENTERED);
106 
107     double* vx = mesh.getFieldPtr<double>("vx", mint::NODE_CENTERED);
108     double* vy = mesh.getFieldPtr<double>("vy", mint::NODE_CENTERED);
109 
110     mint::for_all_nodes<exec_policy, mint::xargs::xy>(
111       &mesh,
112       AXOM_LAMBDA(IndexType nodeIdx, double x, double y) {
113         vx[nodeIdx] = (x - xold[nodeIdx]) * invdt;
114         vy[nodeIdx] = (y - yold[nodeIdx]) * invdt;
115       });
116 
117     // sphinx_tutorial_for_all_nodes_xy_end
118   }
119 }
120 
121 //------------------------------------------------------------------------------
cell_traversals()122 void cell_traversals()
123 {
124   using exec_policy = axom::SEQ_EXEC;
125   using IndexType = axom::IndexType;
126 
127   const double lo[] = {-5.0, -5.0};
128   const double hi[] = {5.0, 5.0};
129   mint::UniformMesh mesh(lo, hi, 50, 50);
130 
131   mesh.createField<double>("vx", mint::NODE_CENTERED);
132   mesh.createField<double>("vy", mint::NODE_CENTERED);
133 
134   mesh.createField<double>("cell_vx", mint::CELL_CENTERED);
135   mesh.createField<double>("cell_vy", mint::CELL_CENTERED);
136   mesh.createField<double>("den", mint::CELL_CENTERED);
137   mesh.createField<double>("mass", mint::CELL_CENTERED);
138   mesh.createField<double>("vol", mint::CELL_CENTERED);
139   mesh.createField<double>("xc", mint::CELL_CENTERED);
140   mesh.createField<double>("yc", mint::CELL_CENTERED);
141   mesh.createField<double>("perimeter", mint::CELL_CENTERED);
142   mesh.createField<IndexType>("ID", mint::CELL_CENTERED);
143 
144   mesh.createField<double>("area", mint::FACE_CENTERED);
145   // Index example
146   {
147     // sphinx_tutorial_for_all_cells_index_start
148 
149     const double* mass = mesh.getFieldPtr<double>("mass", mint::CELL_CENTERED);
150     const double* vol = mesh.getFieldPtr<double>("vol", mint::CELL_CENTERED);
151 
152     double* den = mesh.getFieldPtr<double>("den", mint::CELL_CENTERED);
153 
154     mint::for_all_cells<exec_policy>(
155       &mesh,
156       AXOM_LAMBDA(IndexType cellIdx) {
157         den[cellIdx] = mass[cellIdx] / vol[cellIdx];
158       });
159 
160     // sphinx_tutorial_for_all_cells_index_end
161   }
162 
163   // IJ example
164   {
165     // sphinx_tutorial_for_all_cells_ij_start
166 
167     const IndexType jp = mesh.cellJp();
168 
169     IndexType* ID = mesh.getFieldPtr<IndexType>("ID", mint::CELL_CENTERED);
170     mint::for_all_cells<exec_policy, mint::xargs::ij>(
171       &mesh,
172       AXOM_LAMBDA(IndexType cellIdx, IndexType i, IndexType j) {
173         ID[cellIdx] = i + j * jp;
174       });
175 
176     // sphinx_tutorial_for_all_cells_ij_end
177   }
178 
179   // nodeIds example
180   {
181     // sphinx_tutorial_for_all_cells_nodeids_start
182 
183     const double* vx = mesh.getFieldPtr<double>("vx", mint::NODE_CENTERED);
184     const double* vy = mesh.getFieldPtr<double>("vy", mint::NODE_CENTERED);
185 
186     double* cell_vx = mesh.getFieldPtr<double>("cell_vx", mint::CELL_CENTERED);
187     double* cell_vy = mesh.getFieldPtr<double>("cell_vy", mint::CELL_CENTERED);
188 
189     mint::for_all_cells<exec_policy, mint::xargs::nodeids>(
190       &mesh,
191       AXOM_LAMBDA(IndexType cellIdx, const IndexType* nodeIDs, IndexType N) {
192         // sum nodal contributions
193         cell_vx[cellIdx] = 0.0;
194         cell_vy[cellIdx] = 0.0;
195         for(IndexType inode = 0; inode < N; ++inode)
196         {
197           cell_vx[cellIdx] += vx[nodeIDs[inode]];
198           cell_vy[cellIdx] += vy[nodeIDs[inode]];
199         }  // END for all cell nodes
200 
201         // average at the cell center
202         const double invf = 1.0 / static_cast<double>(N);
203         cell_vx[cellIdx] *= invf;
204         cell_vy[cellIdx] *= invf;
205       });
206 
207     // sphinx_tutorial_for_all_cells_nodeids_end
208   }
209 
210   // coords example
211   {
212     // sphinx_tutorial_for_all_cells_coords_start
213 
214     double* xc = mesh.getFieldPtr<double>("xc", mint::CELL_CENTERED);
215     double* yc = mesh.getFieldPtr<double>("yc", mint::CELL_CENTERED);
216 
217     mint::for_all_cells<exec_policy, mint::xargs::coords>(
218       &mesh,
219       AXOM_LAMBDA(IndexType cellIdx,
220                   const numerics::Matrix<double>& coords,
221                   const IndexType* AXOM_UNUSED_PARAM(nodeIdx)) {
222         // sum nodal coordinates
223         double xsum = 0.0;
224         double ysum = 0.0;
225         const int numNodes = coords.getNumColumns();
226         for(int inode = 0; inode < numNodes; ++inode)
227         {
228           const double* node = coords.getColumn(inode);
229           xsum += node[mint::X_COORDINATE];
230           ysum += node[mint::Y_COORDINATE];
231         }  // end for all cell nodes
232 
233         // compute centroid by averaging nodal coordinates
234         const double invf = 1.0 / static_cast<double>(numNodes);
235         xc[cellIdx] = xsum * invf;
236         yc[cellIdx] = ysum * invf;
237       });
238 
239     // sphinx_tutorial_for_all_cells_coords_end
240   }
241 
242   // faceids example
243   {
244     // sphinx_tutorial_for_all_cells_faceids_start
245 
246     const double* area = mesh.getFieldPtr<double>("area", mint::FACE_CENTERED);
247     double* perimeter =
248       mesh.getFieldPtr<double>("perimeter", mint::CELL_CENTERED);
249 
250     mint::for_all_cells<exec_policy, mint::xargs::faceids>(
251       &mesh,
252       AXOM_LAMBDA(IndexType cellIdx, const IndexType* faceIDs, IndexType N) {
253         perimeter[cellIdx] = 0.0;
254         for(IndexType iface = 0; iface < N; ++iface)
255         {
256           perimeter[cellIdx] += area[faceIDs[iface]];
257         }
258       });
259 
260     // sphinx_tutorial_for_all_cells_faceids_end
261   }
262 }
263 
264 //------------------------------------------------------------------------------
face_traversals()265 void face_traversals()
266 {
267   using exec_policy = axom::SEQ_EXEC;
268   using IndexType = axom::IndexType;
269 
270   const double lo[] = {-5.0, -5.0};
271   const double hi[] = {5.0, 5.0};
272   mint::UniformMesh mesh(lo, hi, 50, 50);
273 
274   mesh.createField<double>("vx", mint::NODE_CENTERED);
275   mesh.createField<double>("vy", mint::NODE_CENTERED);
276 
277   mesh.createField<double>("t1", mint::FACE_CENTERED);
278   mesh.createField<double>("t2", mint::FACE_CENTERED);
279   mesh.createField<double>("w", mint::FACE_CENTERED);
280   ;
281   mesh.createField<double>("temp", mint::FACE_CENTERED);
282   mesh.createField<double>("face_vx", mint::FACE_CENTERED);
283   mesh.createField<double>("face_vy", mint::FACE_CENTERED);
284   mesh.createField<double>("fx", mint::FACE_CENTERED);
285   mesh.createField<double>("fy", mint::FACE_CENTERED);
286   mesh.createField<IndexType>("boundary", mint::FACE_CENTERED);
287 
288   // Index example
289   {
290     // sphinx_tutorial_for_all_faces_index_start
291 
292     const double* t1 = mesh.getFieldPtr<double>("t1", mint::FACE_CENTERED);
293     const double* t2 = mesh.getFieldPtr<double>("t2", mint::FACE_CENTERED);
294     const double* w = mesh.getFieldPtr<double>("w", mint::FACE_CENTERED);
295 
296     double* temp = mesh.getFieldPtr<double>("temp", mint::FACE_CENTERED);
297     mint::for_all_faces<exec_policy>(
298       &mesh,
299       AXOM_LAMBDA(IndexType faceIdx) {
300         const double wf = w[faceIdx];
301         const double a = t1[faceIdx];
302         const double b = t2[faceIdx];
303 
304         temp[faceIdx] = wf * a + (1. - wf) * b;
305       });
306 
307     // sphinx_tutorial_for_all_faces_index_end
308   }
309 
310   // nodeids example
311   {
312     // sphinx_tutorial_for_all_faces_nodeids_start
313 
314     const double* vx = mesh.getFieldPtr<double>("vx", mint::NODE_CENTERED);
315     const double* vy = mesh.getFieldPtr<double>("vy", mint::NODE_CENTERED);
316 
317     double* face_vx = mesh.getFieldPtr<double>("face_vx", mint::FACE_CENTERED);
318     double* face_vy = mesh.getFieldPtr<double>("face_vy", mint::FACE_CENTERED);
319 
320     mint::for_all_faces<exec_policy, mint::xargs::nodeids>(
321       &mesh,
322       AXOM_LAMBDA(IndexType faceIdx, const IndexType* nodeIDs, IndexType N) {
323         // sum constituent face node contributions
324         face_vx[faceIdx] = 0.0;
325         face_vy[faceIdx] = 0.0;
326         for(int inode = 0; inode < N; ++inode)
327         {
328           face_vx[faceIdx] += vx[nodeIDs[inode]];
329           face_vy[faceIdx] += vy[nodeIDs[inode]];
330         }  // END for all face nodes
331 
332         // average
333         const double invf = 1.0 / static_cast<double>(N);
334         face_vx[faceIdx] *= invf;
335         face_vy[faceIdx] *= invf;
336       });
337 
338     // sphinx_tutorial_for_all_faces_nodeids_end
339   }
340 
341   // coords example
342   {
343     // sphinx_tutorial_for_all_faces_coords_start
344 
345     double* fx = mesh.getFieldPtr<double>("fx", mint::FACE_CENTERED);
346     double* fy = mesh.getFieldPtr<double>("fy", mint::FACE_CENTERED);
347 
348     mint::for_all_faces<exec_policy, mint::xargs::coords>(
349       &mesh,
350       AXOM_LAMBDA(IndexType faceIdx,
351                   const numerics::Matrix<double>& coords,
352                   const IndexType* AXOM_UNUSED_PARAM(nodeIdx)) {
353         // sum nodal coordinates
354         double xsum = 0.0;
355         double ysum = 0.0;
356         const int numNodes = coords.getNumColumns();
357         for(int inode = 0; inode < numNodes; ++inode)
358         {
359           const double* node = coords.getColumn(inode);
360           xsum += node[mint::X_COORDINATE];
361           ysum += node[mint::Y_COORDINATE];
362         }  // end for all face nodes
363 
364         // compute centroid by averaging nodal coordinates
365         const double invf = 1.0 / static_cast<double>(numNodes);
366         fx[faceIdx] = xsum * invf;
367         fy[faceIdx] = ysum * invf;
368       });
369 
370     // sphinx_tutorial_for_all_faces_coords_end
371   }
372 
373   // cellids example
374   {
375     // sphinx_tutorial_for_all_faces_cellids_start
376 
377     constexpr IndexType ON_BOUNDARY = 1;
378     constexpr IndexType INTERIOR = 0;
379 
380     IndexType* boundary =
381       mesh.getFieldPtr<IndexType>("boundary", mint::FACE_CENTERED);
382 
383     mint::for_all_faces<exec_policy, mint::xargs::cellids>(
384       &mesh,
385       AXOM_LAMBDA(IndexType faceIdx, IndexType AXOM_UNUSED_PARAM(c1), IndexType c2) {
386         boundary[faceIdx] = (c2 == -1) ? ON_BOUNDARY : INTERIOR;
387       });
388 
389     // sphinx_tutorial_for_all_faces_cellids_end
390   }
391 }
392 
393 //------------------------------------------------------------------------------
fem_tutorial()394 void fem_tutorial()
395 {
396   // sphinx_tutorial_create_fe_start
397 
398   constexpr bool ZERO_COPY = true;
399 
400   double coords[] = {
401     0.0,
402     0.0,  // x1, y1
403     5.0,
404     0.0,  // x2, y2
405     5.0,
406     5.0,  // x3, y3,
407     0.0,
408     5.0  // x4, y4
409   };
410 
411   numerics::Matrix<double> nodes_matrix(2, 4, coords, ZERO_COPY);
412   mint::FiniteElement fe(nodes_matrix, mint::QUAD);
413 
414   // bind to FE basis, wires the shape function pointers
415   mint::bind_basis<MINT_LAGRANGE_BASIS, mint::QUAD>(fe);
416 
417   // sphinx_tutorial_create_fe_end
418 
419   // sphinx_tutorial_evaluate_shape_functions_start
420 
421   // isoparametric center
422   double xi[] = {0.5, 0.5};
423   double N[4];
424   fe.evaluateShapeFunctions(xi, N);
425 
426   // sphinx_tutorial_evaluate_shape_functions_end
427 
428   // sphinx_tutorial_jacobian_start
429 
430   numerics::Matrix<double> J(2, 2);
431   fe.jacobian(xi, J);
432 
433   const double jdet = numerics::determinant(J);
434   std::cout << "jacobian determinant: " << jdet << std::endl;
435 
436   // sphinx_tutorial_jacobian_end
437 
438   // sphinx_tutorial_forward_map_start
439 
440   double xc[2];
441   fe.computePhysicalCoords(xi, xc);
442   std::cout << "xc: ( ";
443   std::cout << xc[0] << ", " << xc[1];
444   std::cout << " )\n";
445 
446   // sphinx_tutorial_forward_map_end
447 
448   // sphinx_tutorial_inverse_map_start
449 
450   double xr[2];
451   int status = fe.computeReferenceCoords(xc, xr);
452 
453   switch(status)
454   {
455   case mint::INVERSE_MAP_FAILED:
456     std::cout << "Newton-Raphson failed!";
457     break;
458   case mint::OUTSIDE_ELEMENT:
459     std::cout << "point is outside!\n";
460     break;
461   default:
462     // found the reference coordinates!
463     std::cout << "xr: ( ";
464     std::cout << xr[0] << ", " << xr[1];
465     std::cout << " )\n";
466   }
467 
468   // sphinx_tutorial_inverse_map_end
469 }
470 
471 //------------------------------------------------------------------------------
working_with_fields(mint::Mesh * mesh)472 void working_with_fields(mint::Mesh* mesh)
473 {
474   constexpr int FIELD_ASSOCIATION = mint::NODE_CENTERED;
475 
476   {  // START unnamed namespace
477 
478     // sphinx_tutorial_add_fields_start
479 
480     double* den = mesh->createField<double>("den", mint::CELL_CENTERED);
481     double* vel = mesh->createField<double>("vel", mint::NODE_CENTERED, 3);
482 
483     // sphinx_tutorial_add_fields_end
484 
485     AXOM_UNUSED_VAR(den);
486     AXOM_UNUSED_VAR(vel);
487 
488   }  // END unnamed namespace
489 
490   // sphinx_tutorial_get_field_by_name_start
491 
492   double* den = mesh->getFieldPtr<double>("den", mint::CELL_CENTERED);
493 
494   axom::IndexType nc = -1;  // number of components
495   double* vel = mesh->getFieldPtr<double>("vel", mint::NODE_CENTERED, nc);
496 
497   // sphinx_tutorial_get_field_by_name_end
498 
499   // sphinx_tutorial_check_fields_start
500 
501   const bool hasDen = mesh->hasField("den", mint::CELL_CENTERED);
502   const bool hasVel = mesh->hasField("vel", mint::NODE_CENTERED);
503 
504   // sphinx_tutorial_check_fields_end
505 
506   // sphinx_tutorial_remove_fields_start
507 
508   bool isRemoved = mesh->removeField("den", mint::CELL_CENTERED);
509 
510   // sphinx_tutorial_remove_fields_end
511 
512   // sphinx_tutorial_query_fields_start
513 
514   const mint::FieldData* fieldData = mesh->getFieldData(FIELD_ASSOCIATION);
515 
516   const int numFields = fieldData->getNumFields();
517   for(int ifield = 0; ifield < numFields; ++ifield)
518   {
519     const mint::Field* field = fieldData->getField(ifield);
520 
521     const std::string& fieldName = field->getName();
522     axom::IndexType numTuples = field->getNumTuples();
523     axom::IndexType numComponents = field->getNumComponents();
524 
525     std::cout << "field name: " << fieldName << std::endl;
526     std::cout << "numTuples: " << numTuples << std::endl;
527     std::cout << "numComponents: " << numComponents << std::endl;
528 
529     if(field->getType() == mint::DOUBLE_FIELD_TYPE)
530     {
531       double* data = mesh->getFieldPtr<double>(fieldName, FIELD_ASSOCIATION);
532       data[0] = 42.0;
533       // process double precision floating point data
534       // ...
535     }
536     else if(field->getType() == mint::INT32_FIELD_TYPE)
537     {
538       int* data = mesh->getFieldPtr<int>(fieldName, FIELD_ASSOCIATION);
539       data[0] = 42;
540       // process integral data
541       // ...
542     }
543     // ...
544 
545   }  // END for all fields
546 
547   // sphinx_tutorial_query_fields_end
548 
549   AXOM_UNUSED_VAR(hasDen);
550   AXOM_UNUSED_VAR(hasVel);
551   AXOM_UNUSED_VAR(den);
552   AXOM_UNUSED_VAR(vel);
553   AXOM_UNUSED_VAR(isRemoved);
554 }
555 
556 //------------------------------------------------------------------------------
construct_uniform()557 void construct_uniform()
558 {
559   // sphinx_tutorial_construct_uniform_start
560 
561   const double lo[] = {-5.0, -5.0};
562   const double hi[] = {5.0, 5.0};
563   mint::UniformMesh mesh(lo, hi, 50, 50);
564 
565   // sphinx_tutorial_construct_uniform_end
566 
567   mint::write_vtk(&mesh, "tutorial_uniform_mesh.vtk");
568 }
569 
570 //------------------------------------------------------------------------------
construct_rectilinear()571 void construct_rectilinear()
572 {
573   // sphinx_tutorial_construct_rectilinear_start
574 
575   constexpr double beta = 0.1;
576   const double expbeta = exp(beta);
577   const double invf = 1 / (expbeta - 1.0);
578 
579   // construct a N x N rectilinear mesh
580   constexpr axom::IndexType N = 25;
581   mint::RectilinearMesh mesh(N, N);
582   double* x = mesh.getCoordinateArray(mint::X_COORDINATE);
583   double* y = mesh.getCoordinateArray(mint::Y_COORDINATE);
584 
585   // fill the coordinates along each axis
586   x[0] = y[0] = 0.0;
587   for(int i = 1; i < N; ++i)
588   {
589     const double delta = (exp(i * beta) - 1.0) * invf;
590     x[i] = x[i - 1] + delta;
591     y[i] = y[i - 1] + delta;
592   }
593 
594   // sphinx_tutorial_construct_rectilinear_end
595 
596   mint::write_vtk(&mesh, "tutorial_rectilinear_mesh.vtk");
597 }
598 
599 //------------------------------------------------------------------------------
construct_curvilinear()600 void construct_curvilinear()
601 {
602   // sphinx_tutorial_construct_curvilinear_start
603 
604   constexpr double R = 2.5;
605   constexpr double M = (2 * M_PI) / 50.0;
606   constexpr double h = 0.5;
607   constexpr axom::IndexType N = 25;
608 
609   // construct the curvilinear mesh object
610   mint::CurvilinearMesh mesh(N, N);
611 
612   // get a handle on the coordinate arrays
613   double* x = mesh.getCoordinateArray(mint::X_COORDINATE);
614   double* y = mesh.getCoordinateArray(mint::Y_COORDINATE);
615 
616   // fill the coordinates of the curvilinear mesh
617   const axom::IndexType jp = mesh.nodeJp();
618   for(axom::IndexType j = 0; j < N; ++j)
619   {
620     const axom::IndexType j_offset = j * jp;
621 
622     for(axom::IndexType i = 0; i < N; ++i)
623     {
624       const axom::IndexType nodeIdx = i + j_offset;
625 
626       const double xx = h * i;
627       const double yy = h * j;
628       const double alpha = yy + R;
629       const double beta = xx * M;
630 
631       x[nodeIdx] = alpha * cos(beta);
632       y[nodeIdx] = alpha * sin(beta);
633     }  // END for all i
634 
635   }  // END for all j
636 
637   // sphinx_tutorial_construct_curvilinear_end
638 
639   mint::write_vtk(&mesh, "tutorial_curvilinear_mesh.vtk");
640 }
641 
642 //------------------------------------------------------------------------------
construct_single_cell_type_unstructured()643 void construct_single_cell_type_unstructured()
644 {
645   // sphinx_tutorial_construct_unstructured_start
646 
647   constexpr int DIMENSION = 2;
648   constexpr mint::CellType CELL_TYPE = mint::TRIANGLE;
649 
650   // Construct the mesh object
651   mint::UnstructuredMesh<mint::SINGLE_SHAPE> mesh(DIMENSION, CELL_TYPE);
652 
653   // Append the mesh nodes
654   const axom::IndexType n0 = mesh.appendNode(0.0, 0.0);
655   const axom::IndexType n1 = mesh.appendNode(2.0, 0.0);
656   const axom::IndexType n2 = mesh.appendNode(1.0, 1.0);
657   const axom::IndexType n3 = mesh.appendNode(3.5, 1.0);
658   const axom::IndexType n4 = mesh.appendNode(2.5, 2.0);
659   const axom::IndexType n5 = mesh.appendNode(5.0, 0.0);
660 
661   // Append mesh cells
662   const axom::IndexType c0[] = {n1, n3, n2};
663   const axom::IndexType c1[] = {n2, n0, n1};
664   const axom::IndexType c2[] = {n3, n4, n2};
665   const axom::IndexType c3[] = {n1, n5, n3};
666 
667   mesh.appendCell(c0);
668   mesh.appendCell(c1);
669   mesh.appendCell(c2);
670   mesh.appendCell(c3);
671 
672   // sphinx_tutorial_construct_unstructured_end
673 
674   // STEP 3: write output mesh
675   mint::write_vtk(&mesh, "tutorial_triangle_mesh.vtk");
676 }
677 
678 //------------------------------------------------------------------------------
construct_mixed_cell_type_unstructured()679 void construct_mixed_cell_type_unstructured()
680 {
681   // sphinx_tutorial_construct_unstructured_mixed_start
682 
683   constexpr int DIMENSION = 2;
684 
685   // Construct the mesh object
686   mint::UnstructuredMesh<mint::MIXED_SHAPE> mesh(DIMENSION);
687 
688   // Append the mesh nodes
689   const axom::IndexType n0 = mesh.appendNode(0.0, 0.0);
690   const axom::IndexType n1 = mesh.appendNode(2.0, 0.0);
691   const axom::IndexType n2 = mesh.appendNode(1.0, 1.0);
692   const axom::IndexType n3 = mesh.appendNode(3.5, 1.0);
693   const axom::IndexType n4 = mesh.appendNode(2.5, 2.0);
694   const axom::IndexType n5 = mesh.appendNode(5.0, 0.0);
695 
696   // Append mesh cells
697   const axom::IndexType c0[] = {n0, n1, n2};
698   const axom::IndexType c1[] = {n1, n5, n3, n2};
699   const axom::IndexType c2[] = {n3, n4, n2};
700 
701   mesh.appendCell(c0, mint::TRIANGLE);
702   mesh.appendCell(c1, mint::QUAD);
703   mesh.appendCell(c2, mint::TRIANGLE);
704 
705   // sphinx_tutorial_construct_unstructured_mixed_end
706 
707   // STEP 3: write output mesh
708   mint::write_vtk(&mesh, "tutorial_mixed_unstructured_mesh.vtk");
709 }
710 
711 //------------------------------------------------------------------------------
using_external_storage()712 void using_external_storage()
713 {
714   // sphinx_tutorial_using_external_storage_start
715 
716   constexpr axom::IndexType NUM_NODES = 6;
717   constexpr axom::IndexType NUM_CELLS = 4;
718 
719   // application buffers
720   double x[] = {0.0, 2.0, 1.0, 3.5, 2.5, 5.0};
721   double y[] = {0.0, 0.0, 1.0, 1.0, 2.0, 0.0};
722 
723   axom::IndexType cell_connectivity[] = {
724     1,
725     3,
726     2,  // c0
727     2,
728     0,
729     1,  // c1
730     3,
731     4,
732     2,  // c2
733     1,
734     5,
735     3  // c3
736   };
737 
738   // cell-centered density field values
739   double den[] = {0.5, 1.2, 2.5, 0.9};
740 
741   // construct mesh object with external buffers
742   using MeshType = mint::UnstructuredMesh<mint::SINGLE_SHAPE>;
743   MeshType* mesh =
744     new MeshType(mint::TRIANGLE, NUM_CELLS, cell_connectivity, NUM_NODES, x, y);
745 
746   // register external field
747   mesh->createField<double>("den", mint::CELL_CENTERED, den);
748 
749   // output external mesh to vtk
750   mint::write_vtk(mesh, "tutorial_external_mesh.vtk");
751 
752   // delete the mesh, doesn't touch application buffers
753   delete mesh;
754   mesh = nullptr;
755 
756   // sphinx_tutorial_using_external_storage_end
757 }
758 
759 //------------------------------------------------------------------------------
using_sidre()760 void using_sidre()
761 {
762 #ifdef AXOM_MINT_USE_SIDRE
763 
764   // sphinx_tutorial_using_sidre_create_mesh_start
765   // create a Sidre Datastore to store the mesh
766   sidre::DataStore ds;
767   sidre::Group* group = ds.getRoot();
768 
769   // Construct the mesh object and populate the supplied Sidre Group
770   mint::UnstructuredMesh<mint::SINGLE_SHAPE> mesh(2, mint::TRIANGLE, group);
771 
772   // Append the mesh nodes
773   const axom::IndexType n0 = mesh.appendNode(0.0, 0.0);
774   const axom::IndexType n1 = mesh.appendNode(2.0, 0.0);
775   const axom::IndexType n2 = mesh.appendNode(1.0, 1.0);
776   const axom::IndexType n3 = mesh.appendNode(3.5, 1.0);
777   const axom::IndexType n4 = mesh.appendNode(2.5, 2.0);
778   const axom::IndexType n5 = mesh.appendNode(5.0, 0.0);
779 
780   // Append mesh cells
781   const axom::IndexType c0[] = {n1, n3, n2};
782   const axom::IndexType c1[] = {n2, n0, n1};
783   const axom::IndexType c2[] = {n3, n4, n2};
784   const axom::IndexType c3[] = {n1, n5, n3};
785 
786   mesh.appendCell(c0);
787   mesh.appendCell(c1);
788   mesh.appendCell(c2);
789   mesh.appendCell(c3);
790 
791   // create a cell-centered field
792   double* den = mesh.createField<double>("den", mint::CELL_CENTERED);
793 
794   // set density values at each cell
795   den[0] = 0.5;  // c0
796   den[1] = 1.2;  // c1
797   den[2] = 2.5;  // c2
798   den[3] = 0.9;  // c3
799 
800   // sphinx_tutorial_using_sidre_create_mesh_end
801 
802   std::ofstream ofs;
803   ofs.open("sphinx_tutorial_sidre_tree.txt");
804   group->print(ofs);
805   ofs.close();
806 
807   // sphinx_tutorial_sidre_import_start
808 
809   mint::Mesh* imported_mesh = mint::getMesh(group);
810   std::cout << "Mesh Type: " << imported_mesh->getMeshType() << std::endl;
811   std::cout << "hasSidre: " << imported_mesh->hasSidreGroup() << std::endl;
812 
813   mint::write_vtk(imported_mesh, "tutorial_imported_mesh.vtk");
814 
815   delete imported_mesh;
816   imported_mesh = nullptr;
817 
818   // sphinx_tutorial_sidre_import_end
819 
820 #endif /* AXOM_MINT_USE_SIDRE */
821 }
822 
823 /*!
824  * \brief Tutorial main
825  */
main(int AXOM_UNUSED_PARAM (argc),char ** AXOM_UNUSED_PARAM (argv))826 int main(int AXOM_UNUSED_PARAM(argc), char** AXOM_UNUSED_PARAM(argv))
827 {
828   // Native construction of various mesh types
829   construct_uniform();
830   construct_rectilinear();
831   construct_curvilinear();
832   construct_single_cell_type_unstructured();
833   construct_mixed_cell_type_unstructured();
834 
835   fem_tutorial();
836   using_sidre();
837   using_external_storage();
838 
839   node_traversals();
840   cell_traversals();
841   face_traversals();
842 
843   const double lo[] = {-5.0, -5.0};
844   const double hi[] = {5.0, 5.0};
845   mint::UniformMesh mesh(lo, hi, 50, 50);
846 
847   working_with_fields(&mesh);
848   vtk_output(&mesh, "tutorial_mesh.vtk");
849 
850   return 0;
851 }
852