35#include <boost/format.hpp>
41#include <vtkCellType.h>
42#include <vtkDoubleArray.h>
43#include <vtkInformation.h>
44#include <vtkMultiBlockDataSet.h>
45#include <vtkPointData.h>
47#include <vtkXMLMultiBlockDataWriter.h>
48#include <vtkXMLUnstructuredGridWriter.h>
60 ConfigOption(
true,
"0",
"Output using legacy manual file writers");
62 true,
"0",
"Output using new high-order Lagrange elements");
64 true,
"0",
"Output using multi-blocks to separate composites");
73inline size_t key2(
int i,
int j)
75 return (
size_t)i << 32 | (
unsigned int)j;
79inline size_t key3(
int i,
int j,
int k)
81 return (
size_t)i << 10 ^ j << 5 ^ k;
85typedef std::tuple<int, int, int> Mode;
89 bool operator()(Mode
const &a, Mode
const &b)
const
91 if (std::get<0>(a) < std::get<0>(b))
95 if (std::get<0>(a) > std::get<0>(b))
99 if (std::get<1>(a) < std::get<1>(b))
103 if (std::get<1>(a) > std::get<1>(b))
107 if (std::get<2>(a) < std::get<2>(b))
116void Rotate(
int nrot, std::vector<long long> &surfVerts)
119 int np =
static_cast<int>(
120 (
sqrt(8.0 *
static_cast<int>(surfVerts.size()) + 1.0) - 1) / 2);
121 std::vector<long long> tmp(np * np);
123 for (n = 0; n < nrot; ++n)
125 for (cnt = i = 0; i < np; ++i)
127 for (j = 0; j < np - i; ++j, cnt++)
129 tmp[i * np + j] = surfVerts[cnt];
132 for (cnt = i = 0; i < np; ++i)
134 for (j = 0; j < np - i; ++j, cnt++)
136 surfVerts[cnt] = tmp[(np - 1 - i - j) * np + i];
142void Reflect(std::vector<long long> &surfVerts)
145 int np =
static_cast<int>(
146 (
sqrt(8.0 *
static_cast<double>(surfVerts.size()) + 1.0) - 1) / 2);
147 std::vector<long long> tmp(np * np);
149 for (cnt = i = 0; i < np; ++i)
151 for (j = 0; j < np - i; ++j, cnt++)
153 tmp[i * np + np - i - 1 - j] = surfVerts[cnt];
157 for (cnt = i = 0; i < np; ++i)
159 for (j = 0; j < np - i; ++j, cnt++)
161 surfVerts[cnt] = tmp[i * np + j];
166void Align(std::vector<long long> thisVertId, std::vector<long long> vertId,
167 std::vector<long long> &surfVerts)
169 if (vertId[0] == thisVertId[0])
171 if (vertId[1] == thisVertId[1] || vertId[1] == thisVertId[2])
173 if (vertId[1] == thisVertId[2])
175 Rotate(1, surfVerts);
180 else if (vertId[0] == thisVertId[1])
182 if (vertId[1] == thisVertId[0] || vertId[1] == thisVertId[2])
184 if (vertId[1] == thisVertId[0])
190 Rotate(2, surfVerts);
194 else if (vertId[0] == thisVertId[2])
196 if (vertId[1] == thisVertId[0] || vertId[1] == thisVertId[1])
198 if (vertId[1] == thisVertId[1])
200 Rotate(2, surfVerts);
205 Rotate(1, surfVerts);
211std::vector<long long> quadTensorNodeOrdering(
212 const std::vector<long long> &nodes)
214 int nN =
static_cast<int>(nodes.size());
215 int n =
static_cast<int>(
sqrt(nN));
217 std::vector<long long> nodeList(nN);
220 nodeList[0] = nodes[0];
223 nodeList[n - 1] = nodes[1];
224 nodeList[n * n - 1] = nodes[2];
225 nodeList[n * (n - 1)] = nodes[3];
231 for (
int i = 1; i < n - 1; ++i)
233 nodeList[i] = nodes[4 + i - 1];
237 for (
int i = 1; i < n - 1; ++i)
239 nodeList[n * (n - 1) + i] = nodes[4 + 2 * (n - 2) + i - 1];
242 for (
int j = 1; j < n - 1; ++j)
245 nodeList[n * (n - j - 1)] = nodes[4 + 3 * (n - 2) + n - 2 - j];
248 for (
int i = 1; i < n - 1; ++i)
250 nodeList[j * n + i] = nodes[(i - 3) - 2 * j + (3 + j) * n];
254 nodeList[(j + 1) * n - 1] = nodes[4 + (n - 2) + j - 1];
261std::vector<long long> triTensorNodeOrdering(
262 const std::vector<long long> &nodes)
264 int nN =
static_cast<int>(nodes.size());
265 int n =
static_cast<int>(
std::sqrt(2 * nN));
267 std::vector<long long> nodeList(nN);
271 nodeList[0] = nodes[0];
274 nodeList[n - 1] = nodes[1];
275 nodeList[n * (n + 1) / 2 - 1] = nodes[2];
280 for (
int i = 1; i < n - 1; ++i)
282 nodeList[i] = nodes[3 + i - 1];
283 nodeList[cnt] = nodes[3 + 3 * (n - 2) - i];
284 nodeList[cnt + n - i - 1] = nodes[3 + (n - 2) + i - 1];
292 std::vector<long long> interior((n - 3) * (n - 2) / 2);
293 std::copy(nodes.begin() + 3 + 3 * (n - 2), nodes.end(),
295 interior = triTensorNodeOrdering(interior);
300 for (
int j = 1; j < n - 2; ++j)
302 for (
int i = 0; i < n - j - 2; ++i)
304 nodeList[cnt + i + 1] = interior[cnt2 + i];
314std::vector<long long> tetTensorNodeOrdering(
315 const std::vector<long long> &nodes)
317 int nN =
static_cast<int>(nodes.size());
318 int n =
static_cast<int>(
319 std::cbrt(3 * nN +
std::sqrt(9 * nN * nN - 1 / 27)) +
320 std::cbrt(3 * nN -
std::sqrt(9 * nN * nN - 1 / 27)) - 0.5);
322 std::vector<long long> nodeList(nN);
323 int nTri = n * (n + 1) / 2;
324 int nTet = n * (n + 1) * (n + 2) / 6;
327 nodeList[0] = nodes[0];
333 nodeList[n - 1] = nodes[1];
334 nodeList[nTri - 1] = nodes[2];
335 nodeList[nTet - 1] = nodes[3];
344 std::map<Mode, int, cmpop> tmp;
345 for (
int k = 0, cnt = 0; k < n; ++k)
347 for (
int j = 0; j < n - k; ++j)
349 for (
int i = 0; i < n - k - j; ++i)
351 tmp[Mode(i, j, k)] = cnt++;
357 for (
int i = 1; i < n - 1; ++i)
360 nodeList[tmp[Mode(i, 0, 0)]] = nodes[4 + eI];
361 nodeList[tmp[Mode(n - 1 - i, i, 0)]] = nodes[4 + (n - 2) + eI];
362 nodeList[tmp[Mode(0, n - 1 - i, 0)]] = nodes[4 + 2 * (n - 2) + eI];
366 for (
int i = 1; i < n - 1; ++i)
368 int eI = (n - 1 - i) - 1;
369 nodeList[tmp[Mode(0, 0, n - 1 - i)]] = nodes[4 + 3 * (n - 2) + eI];
370 nodeList[tmp[Mode(i, 0, n - 1 - i)]] = nodes[4 + 4 * (n - 2) + eI];
371 nodeList[tmp[Mode(0, i, n - 1 - i)]] = nodes[4 + 5 * (n - 2) + eI];
381 int nFacePts = (n - 3) * (n - 2) / 2;
384 std::vector<std::vector<long long>> tmpNodes(4);
385 int offset = 4 + 6 * (n - 2);
387 for (
int i = 0; i < 4; ++i)
389 tmpNodes[i].resize(nFacePts);
390 for (
int j = 0; j < nFacePts; ++j)
392 tmpNodes[i][j] = nodes[offset++];
394 tmpNodes[i] = triTensorNodeOrdering(tmpNodes[i]);
400 std::vector<long long> triVertId(3), toAlign(3);
408 Align(triVertId, toAlign, tmpNodes[2]);
409 Align(triVertId, toAlign, tmpNodes[3]);
414 Align(triVertId, toAlign, tmpNodes[1]);
418 for (
int j = 1, cnt = 0; j < n - 2; ++j)
420 for (
int i = 1; i < n - j - 1; ++i, ++cnt)
422 nodeList[tmp[Mode(i, j, 0)]] = tmpNodes[3][cnt];
423 nodeList[tmp[Mode(i, 0, j)]] = tmpNodes[0][cnt];
424 nodeList[tmp[Mode(n - 1 - i - j, i, j)]] = tmpNodes[1][cnt];
425 nodeList[tmp[Mode(0, i, j)]] = tmpNodes[2][cnt];
435 std::vector<long long> intNodes, tmpInt;
436 for (
int i = offset; i < nTet; ++i)
438 intNodes.emplace_back(nodes[i]);
441 tmpInt = tetTensorNodeOrdering(intNodes);
443 for (
int k = 1, cnt = 0; k < n - 2; ++k)
445 for (
int j = 1; j < n - k - 1; ++j)
447 for (
int i = 1; i < n - k - j - 1; ++i)
449 nodeList[tmp[Mode(i, j, k)]] = tmpInt[cnt++];
459std::vector<long long> prismTensorNodeOrdering(
460 const std::vector<long long> &nodes)
462 int nN =
static_cast<int>(nodes.size());
463 int n =
static_cast<int>(std::cbrt(2 * nN));
465 std::vector<long long> nodeList(nN);
467 int nPrism = n * n * (n + 1) / 2;
471 nodeList[0] = nodes[0];
474 nodeList[nPrism - n] = nodes[1];
475 nodeList[n - 1] = nodes[2];
476 nodeList[nQuad - n] = nodes[3];
477 nodeList[nPrism - 1] = nodes[4];
478 nodeList[nQuad - 1] = nodes[5];
488 for (
int i = 0; i < n - 2; ++i)
493 nodeList[cnt] = nodes[nPts + i];
494 nodeList[cnt + edge - i] = nodes[nPts + 2 * edge - i - 1];
495 nodeList[i + 1] = nodes[nPts + 3 * edge - i - 1];
499 for (
int i = 1; i < n - 1; ++i)
504 nodeList[cnt - n + i] = nodes[nPts + 3 * edge + i - 1];
505 nodeList[cnt - 1] = nodes[nPts + 5 * edge - i];
506 nodeList[nQuad - i - 1] = nodes[nPts + 5 * edge + i - 1];
510 for (
int i = 1; i < n - 1; ++i)
513 nodeList[n * i] = nodes[nPts + 6 * edge + i - 1];
514 nodeList[nPrism - n + i] = nodes[nPts + 7 * edge + i - 1];
515 nodeList[n * i + n - 1] = nodes[nPts + 8 * edge + i - 1];
519 int nSmallTri = (n - 3) * (n - 2) / 2;
520 int nSmallQuad = (n - 2) * (n - 2);
521 nPts = 6 + 9 * edge + 2 * nSmallTri;
523 for (
int i = 1; i < n - 1; ++i)
525 for (
int j = 0; j < n - 2; ++j)
527 nodeList[cnt + (n - i) + (n - i) * j] =
528 nodes[nPts + j * edge + (i - 1)];
530 nodeList[cnt + 2 * (n - i) - 1 + (n - i) * j] =
531 nodes[nPts + nSmallQuad + (j + 1) * edge - i];
533 nodeList[i * n + j + 1] =
534 nodes[nPts + 2 * nSmallQuad + i * edge - j - 1];
546 std::vector<long long> tmpNodes(nSmallTri);
547 std::iota(tmpNodes.begin(), tmpNodes.end(), 0);
550 std::vector<long long> triVertId(3), toAlign(3);
558 Align(triVertId, toAlign, tmpNodes);
565 for (
int i = 1; i < n - 2; ++i)
567 for (
int j = 1; j < n - i - 1; ++j)
569 nodeList[cnt + j] = nPts + tmpNodes[cnt2++];
578 for (
int i = 1; i < n - 2; ++i)
581 for (
int j = 1; j < n - i - 1; ++j)
583 nodeList[cnt - (n - i) + j] = nPts + nSmallTri + tmpNodes[cnt2++];
588 nPts = 6 + 9 * edge + 2 * nSmallTri + 3 * nSmallQuad;
589 for (
int k = 1; k < n - 1; ++k)
593 for (
int i = 1; i < n - 2; ++i)
595 for (
int j = 1; j < n - i - 1; ++j)
597 nodeList[cnt + k * (n - i) + j] = nPts + tmpNodes[cnt2++];
609std::vector<long long> hexTensorNodeOrdering(
610 const std::vector<long long> &nodes)
612 int nN =
static_cast<int>(nodes.size());
613 int n =
static_cast<int>(std::cbrt(nN));
615 std::vector<long long> nodeList(nN);
618 nodeList[0] = nodes[0];
625 nodeList[n - 1] = nodes[1];
626 nodeList[n * n - 1] = nodes[2];
627 nodeList[n * (n - 1)] = nodes[3];
628 nodeList[n * n * (n - 1)] = nodes[4];
629 nodeList[n - 1 + n * n * (n - 1)] = nodes[5];
630 nodeList[n * n - 1 + n * n * (n - 1)] = nodes[6];
631 nodeList[n * (n - 1) + n * n * (n - 1)] = nodes[7];
638 int hexEdges[12][2] = {{0, 1},
645 {n * (n - 1), n * n},
646 {n * n * (n - 1), 1},
647 {n * n * (n - 1) + n - 1, n},
649 {n * n * (n - 1) + n * (n - 1), -n}};
650 int hexFaces[6][3] = {{0, 1, n}, {0, 1, n * n},
651 {n - 1, n, n * n}, {n * (n - 1), 1, n * n},
652 {0, n, n * n}, {n * n * (n - 1), 1, n}};
654 int gmshToNekEdge[12] = {0, 1, -2, -3, 8, 9, -10, -11, 4, 5, 6, 7};
658 for (
int i : gmshToNekEdge)
664 for (
int j = 1; j < n - 1; ++j)
666 nodeList[hexEdges[e][0] + j * hexEdges[e][1]] = nodes[offset++];
671 for (
int j = 1; j < n - 1; ++j)
673 nodeList[hexEdges[e][0] + (n - j - 1) * hexEdges[e][1]] =
680 int gmsh2NekFace[6] = {4, 2, 1, 3, 0, 5};
691 for (
int i = 0; i < 6; ++i)
693 int n2 = (n - 2) * (n - 2);
694 int face = gmsh2NekFace[i];
695 offset = 8 + 12 * (n - 2) + i * n2;
698 std::vector<long long> faceNodes(n2);
699 for (
int j = 0; j < n2; ++j)
701 faceNodes[j] = nodes[offset + j];
706 std::vector<long long> tmp(n2);
718 for (
int j = 0; j < n - 2; ++j)
720 for (
int k = 0; k < n - 2; ++k)
722 tmp[j * (n - 2) + k] = faceNodes[k * (n - 2) + j];
728 for (
int j = 0; j < n - 2; ++j)
730 for (
int k = 0; k < n - 2; ++k)
732 tmp[j * (n - 2) + k] = faceNodes[j * (n - 2) + (n - k - 3)];
738 for (
int k = 1; k < n - 1; ++k)
740 for (
int j = 1; j < n - 1; ++j)
742 nodeList[hexFaces[face][0] + j * hexFaces[face][1] +
743 k * hexFaces[face][2]] =
744 faceNodes[(k - 1) * (n - 2) + j - 1];
750 std::vector<long long> intNodes, tmpInt;
751 for (
int i = 8 + 12 * (n - 2) + 6 * (n - 2) * (n - 2); i < n * n * n; ++i)
753 intNodes.push_back(nodes[i]);
756 if (!intNodes.empty())
758 tmpInt = hexTensorNodeOrdering(intNodes);
759 for (
int k = 1, cnt = 0; k < n - 1; ++k)
761 for (
int j = 1; j < n - 1; ++j)
763 for (
int i = 1; i < n - 1; ++i)
765 nodeList[i + j * n + k * n * n] = tmpInt[cnt++];
774std::vector<long long> lowOrderMapping(
int nDim, Array<OneD, int> nquad)
776 std::vector<long long>
p;
780 for (
int j = 0; j < nquad[0] - 1; ++j)
782 for (
int k = 0; k < nquad[1] - 1; ++k)
784 for (
int l = 0; l < nquad[2] - 1; ++l)
788 {l * nquad[0] * nquad[1] + k * nquad[0] + j,
789 l * nquad[0] * nquad[1] + k * nquad[0] + j + 1,
790 l * nquad[0] * nquad[1] + (k + 1) * nquad[0] + j +
792 l * nquad[0] * nquad[1] + (k + 1) * nquad[0] + j,
793 (l + 1) * nquad[0] * nquad[1] + k * nquad[0] + j,
794 (l + 1) * nquad[0] * nquad[1] + k * nquad[0] + j +
796 (l + 1) * nquad[0] * nquad[1] +
797 (k + 1) * nquad[0] + j + 1,
798 (l + 1) * nquad[0] * nquad[1] +
799 (k + 1) * nquad[0] + j});
805 for (
int j = 0; j < nquad[0] - 1; ++j)
807 for (
int k = 0; k < nquad[1] - 1; ++k)
809 p.insert(
p.end(), {k * nquad[0] + j, k * nquad[0] + j + 1,
810 (k + 1) * nquad[0] + j + 1,
811 (k + 1) * nquad[0] + j});
816 for (
int j = 0; j < nquad[0] - 1; ++j)
818 p.insert(
p.end(), {j, j + 1});
828int GetHighOrderVtkCellType([[maybe_unused]]
int sType)
830#if VTK_MAJOR_VERSION >= 8
832 static const std::map<int, int> vtkCellType = {
841 return vtkCellType.at(sType);
845 "High-order VTK output requires minimum VTK library version of 8.0")
855 vtkSmartPointer<vtkUnstructuredGrid> vtkMesh =
856 vtkSmartPointer<vtkUnstructuredGrid>::New();
859 std::unordered_map<size_t, std::vector<long long>> mappingCache;
862 int nDim =
m_f->m_exp[0]->GetShapeDimension();
863 int nHomoDir =
m_f->m_numHomogeneousDir;
865 auto type = (nDim + nHomoDir == 3) ? VTK_HEXAHEDRON
866 : (nDim + nHomoDir == 2) ? VTK_QUAD
868 int nQpts = (nDim + nHomoDir == 3) ? 8 : (nDim + nHomoDir == 2) ? 4 : 2;
875 "Only regular expansions and the 3DH1D homogeneous expansion "
876 "are supported in the new VTK writer. Please use the 'legacy' "
877 "option for all other expansion types.")
879 m_numPlanes =
m_f->m_exp[0]->GetHomogeneousBasis()->GetNumModes();
881 m_extraPlane = (
m_f->m_exp[0]->GetHomogeneousBasis()->GetBasisType() ==
883 m_f->m_exp[0]->GetHomogeneousBasis()->GetPointsType() ==
888 vtkNew<vtkPoints> vtkPoints;
889 vtkPoints->SetDataType(VTK_DOUBLE);
892 int nElmts =
static_cast<int>(
m_f->m_exp[0]->GetNumElmts());
893 for (
int i = 0; i < nElmts; ++i)
896 for (
int j = 0; j < nDim; ++j)
898 nquad[j] =
m_f->m_exp[0]->GetExp(i)->GetNumPoints(j);
916 for (
int j = 1; j < nDim + nHomoDir; ++j)
923 m_f->m_exp[0]->GetCoords(i, x, y,
z);
931 tmp = x + (nquad[2] - 1) * nquad[0] * nquad[1], 1);
933 tmp = y + (nquad[2] - 1) * nquad[0] * nquad[1], 1);
936 NekDouble zDouble =
z[nquad[0] * nquad[1] * (nquad[2] - 1) - 1] +
937 (
z[nquad[0] * nquad[1]] -
z[0]);
939 tmp =
z + (nquad[2] - 1) * nquad[0] * nquad[1], 1);
943 for (
int j = 0; j < nPts; ++j)
945 vtkPoints->InsertNextPoint(x[j], y[j],
z[j]);
949 auto oIt = mappingCache.find(key3(nquad[0], nquad[1], nquad[2]));
950 if (oIt == mappingCache.end())
952 auto p = lowOrderMapping(nDim + nHomoDir, nquad);
955 std::make_pair(key3(nquad[0], nquad[1], nquad[2]),
p))
959 auto p = oIt->second;
960 std::for_each(
p.begin(),
p.end(),
961 [offset](
long long &
d) { d += offset; });
962 for (
int j = 0; j <
p.size(); j += nQpts)
964 vtkMesh->InsertNextCell(type, nQpts, &
p[j]);
970 vtkMesh->SetPoints(vtkPoints.GetPointer());
976 po::variables_map &vm, std::string &filename,
977 vtkSmartPointer<vtkUnstructuredGrid> &vtkMesh)
981 int nElmts =
static_cast<int>(
m_f->m_exp[0]->GetNumElmts());
983 for (
int v = 0; v <
m_f->m_variables.size(); ++v)
985 vtkNew<vtkDoubleArray> fieldData;
986 for (
int i = 0; i < nElmts; ++i)
988 int elmtOffset =
m_f->m_exp[v]->GetPhys_Offset(i);
989 int nPtsPerElmtPerPlane =
m_f->m_exp[v]->GetExp(i)->GetTotPoints();
993 int planeOffset = j * numPtsPerPlane;
994 for (
int k = 0; k < nPtsPerElmtPerPlane; ++k)
996 fieldData->InsertNextValue(
997 m_f->m_exp[v]->GetPhys()[elmtOffset + planeOffset + k]);
1004 for (
int k = 0; k < nPtsPerElmtPerPlane; ++k)
1006 fieldData->InsertNextValue(
1007 m_f->m_exp[v]->GetPhys()[elmtOffset + k]);
1012 fieldData->SetName(&
m_f->m_variables[v][0]);
1013 vtkMesh->GetPointData()->AddArray(fieldData.GetPointer());
1023 std::string &filename)
1026 m_f->m_numHomogeneousDir == 0,
1027 "Multi block VTK is not implemented for homogeneous expansion types.")
1030 "Multi block VTK is not implemented in parallel.")
1032 int dim =
m_f->m_graph->GetMeshDimension();
1035 std::array<std::map<int, std::pair<int, int>>, 4> geomIdToExpId;
1036 int nElmts =
static_cast<int>(
m_f->m_exp[0]->GetNumElmts());
1037 for (
int i = 0; i < nElmts; ++i)
1039 auto geom =
m_f->m_exp[0]->GetExp(i)->GetGeom();
1040 geomIdToExpId[geom->GetShapeDim()][geom->GetGlobalID()] =
1041 std::make_pair(i, -1);
1043 for (
int j = 0; j < geom->GetNumFaces(); ++j)
1045 geomIdToExpId[2][geom->GetFid(j)] = std::make_pair(i, j);
1048 for (
int j = 0; j < geom->GetNumEdges(); ++j)
1050 geomIdToExpId[1][geom->GetEid(j)] = std::make_pair(i, j);
1055 std::unordered_map<size_t, std::vector<long long>> mappingCache;
1057 std::map<int, vtkNew<vtkUnstructuredGrid>> vtkMesh;
1058 std::map<int, SpatialDomains::CompositeSharedPtr> composites =
1059 m_f->m_graph->GetComposites();
1060 std::map<int, std::string> compositeNames;
1061 for (
auto &comp : composites)
1064 std::vector<vtkNew<vtkDoubleArray>> fieldData(
m_f->m_variables.size());
1067 vtkNew<vtkPoints> vtkPoints;
1068 vtkPoints->SetDataType(VTK_DOUBLE);
1070 int compId = comp.first;
1071 std::vector<std::shared_ptr<SpatialDomains::Geometry>> geomVec =
1072 comp.second->m_geomVec;
1074 unsigned int offset = 0;
1075 for (
auto &geom : geomVec)
1077 int geomId = geom->GetGlobalID();
1078 int sDim = geom->GetShapeDim();
1079 auto type = (sDim == 3) ? VTK_HEXAHEDRON
1080 : (sDim == 2) ? VTK_QUAD
1082 int nQpts = (sDim == 3) ? 8 : (sDim == 2) ? 4 : 2;
1085 m_f->m_exp[0]->GetExp(geomIdToExpId[sDim][geomId].first);
1087 unsigned int nPts = exp->GetTotPoints();
1089 exp->GetCoords(x, y,
z);
1091 int offsetPhys =
m_f->m_exp[0]->GetPhys_Offset(
1092 geomIdToExpId[sDim][geomId].first);
1095 for (
int j = 0; j < nPts; ++j)
1097 vtkPoints->InsertNextPoint(x[j], y[j],
z[j]);
1100 for (
int k = 0; k <
m_f->m_variables.size(); ++k)
1102 fieldData[k]->InsertNextValue(
1103 m_f->m_exp[k]->GetPhys()[j + offsetPhys]);
1110 exp->GetTracePhysMap(geomIdToExpId[sDim][geomId].second,
1112 for (
int j : pointsMap)
1114 vtkPoints->InsertNextPoint(x[j], y[j],
z[j]);
1117 for (
int k = 0; k <
m_f->m_variables.size(); ++k)
1119 fieldData[k]->InsertNextValue(
1120 m_f->m_exp[k]->GetPhys()[offsetPhys + j]);
1124 exp = exp->GetTraceExp(geomIdToExpId[sDim][geomId].second);
1125 nPts = pointsMap.size();
1129 for (
int j = 0; j < sDim; ++j)
1131 nquad[j] = exp->GetNumPoints(j);
1134 auto oIt = mappingCache.find(key3(nquad[0], nquad[1], nquad[2]));
1135 if (oIt == mappingCache.end())
1137 auto p = lowOrderMapping(sDim, nquad);
1139 .insert(std::make_pair(
1140 key3(nquad[0], nquad[1], nquad[2]),
p))
1144 auto p = oIt->second;
1145 std::for_each(
p.begin(),
p.end(),
1146 [offset](
long long &
d) { d += offset; });
1148 for (
int j = 0; j <
p.size(); j += nQpts)
1150 vtkMesh[compId]->InsertNextCell(type, nQpts, &
p[j]);
1156 vtkMesh[compId]->SetPoints(vtkPoints.GetPointer());
1159 for (
int k = 0; k <
m_f->m_variables.size(); ++k)
1161 fieldData[k]->SetName(&
m_f->m_variables[k][0]);
1162 vtkMesh[compId]->GetPointData()->AddArray(
1163 fieldData[k].GetPointer());
1168 compositeNames[compId] =
"Composite ID " + std::to_string(compId);
1169 auto clabels =
m_f->m_graph->GetCompositesLabels();
1170 auto oIt = clabels.find(compId);
1171 if (oIt != clabels.end())
1173 compositeNames[compId] = oIt->second;
1178 vtkNew<vtkMultiBlockDataSet> mainBlock;
1180 std::set<int> compSet;
1183 vtkNew<vtkMultiBlockDataSet> mainDomainBlock;
1184 auto domains =
m_f->m_graph->GetDomain();
1185 std::vector<vtkNew<vtkMultiBlockDataSet>> domainMultiBlocks(domains.size());
1186 for (
int i = 0; i < domains.size(); ++i)
1188 auto dom = domains[i];
1191 for (
auto &comp : composites)
1193 int compId = comp.first;
1194 if (dom.find(compId) != dom.end())
1196 unsigned int nBlock = domainMultiBlocks[i]->GetNumberOfBlocks();
1197 domainMultiBlocks[i]->SetBlock(nBlock,
1198 vtkMesh[compId].GetPointer());
1199 domainMultiBlocks[i]->GetMetaData(nBlock)->Set(
1200 vtkCompositeDataSet::NAME(),
1201 compositeNames[compId].c_str());
1202 compSet.insert(compId);
1206 unsigned int nBlock = mainDomainBlock->GetNumberOfBlocks();
1207 mainDomainBlock->SetBlock(nBlock, domainMultiBlocks[i].GetPointer());
1208 mainDomainBlock->GetMetaData(nBlock)->Set(
1209 vtkCompositeDataSet::NAME(),
1210 (
"Domain ID " + std::to_string(i)).c_str());
1213 if (mainDomainBlock->GetNumberOfBlocks() != 0)
1215 auto nBlock =
static_cast<unsigned int>(mainBlock->GetNumberOfBlocks());
1216 mainBlock->SetBlock(nBlock, mainDomainBlock.GetPointer());
1217 mainBlock->GetMetaData(nBlock)->Set(vtkCompositeDataSet::NAME(),
1223 m_f->m_exp[0]->GetGraph());
1227 vtkNew<vtkMultiBlockDataSet> mainBoundaryBlock;
1228 std::vector<vtkNew<vtkMultiBlockDataSet>> boundaryMultiBlocks(
1231 for (
auto &boundary : bregions)
1234 for (
auto &comp : composites)
1236 int compId = comp.first;
1237 if (boundary.second->find(compId) != boundary.second->end())
1239 unsigned int nBlock =
1240 boundaryMultiBlocks[cnt]->GetNumberOfBlocks();
1241 boundaryMultiBlocks[cnt]->SetBlock(
1242 nBlock, vtkMesh[compId].GetPointer());
1243 boundaryMultiBlocks[cnt]->GetMetaData(nBlock)->Set(
1244 vtkCompositeDataSet::NAME(),
1245 compositeNames[compId].c_str());
1246 compSet.insert(compId);
1250 unsigned int nBlock = mainBoundaryBlock->GetNumberOfBlocks();
1251 mainBoundaryBlock->SetBlock(nBlock,
1252 boundaryMultiBlocks[cnt++].GetPointer());
1255 std::string
name =
"Boundary ID " + std::to_string(boundary.first);
1257 auto oIt = blabels.find(boundary.first);
1258 if (oIt != blabels.end())
1263 mainBoundaryBlock->GetMetaData(nBlock)->Set(vtkCompositeDataSet::NAME(),
1267 if (mainBoundaryBlock->GetNumberOfBlocks() != 0)
1269 auto nBlock =
static_cast<unsigned int>(mainBlock->GetNumberOfBlocks());
1270 mainBlock->SetBlock(nBlock, mainBoundaryBlock.GetPointer());
1271 mainBlock->GetMetaData(nBlock)->Set(vtkCompositeDataSet::NAME(),
1276 vtkNew<vtkMultiBlockDataSet> compsMultiBlocks;
1278 for (
auto &comp : composites)
1280 int compId = comp.first;
1281 if (compSet.find(compId) == compSet.end())
1283 unsigned int nBlock = compsMultiBlocks->GetNumberOfBlocks();
1284 compsMultiBlocks->SetBlock(nBlock, vtkMesh[compId].GetPointer());
1285 compsMultiBlocks->GetMetaData(nBlock)->Set(
1286 vtkCompositeDataSet::NAME(), compositeNames[compId].c_str());
1290 if (compsMultiBlocks->GetNumberOfBlocks() != 0)
1292 auto nBlock =
static_cast<unsigned int>(mainBlock->GetNumberOfBlocks());
1293 mainBlock->SetBlock(nBlock, compsMultiBlocks.GetPointer());
1294 mainBlock->GetMetaData(nBlock)->Set(vtkCompositeDataSet::NAME(),
1295 "Other composites");
1300 WriteVTK(mainBlock.GetPointer(), filename, vm);
1305 po::variables_map &vm)
1308 m_f->m_numHomogeneousDir == 0,
1309 "High order VTK is not implemented for homogeneous expansion types.")
1313 std::vector<LibUtilities::ShapeType> sType;
1314 for (
auto &i : *
m_f->m_exp[0]->GetExp())
1316 sType.emplace_back(i->GetGeom()->GetShapeType());
1322 equispaced->Process(vm);
1325 vtkNew<vtkPoints> vtkPoints;
1327 vtkPoints->SetDataType(VTK_DOUBLE);
1332 int dim =
static_cast<int>(fPts->GetDim());
1333 int nPts =
static_cast<int>(fPts->GetNpoints());
1337 for (
int i = 0; i < nPts; ++i)
1339 vtkPoints->InsertNextPoint(pts[0][i], pts[1][i], pts[2][i]);
1343 for (
int i = 0; i < nPts; ++i)
1345 vtkPoints->InsertNextPoint(pts[0][i], pts[1][i], 0.0);
1349 for (
int i = 0; i < nPts; ++i)
1351 vtkPoints->InsertNextPoint(pts[0][i], 0.0, 0.0);
1359 vtkSmartPointer<vtkUnstructuredGrid> vtkMesh =
1360 vtkSmartPointer<vtkUnstructuredGrid>::New();
1361 vtkMesh->SetPoints(vtkPoints.GetPointer());
1364 std::unordered_map<size_t, std::vector<long long>> mappingCache;
1367 std::vector<int> ppe =
m_f->m_fieldPts->GetPointsPerElement();
1369 std::partial_sum(ppe.begin(), ppe.end(), &ppeOffset[1]);
1372 for (
int i = 0; i < ppe.size(); ++i)
1376 auto oIt = mappingCache.find(key2(sType[i], ppe[i]));
1377 if (oIt == mappingCache.end())
1379 std::vector<long long>
p(ppe[i]);
1380 std::iota(
p.begin(),
p.end(), 0);
1384 p = quadTensorNodeOrdering(
p);
1387 p = triTensorNodeOrdering(
p);
1390 p = tetTensorNodeOrdering(
p);
1393 p = hexTensorNodeOrdering(
p);
1396 p = prismTensorNodeOrdering(
p);
1400 "High-order VTU output not set up for the " +
1401 static_cast<std::string
>(
1408 std::vector<long long> inv(ppe[i]);
1409 for (
int j = 0; j < ppe[i]; ++j)
1415 mappingCache.insert(std::make_pair(key2(sType[i], ppe[i]), inv))
1420 std::vector<long long>
p = oIt->second;
1421 for (
long long &j :
p)
1426 vtkMesh->InsertNextCell(GetHighOrderVtkCellType(sType[i]), ppe[i],
1434 po::variables_map &vm, std::string &filename,
1435 vtkSmartPointer<vtkUnstructuredGrid> &vtkMesh)
1442 equispaced->Process(vm);
1446 int nPts =
static_cast<int>(fPts->GetNpoints());
1447 int dim =
static_cast<int>(fPts->GetDim());
1453 for (
int i = 0; i < fPts->GetNFields(); ++i)
1455 vtkNew<vtkDoubleArray> fieldData;
1456 fieldData->SetArray(&pts[dim + i][0], nPts, 1);
1457 fieldData->SetName(&fPts->GetFieldName(i)[0]);
1458 vtkMesh->GetPointData()->AddArray(fieldData.GetPointer());
1468 po::variables_map &vm)
1471 vtkSmartPointer<vtkXMLWriter> vtkMeshWriter =
1472 vtkNew<vtkXMLUnstructuredGridWriter>().GetPointer();
1475 if (
m_config[
"multiblock"].m_beenSet)
1477 vtkMeshWriter = vtkNew<vtkXMLMultiBlockDataWriter>().GetPointer();
1481 int dot =
static_cast<int>(filename.find_last_of(
'.'));
1482 std::string body = filename.substr(0, dot + 1);
1483 filename = body + vtkMeshWriter->GetDefaultFileExtension();
1486 if (!
m_f->m_fieldMetaDataMap[
"Time"].empty())
1488 vtkMesh->GetInformation()->Set(
1489 vtkDataObject::DATA_TIME_STEP(),
1490 std::stod(
m_f->m_fieldMetaDataMap[
"Time"]));
1492 else if (!
m_f->m_fieldMetaDataMap[
"FinalTime"].empty())
1494 vtkMesh->GetInformation()->Set(
1495 vtkDataObject::DATA_TIME_STEP(),
1496 std::stod(
m_f->m_fieldMetaDataMap[
"FinalTime"]));
1501 vtkMeshWriter->SetFileName(filename.c_str());
1503#if VTK_MAJOR_VERSION <= 5
1504 vtkMeshWriter->SetInput(vtkMesh);
1506 vtkMeshWriter->SetInputData(vtkMesh);
1509 if (
m_config[
"uncompress"].m_beenSet)
1511 vtkMeshWriter->SetDataModeToAscii();
1514 vtkMeshWriter->Update();
1516 std::cout <<
"Written file: " << filename << std::endl;
1522 if (
m_f->m_comm->GetSpaceComm()->TreatAsRankZero() &&
1523 !
m_f->m_comm->GetSpaceComm()->IsSerial())
1531 std::string filename =
m_config[
"outfile"].as<std::string>();
1532 int dot =
static_cast<int>(filename.find_last_of(
'.'));
1533 std::string body = filename.substr(0, dot);
1534 filename = body +
".pvtu";
1536 std::ofstream outfile(filename.c_str());
1538 int nprocs =
m_f->m_comm->GetSpaceComm()->GetSize();
1542 outfile <<
"<?xml version=\"1.0\"?>" << endl;
1543 outfile << R
"(<VTKFile type="PUnstructuredGrid" version="0.1" )"
1544 << "byte_order=\"LittleEndian\">" << endl;
1545 outfile <<
" <PUnstructuredGrid GhostLevel=\"0\">" << endl;
1548 if (!
m_f->m_fieldMetaDataMap[
"Time"].empty())
1550 outfile <<
" <FieldData> " << endl;
1551 outfile <<
" <DataArray type=\"Float64\" Name=\"TimeValue\" "
1552 "NumberOfTuples=\"1\" format=\"ascii\">"
1554 outfile <<
m_f->m_fieldMetaDataMap[
"Time"] << std::endl;
1555 outfile <<
" </DataArray>" << std::endl;
1556 outfile <<
" </FieldData> " << endl;
1560 outfile <<
" <PPoints> " << endl;
1561 outfile << R
"( <PDataArray type="Float64" NumberOfComponents=")" << 3
1563 outfile <<
" </PPoints>" << endl;
1566 outfile <<
" <PCells>" << endl;
1567 outfile <<
" <PDataArray type=\"Int64\" Name=\"connectivity\" "
1568 "NumberOfComponents=\"1\"/>"
1570 outfile <<
" <PDataArray type=\"Int64\" Name=\"offsets\" "
1571 "NumberOfComponents=\"1\"/>"
1573 outfile <<
" <PDataArray type=\"UInt8\" Name=\"types\" "
1574 "NumberOfComponents=\"1\"/>"
1576 outfile <<
" </PCells>" << endl;
1579 outfile <<
" <PPointData>" << endl;
1580 for (
auto &var :
m_f->m_variables)
1582 outfile << R
"( <PDataArray type="Float64" Name=")" << var << "\"/>"
1585 outfile <<
" </PPointData>" << endl;
1588 for (
int i = 0; i < nprocs; ++i)
1592 outfile <<
" <Piece Source=\"" << path <<
"/" << pad.str() <<
"\"/>"
1595 outfile <<
" </PUnstructuredGrid>" << endl;
1596 outfile <<
"</VTKFile>" << endl;
1598 cout <<
"Written file: " << filename << endl;
1604 "OutputVtk can't write using only FieldData. You may need "
1605 "to add a mesh XML file to your input files.");
1617 if (
m_f->m_graph->GetMovement()->GetMoveFlag())
1619 if (!
m_f->m_fieldMetaDataMap[
"Time"].empty())
1621 m_f->m_graph->GetMovement()->PerformMovement(
1622 std::stod(
m_f->m_fieldMetaDataMap[
"Time"]));
1623 for (
auto &i :
m_f->m_exp)
1633 "Multi block VTK is not implemented for legacy output.")
1636 "High order VTK is not implemented for legacy output.")
1643 std::string filename;
1653 if (!
m_f->m_graph->GetMovement()->GetMoveFlag())
1658 if (
m_config[
"highorder"].m_beenSet)
1661 "Multi block VTK is not implemented for high-order output.")
1670 else if (
m_config[
"multiblock"].m_beenSet)
#define ASSERTL0(condition, msg)
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
FieldSharedPtr m_f
Field object.
std::map< std::string, ConfigOption > m_config
List of configuration values.
Converter from fld to vtk.
std::string PrepareOutput(po::variables_map &vm)
fs::path v_GetPath(std::string &filename, po::variables_map &vm) override
void v_OutputFromExp(po::variables_map &vm) override
Write from m_exp to output file.
void v_OutputFromPts(po::variables_map &vm) override
Write from pts to output file.
vtkSmartPointer< vtkUnstructuredGrid > OutputFromExpLowOrder()
Prepare low order VTK output.
void AddFieldDataToVTKHighOrder(po::variables_map &vm, std::string &filename, vtkSmartPointer< vtkUnstructuredGrid > &vtkMesh)
Add field data to high order Lagrange VTK output.
void OutputFromExpLowOrderMultiBlock(po::variables_map &vm, std::string &filename)
Prepare low order multi-block VTK output & add field data.
OutputVtk(FieldSharedPtr f)
vtkSmartPointer< vtkUnstructuredGrid > m_vtkMesh
Cache file for unstructured grid VTK mesh data.
void v_OutputFromExp(po::variables_map &vm) final
Write from m_exp to output file.
void v_OutputFromPts(po::variables_map &vm) final
Write from pts to output file.
bool m_extraPlane
Flag if extra plane in case of fourier expansion in homogeneous dir.
int m_numPlanes
Number of planes if homogeneous.
void v_OutputFromData(po::variables_map &vm) final
Write from data to output file.
void AddFieldDataToVTKLowOrder(po::variables_map &vm, std::string &filename, vtkSmartPointer< vtkUnstructuredGrid > &vtkMesh)
Add field data to low order VTK output.
void WriteVTK(vtkDataObject *vtkMesh, std::string &filename, po::variables_map &vm)
Write VTK file using.
vtkSmartPointer< vtkUnstructuredGrid > OutputFromExpHighOrder(po::variables_map &vm)
Prepare high order Lagrange VTK output.
static ModuleKey m_className
bool m_cachedMesh
Flag if mesh has been cached.
static std::shared_ptr< Module > create(const FieldSharedPtr &f)
Creates an instance of this class.
void WritePVtu(po::variables_map &vm)
Write the parallel .pvtu file.
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
const std::map< int, std::string > & GetBoundaryLabels(void) const
const BoundaryRegionCollection & GetBoundaryRegions(void) const
std::shared_ptr< Field > FieldSharedPtr
std::pair< ModuleType, std::string > ModuleKey
ModuleFactory & GetModuleFactory()
const char *const ShapeTypeMap[SIZE_ShapeType]
static std::string PortablePath(const fs::path &path)
create portable path on different platforms for std::filesystem path.
std::shared_ptr< PtsField > PtsFieldSharedPtr
@ eFourierEvenlySpaced
1D Evenly-spaced points using Fourier Fit
@ eFourier
Fourier Expansion .
std::shared_ptr< Expansion > ExpansionSharedPtr
std::map< int, BoundaryRegionShPtr > BoundaryRegionCollection
@ eDir1FwdDir1_Dir2FwdDir2
@ eDir1BwdDir1_Dir2FwdDir2
@ eDir1FwdDir2_Dir2FwdDir1
std::vector< double > z(NPUPPER)
std::vector< double > d(NPUPPER *NPUPPER)
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
scalarT< T > abs(scalarT< T > in)
scalarT< T > sqrt(scalarT< T > in)
Represents a command-line configuration option.