35#include <boost/core/ignore_unused.hpp>
36#include <boost/format.hpp>
42#include <vtkCellType.h>
43#include <vtkDoubleArray.h>
44#include <vtkInformation.h>
45#include <vtkMultiBlockDataSet.h>
46#include <vtkPointData.h>
48#include <vtkXMLMultiBlockDataWriter.h>
49#include <vtkXMLUnstructuredGridWriter.h>
63 ConfigOption(
true,
"0",
"Output using legacy manual file writers");
65 true,
"0",
"Output using new high-order Lagrange elements");
67 true,
"0",
"Output using multi-blocks to separate composites");
76inline size_t key2(
int i,
int j)
78 return (
size_t)i << 32 | (
unsigned int)j;
82inline size_t key3(
int i,
int j,
int k)
84 return (
size_t)i << 10 ^ j << 5 ^ k;
88typedef std::tuple<int, int, int>
Mode;
92 bool operator()(
Mode const &a,
Mode const &b)
const
94 if (std::get<0>(a) < std::get<0>(b))
98 if (std::get<0>(a) > std::get<0>(b))
102 if (std::get<1>(a) < std::get<1>(b))
106 if (std::get<1>(a) > std::get<1>(b))
110 if (std::get<2>(a) < std::get<2>(b))
119void Rotate(
int nrot, std::vector<long long> &surfVerts)
122 int np =
static_cast<int>(
123 (
sqrt(8.0 *
static_cast<int>(surfVerts.size()) + 1.0) - 1) / 2);
124 std::vector<long long> tmp(np * np);
126 for (n = 0; n < nrot; ++n)
128 for (cnt = i = 0; i < np; ++i)
130 for (j = 0; j < np - i; ++j, cnt++)
132 tmp[i * np + j] = surfVerts[cnt];
135 for (cnt = i = 0; i < np; ++i)
137 for (j = 0; j < np - i; ++j, cnt++)
139 surfVerts[cnt] = tmp[(np - 1 - i - j) * np + i];
145void Reflect(std::vector<long long> &surfVerts)
148 int np =
static_cast<int>(
149 (
sqrt(8.0 *
static_cast<double>(surfVerts.size()) + 1.0) - 1) / 2);
150 std::vector<long long> tmp(np * np);
152 for (cnt = i = 0; i < np; ++i)
154 for (j = 0; j < np - i; ++j, cnt++)
156 tmp[i * np + np - i - 1 - j] = surfVerts[cnt];
160 for (cnt = i = 0; i < np; ++i)
162 for (j = 0; j < np - i; ++j, cnt++)
164 surfVerts[cnt] = tmp[i * np + j];
169void Align(std::vector<long long> thisVertId, std::vector<long long> vertId,
170 std::vector<long long> &surfVerts)
172 if (vertId[0] == thisVertId[0])
174 if (vertId[1] == thisVertId[1] || vertId[1] == thisVertId[2])
176 if (vertId[1] == thisVertId[2])
178 Rotate(1, surfVerts);
183 else if (vertId[0] == thisVertId[1])
185 if (vertId[1] == thisVertId[0] || vertId[1] == thisVertId[2])
187 if (vertId[1] == thisVertId[0])
193 Rotate(2, surfVerts);
197 else if (vertId[0] == thisVertId[2])
199 if (vertId[1] == thisVertId[0] || vertId[1] == thisVertId[1])
201 if (vertId[1] == thisVertId[1])
203 Rotate(2, surfVerts);
208 Rotate(1, surfVerts);
214std::vector<long long> quadTensorNodeOrdering(
215 const std::vector<long long> &nodes)
217 int nN =
static_cast<int>(nodes.size());
218 int n =
static_cast<int>(
sqrt(nN));
220 std::vector<long long> nodeList(nN);
223 nodeList[0] = nodes[0];
226 nodeList[n - 1] = nodes[1];
227 nodeList[n * n - 1] = nodes[2];
228 nodeList[n * (n - 1)] = nodes[3];
234 for (
int i = 1; i < n - 1; ++i)
236 nodeList[i] = nodes[4 + i - 1];
240 for (
int i = 1; i < n - 1; ++i)
242 nodeList[n * (n - 1) + i] = nodes[4 + 2 * (n - 2) + i - 1];
245 for (
int j = 1; j < n - 1; ++j)
248 nodeList[n * (n - j - 1)] = nodes[4 + 3 * (n - 2) + n - 2 - j];
251 for (
int i = 1; i < n - 1; ++i)
253 nodeList[j * n + i] = nodes[(i - 3) - 2 * j + (3 + j) * n];
257 nodeList[(j + 1) * n - 1] = nodes[4 + (n - 2) + j - 1];
264std::vector<long long> triTensorNodeOrdering(
265 const std::vector<long long> &nodes)
267 int nN =
static_cast<int>(nodes.size());
268 int n =
static_cast<int>(
std::sqrt(2 * nN));
270 std::vector<long long> nodeList(nN);
274 nodeList[0] = nodes[0];
277 nodeList[n - 1] = nodes[1];
278 nodeList[n * (n + 1) / 2 - 1] = nodes[2];
283 for (
int i = 1; i < n - 1; ++i)
285 nodeList[i] = nodes[3 + i - 1];
286 nodeList[cnt] = nodes[3 + 3 * (n - 2) - i];
287 nodeList[cnt + n - i - 1] = nodes[3 + (n - 2) + i - 1];
295 std::vector<long long> interior((n - 3) * (n - 2) / 2);
296 std::copy(nodes.begin() + 3 + 3 * (n - 2), nodes.end(),
298 interior = triTensorNodeOrdering(interior);
303 for (
int j = 1; j < n - 2; ++j)
305 for (
int i = 0; i < n - j - 2; ++i)
307 nodeList[cnt + i + 1] = interior[cnt2 + i];
317std::vector<long long> tetTensorNodeOrdering(
318 const std::vector<long long> &nodes)
320 int nN =
static_cast<int>(nodes.size());
321 int n =
static_cast<int>(
322 std::cbrt(3 * nN +
std::sqrt(9 * nN * nN - 1 / 27)) +
323 std::cbrt(3 * nN -
std::sqrt(9 * nN * nN - 1 / 27)) - 0.5);
325 std::vector<long long> nodeList(nN);
326 int nTri = n * (n + 1) / 2;
327 int nTet = n * (n + 1) * (n + 2) / 6;
330 nodeList[0] = nodes[0];
336 nodeList[n - 1] = nodes[1];
337 nodeList[nTri - 1] = nodes[2];
338 nodeList[nTet - 1] = nodes[3];
347 std::map<Mode, int, cmpop> tmp;
348 for (
int k = 0, cnt = 0; k < n; ++k)
350 for (
int j = 0; j < n - k; ++j)
352 for (
int i = 0; i < n - k - j; ++i)
354 tmp[
Mode(i, j, k)] = cnt++;
360 for (
int i = 1; i < n - 1; ++i)
363 nodeList[tmp[
Mode(i, 0, 0)]] = nodes[4 + eI];
364 nodeList[tmp[
Mode(n - 1 - i, i, 0)]] = nodes[4 + (n - 2) + eI];
365 nodeList[tmp[
Mode(0, n - 1 - i, 0)]] = nodes[4 + 2 * (n - 2) + eI];
369 for (
int i = 1; i < n - 1; ++i)
371 int eI = (n - 1 - i) - 1;
372 nodeList[tmp[
Mode(0, 0, n - 1 - i)]] = nodes[4 + 3 * (n - 2) + eI];
373 nodeList[tmp[
Mode(i, 0, n - 1 - i)]] = nodes[4 + 4 * (n - 2) + eI];
374 nodeList[tmp[
Mode(0, i, n - 1 - i)]] = nodes[4 + 5 * (n - 2) + eI];
384 int nFacePts = (n - 3) * (n - 2) / 2;
387 std::vector<std::vector<long long>> tmpNodes(4);
388 int offset = 4 + 6 * (n - 2);
390 for (
int i = 0; i < 4; ++i)
392 tmpNodes[i].resize(nFacePts);
393 for (
int j = 0; j < nFacePts; ++j)
395 tmpNodes[i][j] = nodes[offset++];
397 tmpNodes[i] = triTensorNodeOrdering(tmpNodes[i]);
403 std::vector<long long> triVertId(3), toAlign(3);
411 Align(triVertId, toAlign, tmpNodes[2]);
412 Align(triVertId, toAlign, tmpNodes[3]);
417 Align(triVertId, toAlign, tmpNodes[1]);
421 for (
int j = 1, cnt = 0; j < n - 2; ++j)
423 for (
int i = 1; i < n - j - 1; ++i, ++cnt)
425 nodeList[tmp[
Mode(i, j, 0)]] = tmpNodes[3][cnt];
426 nodeList[tmp[
Mode(i, 0, j)]] = tmpNodes[0][cnt];
427 nodeList[tmp[
Mode(n - 1 - i - j, i, j)]] = tmpNodes[1][cnt];
428 nodeList[tmp[
Mode(0, i, j)]] = tmpNodes[2][cnt];
438 std::vector<long long> intNodes, tmpInt;
439 for (
int i = offset; i < nTet; ++i)
441 intNodes.emplace_back(nodes[i]);
444 tmpInt = tetTensorNodeOrdering(intNodes);
446 for (
int k = 1, cnt = 0; k < n - 2; ++k)
448 for (
int j = 1; j < n - k - 1; ++j)
450 for (
int i = 1; i < n - k - j - 1; ++i)
452 nodeList[tmp[
Mode(i, j, k)]] = tmpInt[cnt++];
462std::vector<long long> prismTensorNodeOrdering(
463 const std::vector<long long> &nodes)
465 int nN =
static_cast<int>(nodes.size());
466 int n =
static_cast<int>(std::cbrt(2 * nN));
468 std::vector<long long> nodeList(nN);
470 int nPrism = n * n * (n + 1) / 2;
474 nodeList[0] = nodes[0];
477 nodeList[nPrism - n] = nodes[1];
478 nodeList[n - 1] = nodes[2];
479 nodeList[nQuad - n] = nodes[3];
480 nodeList[nPrism - 1] = nodes[4];
481 nodeList[nQuad - 1] = nodes[5];
491 for (
int i = 0; i < n - 2; ++i)
496 nodeList[cnt] = nodes[nPts + i];
497 nodeList[cnt + edge - i] = nodes[nPts + 2 * edge - i - 1];
498 nodeList[i + 1] = nodes[nPts + 3 * edge - i - 1];
502 for (
int i = 1; i < n - 1; ++i)
507 nodeList[cnt - n + i] = nodes[nPts + 3 * edge + i - 1];
508 nodeList[cnt - 1] = nodes[nPts + 5 * edge - i];
509 nodeList[nQuad - i - 1] = nodes[nPts + 5 * edge + i - 1];
513 for (
int i = 1; i < n - 1; ++i)
516 nodeList[n * i] = nodes[nPts + 6 * edge + i - 1];
517 nodeList[nPrism - n + i] = nodes[nPts + 7 * edge + i - 1];
518 nodeList[n * i + n - 1] = nodes[nPts + 8 * edge + i - 1];
522 int nSmallTri = (n - 3) * (n - 2) / 2;
523 int nSmallQuad = (n - 2) * (n - 2);
524 nPts = 6 + 9 * edge + 2 * nSmallTri;
526 for (
int i = 1; i < n - 1; ++i)
528 for (
int j = 0; j < n - 2; ++j)
530 nodeList[cnt + (n - i) + (n - i) * j] =
531 nodes[nPts + j * edge + (i - 1)];
533 nodeList[cnt + 2 * (n - i) - 1 + (n - i) * j] =
534 nodes[nPts + nSmallQuad + (j + 1) * edge - i];
536 nodeList[i * n + j + 1] =
537 nodes[nPts + 2 * nSmallQuad + i * edge - j - 1];
549 std::vector<long long> tmpNodes(nSmallTri);
550 std::iota(tmpNodes.begin(), tmpNodes.end(), 0);
553 std::vector<long long> triVertId(3), toAlign(3);
561 Align(triVertId, toAlign, tmpNodes);
568 for (
int i = 1; i < n - 2; ++i)
570 for (
int j = 1; j < n - i - 1; ++j)
572 nodeList[cnt + j] = nPts + tmpNodes[cnt2++];
581 for (
int i = 1; i < n - 2; ++i)
584 for (
int j = 1; j < n - i - 1; ++j)
586 nodeList[cnt - (n - i) + j] = nPts + nSmallTri + tmpNodes[cnt2++];
591 nPts = 6 + 9 * edge + 2 * nSmallTri + 3 * nSmallQuad;
592 for (
int k = 1; k < n - 1; ++k)
596 for (
int i = 1; i < n - 2; ++i)
598 for (
int j = 1; j < n - i - 1; ++j)
600 nodeList[cnt + k * (n - i) + j] = nPts + tmpNodes[cnt2++];
612std::vector<long long> hexTensorNodeOrdering(
613 const std::vector<long long> &nodes)
615 int nN =
static_cast<int>(nodes.size());
616 int n =
static_cast<int>(std::cbrt(nN));
618 std::vector<long long> nodeList(nN);
621 nodeList[0] = nodes[0];
628 nodeList[n - 1] = nodes[1];
629 nodeList[n * n - 1] = nodes[2];
630 nodeList[n * (n - 1)] = nodes[3];
631 nodeList[n * n * (n - 1)] = nodes[4];
632 nodeList[n - 1 + n * n * (n - 1)] = nodes[5];
633 nodeList[n * n - 1 + n * n * (n - 1)] = nodes[6];
634 nodeList[n * (n - 1) + n * n * (n - 1)] = nodes[7];
641 int hexEdges[12][2] = {{0, 1},
648 {n * (n - 1), n * n},
649 {n * n * (n - 1), 1},
650 {n * n * (n - 1) + n - 1, n},
652 {n * n * (n - 1) + n * (n - 1), -n}};
653 int hexFaces[6][3] = {{0, 1, n}, {0, 1, n * n},
654 {n - 1, n, n * n}, {n * (n - 1), 1, n * n},
655 {0, n, n * n}, {n * n * (n - 1), 1, n}};
657 int gmshToNekEdge[12] = {0, 1, -2, -3, 8, 9, -10, -11, 4, 5, 6, 7};
661 for (
int i : gmshToNekEdge)
667 for (
int j = 1; j < n - 1; ++j)
669 nodeList[hexEdges[e][0] + j * hexEdges[e][1]] = nodes[offset++];
674 for (
int j = 1; j < n - 1; ++j)
676 nodeList[hexEdges[e][0] + (n - j - 1) * hexEdges[e][1]] =
683 int gmsh2NekFace[6] = {4, 2, 1, 3, 0, 5};
694 for (
int i = 0; i < 6; ++i)
696 int n2 = (n - 2) * (n - 2);
697 int face = gmsh2NekFace[i];
698 offset = 8 + 12 * (n - 2) + i * n2;
701 std::vector<long long> faceNodes(n2);
702 for (
int j = 0; j < n2; ++j)
704 faceNodes[j] = nodes[offset + j];
709 std::vector<long long> tmp(n2);
721 for (
int j = 0; j < n - 2; ++j)
723 for (
int k = 0; k < n - 2; ++k)
725 tmp[j * (n - 2) + k] = faceNodes[k * (n - 2) + j];
731 for (
int j = 0; j < n - 2; ++j)
733 for (
int k = 0; k < n - 2; ++k)
735 tmp[j * (n - 2) + k] = faceNodes[j * (n - 2) + (n - k - 3)];
741 for (
int k = 1; k < n - 1; ++k)
743 for (
int j = 1; j < n - 1; ++j)
745 nodeList[hexFaces[face][0] + j * hexFaces[face][1] +
746 k * hexFaces[face][2]] =
747 faceNodes[(k - 1) * (n - 2) + j - 1];
753 std::vector<long long> intNodes, tmpInt;
754 for (
int i = 8 + 12 * (n - 2) + 6 * (n - 2) * (n - 2); i < n * n * n; ++i)
756 intNodes.push_back(nodes[i]);
759 if (!intNodes.empty())
761 tmpInt = hexTensorNodeOrdering(intNodes);
762 for (
int k = 1, cnt = 0; k < n - 1; ++k)
764 for (
int j = 1; j < n - 1; ++j)
766 for (
int i = 1; i < n - 1; ++i)
768 nodeList[i + j * n + k * n * n] = tmpInt[cnt++];
777std::vector<long long> lowOrderMapping(
int nDim, Array<OneD, int> nquad)
779 std::vector<long long>
p;
783 for (
int j = 0; j < nquad[0] - 1; ++j)
785 for (
int k = 0; k < nquad[1] - 1; ++k)
787 for (
int l = 0; l < nquad[2] - 1; ++l)
791 {l * nquad[0] * nquad[1] + k * nquad[0] + j,
792 l * nquad[0] * nquad[1] + k * nquad[0] + j + 1,
793 l * nquad[0] * nquad[1] + (k + 1) * nquad[0] + j +
795 l * nquad[0] * nquad[1] + (k + 1) * nquad[0] + j,
796 (l + 1) * nquad[0] * nquad[1] + k * nquad[0] + j,
797 (l + 1) * nquad[0] * nquad[1] + k * nquad[0] + j +
799 (l + 1) * nquad[0] * nquad[1] +
800 (k + 1) * nquad[0] + j + 1,
801 (l + 1) * nquad[0] * nquad[1] +
802 (k + 1) * nquad[0] + j});
808 for (
int j = 0; j < nquad[0] - 1; ++j)
810 for (
int k = 0; k < nquad[1] - 1; ++k)
812 p.insert(
p.end(), {k * nquad[0] + j, k * nquad[0] + j + 1,
813 (k + 1) * nquad[0] + j + 1,
814 (k + 1) * nquad[0] + j});
819 for (
int j = 0; j < nquad[0] - 1; ++j)
821 p.insert(
p.end(), {j, j + 1});
831int GetHighOrderVtkCellType(
int sType)
833#if VTK_MAJOR_VERSION >= 8
835 static const std::map<int, int> vtkCellType = {
844 return vtkCellType.at(sType);
846 boost::ignore_unused(sType);
849 "High-order VTK output requires minimum VTK library version of 8.0")
859 vtkSmartPointer<vtkUnstructuredGrid> vtkMesh =
860 vtkSmartPointer<vtkUnstructuredGrid>::New();
863 std::unordered_map<size_t, std::vector<long long>> mappingCache;
866 int nDim =
m_f->m_exp[0]->GetShapeDimension();
867 int nHomoDir =
m_f->m_numHomogeneousDir;
869 auto type = (nDim + nHomoDir == 3) ? VTK_HEXAHEDRON
870 : (nDim + nHomoDir == 2) ? VTK_QUAD
872 int nQpts = (nDim + nHomoDir == 3) ? 8 : (nDim + nHomoDir == 2) ? 4 : 2;
879 "Only regular expansions and the 3DH1D homogeneous expansion "
880 "are supported in the new VTK writer. Please use the 'legacy' "
881 "option for all other expansion types.")
883 m_numPlanes =
m_f->m_exp[0]->GetHomogeneousBasis()->GetNumModes();
885 m_extraPlane = (
m_f->m_exp[0]->GetHomogeneousBasis()->GetBasisType() ==
887 m_f->m_exp[0]->GetHomogeneousBasis()->GetPointsType() ==
892 vtkNew<vtkPoints> vtkPoints;
893 vtkPoints->SetDataType(VTK_DOUBLE);
896 int nElmts =
static_cast<int>(
m_f->m_exp[0]->GetNumElmts());
897 for (
int i = 0; i < nElmts; ++i)
900 for (
int j = 0; j < nDim; ++j)
902 nquad[j] =
m_f->m_exp[0]->GetExp(i)->GetNumPoints(j);
920 for (
int j = 1; j < nDim + nHomoDir; ++j)
927 m_f->m_exp[0]->GetCoords(i, x, y,
z);
935 tmp = x + (nquad[2] - 1) * nquad[0] * nquad[1], 1);
937 tmp = y + (nquad[2] - 1) * nquad[0] * nquad[1], 1);
940 NekDouble zDouble =
z[nquad[0] * nquad[1] * (nquad[2] - 1) - 1] +
941 (
z[nquad[0] * nquad[1]] -
z[0]);
943 tmp =
z + (nquad[2] - 1) * nquad[0] * nquad[1], 1);
947 for (
int j = 0; j < nPts; ++j)
949 vtkPoints->InsertNextPoint(x[j], y[j],
z[j]);
953 auto oIt = mappingCache.find(key3(nquad[0], nquad[1], nquad[2]));
954 if (oIt == mappingCache.end())
956 auto p = lowOrderMapping(nDim + nHomoDir, nquad);
959 std::make_pair(key3(nquad[0], nquad[1], nquad[2]),
p))
963 auto p = oIt->second;
964 std::for_each(
p.begin(),
p.end(),
965 [offset](
long long &
d) { d += offset; });
966 for (
int j = 0; j <
p.size(); j += nQpts)
968 vtkMesh->InsertNextCell(type, nQpts, &
p[j]);
974 vtkMesh->SetPoints(vtkPoints.GetPointer());
980 po::variables_map &vm, std::string &filename,
981 vtkSmartPointer<vtkUnstructuredGrid> &vtkMesh)
985 int nElmts =
static_cast<int>(
m_f->m_exp[0]->GetNumElmts());
987 for (
int v = 0; v <
m_f->m_variables.size(); ++v)
989 vtkNew<vtkDoubleArray> fieldData;
990 for (
int i = 0; i < nElmts; ++i)
992 int elmtOffset =
m_f->m_exp[v]->GetPhys_Offset(i);
993 int nPtsPerElmtPerPlane =
m_f->m_exp[v]->GetExp(i)->GetTotPoints();
997 int planeOffset = j * numPtsPerPlane;
998 for (
int k = 0; k < nPtsPerElmtPerPlane; ++k)
1000 fieldData->InsertNextValue(
1001 m_f->m_exp[v]->GetPhys()[elmtOffset + planeOffset + k]);
1008 for (
int k = 0; k < nPtsPerElmtPerPlane; ++k)
1010 fieldData->InsertNextValue(
1011 m_f->m_exp[v]->GetPhys()[elmtOffset + k]);
1016 fieldData->SetName(&
m_f->m_variables[v][0]);
1017 vtkMesh->GetPointData()->AddArray(fieldData.GetPointer());
1024 std::string &filename)
1027 m_f->m_numHomogeneousDir == 0,
1028 "Multi block VTK is not implemented for homogeneous expansion types.")
1031 "Multi block VTK is not implemented in parallel.")
1033 int dim =
m_f->m_graph->GetMeshDimension();
1036 std::array<std::map<int, std::pair<int, int>>, 4> geomIdToExpId;
1037 int nElmts =
static_cast<int>(
m_f->m_exp[0]->GetNumElmts());
1038 for (
int i = 0; i < nElmts; ++i)
1040 auto geom =
m_f->m_exp[0]->GetExp(i)->GetGeom();
1041 geomIdToExpId[geom->GetShapeDim()][geom->GetGlobalID()] =
1042 std::make_pair(i, -1);
1044 for (
int j = 0; j < geom->GetNumFaces(); ++j)
1046 geomIdToExpId[2][geom->GetFid(j)] = std::make_pair(i, j);
1049 for (
int j = 0; j < geom->GetNumEdges(); ++j)
1051 geomIdToExpId[1][geom->GetEid(j)] = std::make_pair(i, j);
1056 std::unordered_map<size_t, std::vector<long long>> mappingCache;
1058 std::map<int, vtkNew<vtkUnstructuredGrid>> vtkMesh;
1059 std::map<int, SpatialDomains::CompositeSharedPtr> composites =
1060 m_f->m_graph->GetComposites();
1061 std::map<int, std::string> compositeNames;
1062 for (
auto &comp : composites)
1065 std::vector<vtkNew<vtkDoubleArray>> fieldData(
m_f->m_variables.size());
1068 vtkNew<vtkPoints> vtkPoints;
1069 vtkPoints->SetDataType(VTK_DOUBLE);
1071 int compId = comp.first;
1072 std::vector<std::shared_ptr<SpatialDomains::Geometry>> geomVec =
1073 comp.second->m_geomVec;
1075 unsigned int offset = 0;
1076 for (
auto &geom : geomVec)
1078 int geomId = geom->GetGlobalID();
1079 int sDim = geom->GetShapeDim();
1080 auto type = (sDim == 3) ? VTK_HEXAHEDRON
1081 : (sDim == 2) ? VTK_QUAD
1083 int nQpts = (sDim == 3) ? 8 : (sDim == 2) ? 4 : 2;
1086 m_f->m_exp[0]->GetExp(geomIdToExpId[sDim][geomId].first);
1088 unsigned int nPts = exp->GetTotPoints();
1090 exp->GetCoords(x, y,
z);
1092 int offsetPhys =
m_f->m_exp[0]->GetPhys_Offset(
1093 geomIdToExpId[sDim][geomId].first);
1096 for (
int j = 0; j < nPts; ++j)
1098 vtkPoints->InsertNextPoint(x[j], y[j],
z[j]);
1101 for (
int k = 0; k <
m_f->m_variables.size(); ++k)
1103 fieldData[k]->InsertNextValue(
1104 m_f->m_exp[k]->GetPhys()[j + offsetPhys]);
1111 exp->GetTracePhysMap(geomIdToExpId[sDim][geomId].second,
1113 for (
int j : pointsMap)
1115 vtkPoints->InsertNextPoint(x[j], y[j],
z[j]);
1118 for (
int k = 0; k <
m_f->m_variables.size(); ++k)
1120 fieldData[k]->InsertNextValue(
1121 m_f->m_exp[k]->GetPhys()[offsetPhys + j]);
1125 exp = exp->GetTraceExp(geomIdToExpId[sDim][geomId].second);
1126 nPts = pointsMap.size();
1130 for (
int j = 0; j < sDim; ++j)
1132 nquad[j] = exp->GetNumPoints(j);
1135 auto oIt = mappingCache.find(key3(nquad[0], nquad[1], nquad[2]));
1136 if (oIt == mappingCache.end())
1138 auto p = lowOrderMapping(sDim, nquad);
1140 .insert(std::make_pair(
1141 key3(nquad[0], nquad[1], nquad[2]),
p))
1145 auto p = oIt->second;
1146 std::for_each(
p.begin(),
p.end(),
1147 [offset](
long long &
d) { d += offset; });
1149 for (
int j = 0; j <
p.size(); j += nQpts)
1151 vtkMesh[compId]->InsertNextCell(type, nQpts, &
p[j]);
1157 vtkMesh[compId]->SetPoints(vtkPoints.GetPointer());
1160 for (
int k = 0; k <
m_f->m_variables.size(); ++k)
1162 fieldData[k]->SetName(&
m_f->m_variables[k][0]);
1163 vtkMesh[compId]->GetPointData()->AddArray(
1164 fieldData[k].GetPointer());
1169 compositeNames[compId] =
"Composite ID " + std::to_string(compId);
1170 auto clabels =
m_f->m_graph->GetCompositesLabels();
1171 auto oIt = clabels.find(compId);
1172 if (oIt != clabels.end())
1174 compositeNames[compId] = oIt->second;
1179 vtkNew<vtkMultiBlockDataSet> mainBlock;
1181 std::set<int> compSet;
1184 vtkNew<vtkMultiBlockDataSet> mainDomainBlock;
1185 auto domains =
m_f->m_graph->GetDomain();
1186 std::vector<vtkNew<vtkMultiBlockDataSet>> domainMultiBlocks(domains.size());
1187 for (
int i = 0; i < domains.size(); ++i)
1189 auto dom = domains[i];
1192 for (
auto &comp : composites)
1194 int compId = comp.first;
1195 if (dom.find(compId) != dom.end())
1197 unsigned int nBlock = domainMultiBlocks[i]->GetNumberOfBlocks();
1198 domainMultiBlocks[i]->SetBlock(nBlock,
1199 vtkMesh[compId].GetPointer());
1200 domainMultiBlocks[i]->GetMetaData(nBlock)->Set(
1201 vtkCompositeDataSet::NAME(),
1202 compositeNames[compId].c_str());
1203 compSet.insert(compId);
1207 unsigned int nBlock = mainDomainBlock->GetNumberOfBlocks();
1208 mainDomainBlock->SetBlock(nBlock, domainMultiBlocks[i].GetPointer());
1209 mainDomainBlock->GetMetaData(nBlock)->Set(
1210 vtkCompositeDataSet::NAME(),
1211 (
"Domain ID " + std::to_string(i)).c_str());
1214 if (mainDomainBlock->GetNumberOfBlocks() != 0)
1216 auto nBlock =
static_cast<unsigned int>(mainBlock->GetNumberOfBlocks());
1217 mainBlock->SetBlock(nBlock, mainDomainBlock.GetPointer());
1218 mainBlock->GetMetaData(nBlock)->Set(vtkCompositeDataSet::NAME(),
1224 m_f->m_exp[0]->GetGraph());
1228 vtkNew<vtkMultiBlockDataSet> mainBoundaryBlock;
1229 std::vector<vtkNew<vtkMultiBlockDataSet>> boundaryMultiBlocks(
1232 for (
auto &boundary : bregions)
1235 for (
auto &comp : composites)
1237 int compId = comp.first;
1238 if (boundary.second->find(compId) != boundary.second->end())
1240 unsigned int nBlock =
1241 boundaryMultiBlocks[cnt]->GetNumberOfBlocks();
1242 boundaryMultiBlocks[cnt]->SetBlock(
1243 nBlock, vtkMesh[compId].GetPointer());
1244 boundaryMultiBlocks[cnt]->GetMetaData(nBlock)->Set(
1245 vtkCompositeDataSet::NAME(),
1246 compositeNames[compId].c_str());
1247 compSet.insert(compId);
1251 unsigned int nBlock = mainBoundaryBlock->GetNumberOfBlocks();
1252 mainBoundaryBlock->SetBlock(nBlock,
1253 boundaryMultiBlocks[cnt++].GetPointer());
1256 std::string
name =
"Boundary ID " + std::to_string(boundary.first);
1258 auto oIt = blabels.find(boundary.first);
1259 if (oIt != blabels.end())
1264 mainBoundaryBlock->GetMetaData(nBlock)->Set(vtkCompositeDataSet::NAME(),
1268 if (mainBoundaryBlock->GetNumberOfBlocks() != 0)
1270 auto nBlock =
static_cast<unsigned int>(mainBlock->GetNumberOfBlocks());
1271 mainBlock->SetBlock(nBlock, mainBoundaryBlock.GetPointer());
1272 mainBlock->GetMetaData(nBlock)->Set(vtkCompositeDataSet::NAME(),
1277 vtkNew<vtkMultiBlockDataSet> compsMultiBlocks;
1279 for (
auto &comp : composites)
1281 int compId = comp.first;
1282 if (compSet.find(compId) == compSet.end())
1284 unsigned int nBlock = compsMultiBlocks->GetNumberOfBlocks();
1285 compsMultiBlocks->SetBlock(nBlock, vtkMesh[compId].GetPointer());
1286 compsMultiBlocks->GetMetaData(nBlock)->Set(
1287 vtkCompositeDataSet::NAME(), compositeNames[compId].c_str());
1291 if (compsMultiBlocks->GetNumberOfBlocks() != 0)
1293 auto nBlock =
static_cast<unsigned int>(mainBlock->GetNumberOfBlocks());
1294 mainBlock->SetBlock(nBlock, compsMultiBlocks.GetPointer());
1295 mainBlock->GetMetaData(nBlock)->Set(vtkCompositeDataSet::NAME(),
1296 "Other composites");
1299 WriteVTK(mainBlock.GetPointer(), filename, vm);
1303 po::variables_map &vm)
1306 m_f->m_numHomogeneousDir == 0,
1307 "High order VTK is not implemented for homogeneous expansion types.")
1311 std::vector<LibUtilities::ShapeType> sType;
1312 for (
auto &i : *
m_f->m_exp[0]->GetExp())
1314 sType.emplace_back(i->GetGeom()->GetShapeType());
1320 equispaced->Process(vm);
1323 vtkNew<vtkPoints> vtkPoints;
1325 vtkPoints->SetDataType(VTK_DOUBLE);
1330 int dim =
static_cast<int>(fPts->GetDim());
1331 int nPts =
static_cast<int>(fPts->GetNpoints());
1335 for (
int i = 0; i < nPts; ++i)
1337 vtkPoints->InsertNextPoint(pts[0][i], pts[1][i], pts[2][i]);
1341 for (
int i = 0; i < nPts; ++i)
1343 vtkPoints->InsertNextPoint(pts[0][i], pts[1][i], 0.0);
1347 for (
int i = 0; i < nPts; ++i)
1349 vtkPoints->InsertNextPoint(pts[0][i], 0.0, 0.0);
1357 vtkSmartPointer<vtkUnstructuredGrid> vtkMesh =
1358 vtkSmartPointer<vtkUnstructuredGrid>::New();
1359 vtkMesh->SetPoints(vtkPoints.GetPointer());
1362 std::unordered_map<size_t, std::vector<long long>> mappingCache;
1365 std::vector<int> ppe =
m_f->m_fieldPts->GetPointsPerElement();
1367 std::partial_sum(ppe.begin(), ppe.end(), &ppeOffset[1]);
1370 for (
int i = 0; i < ppe.size(); ++i)
1374 auto oIt = mappingCache.find(key2(sType[i], ppe[i]));
1375 if (oIt == mappingCache.end())
1377 std::vector<long long>
p(ppe[i]);
1378 std::iota(
p.begin(),
p.end(), 0);
1382 p = quadTensorNodeOrdering(
p);
1385 p = triTensorNodeOrdering(
p);
1388 p = tetTensorNodeOrdering(
p);
1391 p = hexTensorNodeOrdering(
p);
1394 p = prismTensorNodeOrdering(
p);
1398 "High-order VTU output not set up for the " +
1399 static_cast<std::string
>(
1406 std::vector<long long> inv(ppe[i]);
1407 for (
int j = 0; j < ppe[i]; ++j)
1413 mappingCache.insert(std::make_pair(key2(sType[i], ppe[i]), inv))
1418 std::vector<long long>
p = oIt->second;
1419 for (
long long &j :
p)
1424 vtkMesh->InsertNextCell(GetHighOrderVtkCellType(sType[i]), ppe[i],
1432 po::variables_map &vm, std::string &filename,
1433 vtkSmartPointer<vtkUnstructuredGrid> &vtkMesh)
1440 equispaced->Process(vm);
1444 int nPts =
static_cast<int>(fPts->GetNpoints());
1445 int dim =
static_cast<int>(fPts->GetDim());
1451 for (
int i = 0; i < fPts->GetNFields(); ++i)
1453 vtkNew<vtkDoubleArray> fieldData;
1454 fieldData->SetArray(&pts[dim + i][0], nPts, 1);
1455 fieldData->SetName(&fPts->GetFieldName(i)[0]);
1456 vtkMesh->GetPointData()->AddArray(fieldData.GetPointer());
1463 po::variables_map &vm)
1466 vtkSmartPointer<vtkXMLWriter> vtkMeshWriter =
1467 vtkNew<vtkXMLUnstructuredGridWriter>().GetPointer();
1470 if (
m_config[
"multiblock"].m_beenSet)
1472 vtkMeshWriter = vtkNew<vtkXMLMultiBlockDataWriter>().GetPointer();
1476 int dot =
static_cast<int>(filename.find_last_of(
'.'));
1477 std::string body = filename.substr(0, dot + 1);
1478 filename = body + vtkMeshWriter->GetDefaultFileExtension();
1481 if (!
m_f->m_fieldMetaDataMap[
"Time"].empty())
1483 vtkMesh->GetInformation()->Set(
1484 vtkDataObject::DATA_TIME_STEP(),
1485 std::stod(
m_f->m_fieldMetaDataMap[
"Time"]));
1487 else if (!
m_f->m_fieldMetaDataMap[
"FinalTime"].empty())
1489 vtkMesh->GetInformation()->Set(
1490 vtkDataObject::DATA_TIME_STEP(),
1491 std::stod(
m_f->m_fieldMetaDataMap[
"FinalTime"]));
1496 vtkMeshWriter->SetFileName(filename.c_str());
1498#if VTK_MAJOR_VERSION <= 5
1499 vtkMeshWriter->SetInput(vtkMesh);
1501 vtkMeshWriter->SetInputData(vtkMesh);
1504 if (
m_config[
"uncompress"].m_beenSet)
1506 vtkMeshWriter->SetDataModeToAscii();
1509 vtkMeshWriter->Update();
1511 std::cout <<
"Written file: " << filename << std::endl;
1517 if (
m_f->m_comm->GetSpaceComm()->TreatAsRankZero() &&
1518 !
m_f->m_comm->GetSpaceComm()->IsSerial())
1526 std::string filename =
m_config[
"outfile"].as<std::string>();
1527 int dot =
static_cast<int>(filename.find_last_of(
'.'));
1528 std::string body = filename.substr(0, dot);
1529 filename = body +
".pvtu";
1531 std::ofstream outfile(filename.c_str());
1533 int nprocs =
m_f->m_comm->GetSpaceComm()->GetSize();
1537 outfile <<
"<?xml version=\"1.0\"?>" << endl;
1538 outfile <<
"<VTKFile type=\"PUnstructuredGrid\" version=\"0.1\" "
1539 <<
"byte_order=\"LittleEndian\">" << endl;
1540 outfile <<
" <PUnstructuredGrid GhostLevel=\"0\">" << endl;
1543 if (!
m_f->m_fieldMetaDataMap[
"Time"].empty())
1545 outfile <<
" <FieldData> " << endl;
1546 outfile <<
" <DataArray type=\"Float64\" Name=\"TimeValue\" "
1547 "NumberOfTuples=\"1\" format=\"ascii\">"
1549 outfile <<
m_f->m_fieldMetaDataMap[
"Time"] << std::endl;
1550 outfile <<
" </DataArray>" << std::endl;
1551 outfile <<
" </FieldData> " << endl;
1555 outfile <<
" <PPoints> " << endl;
1556 outfile <<
" <PDataArray type=\"Float64\" NumberOfComponents=\"" << 3
1558 outfile <<
" </PPoints>" << endl;
1561 outfile <<
" <PCells>" << endl;
1562 outfile <<
" <PDataArray type=\"Int64\" Name=\"connectivity\" "
1563 "NumberOfComponents=\"1\"/>"
1565 outfile <<
" <PDataArray type=\"Int64\" Name=\"offsets\" "
1566 "NumberOfComponents=\"1\"/>"
1568 outfile <<
" <PDataArray type=\"UInt8\" Name=\"types\" "
1569 "NumberOfComponents=\"1\"/>"
1571 outfile <<
" </PCells>" << endl;
1574 outfile <<
" <PPointData>" << endl;
1575 for (
auto &var :
m_f->m_variables)
1577 outfile <<
" <PDataArray type=\"Float64\" Name=\"" << var <<
"\"/>"
1580 outfile <<
" </PPointData>" << endl;
1583 for (
int i = 0; i < nprocs; ++i)
1587 outfile <<
" <Piece Source=\"" << path <<
"/" << pad.str() <<
"\"/>"
1590 outfile <<
" </PUnstructuredGrid>" << endl;
1591 outfile <<
"</VTKFile>" << endl;
1593 cout <<
"Written file: " << filename << endl;
1598 boost::ignore_unused(vm);
1600 "OutputVtk can't write using only FieldData. You may need "
1601 "to add a mesh XML file to your input files.");
1614 "Multi block VTK is not implemented for legacy output.")
1617 "High order VTK is not implemented for legacy output.")
1631 if (
m_config[
"highorder"].m_beenSet)
1634 "Multi block VTK is not implemented for high-order output.")
1643 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)
virtual fs::path v_GetPath(std::string &filename, po::variables_map &vm) override
virtual void v_OutputFromExp(po::variables_map &vm) override
Write from m_exp to output file.
virtual 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.
bool m_extraPlane
Flag if extra plane in case of fourier expansion in homogeneous dir.
int m_numPlanes
Number of planes if homogeneous.
virtual void v_OutputFromPts(po::variables_map &vm) override final
Write from pts 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
virtual void v_OutputFromData(po::variables_map &vm) override final
Write from data to output file.
virtual void v_OutputFromExp(po::variables_map &vm) override final
Write from m_exp to output file.
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]
std::string PortablePath(const boost::filesystem::path &path)
create portable path on different platforms for boost::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
std::tuple< unsigned int, unsigned int, unsigned int, unsigned int > Mode
@ eDir1FwdDir1_Dir2FwdDir2
@ eDir1BwdDir1_Dir2FwdDir2
@ eDir1FwdDir2_Dir2FwdDir1
std::vector< double > z(NPUPPER)
std::vector< double > d(NPUPPER *NPUPPER)
The above copyright notice and this permission notice shall be included.
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.