From 5042b944630b3bb64a7e1ba4c84cc1bf11868f2c Mon Sep 17 00:00:00 2001 From: marioalexis Date: Mon, 17 Feb 2025 08:26:03 -0300 Subject: [PATCH] Fem: Add metadata info to blocks --- src/Mod/Fem/App/FemVTKTools.cpp | 233 ++++++++++++++++++++++++-------- 1 file changed, 179 insertions(+), 54 deletions(-) diff --git a/src/Mod/Fem/App/FemVTKTools.cpp b/src/Mod/Fem/App/FemVTKTools.cpp index 522b461e0c..382ff07455 100644 --- a/src/Mod/Fem/App/FemVTKTools.cpp +++ b/src/Mod/Fem/App/FemVTKTools.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -1036,20 +1038,60 @@ void FemVTKTools::exportFreeCADResult(const App::DocumentObject* result, namespace FRDReader { +enum class ElementType +{ + Edge = 11, + QuadEdge = 12, + Triangle = 7, + QuadTriangle = 8, + Quadrangle = 9, + QuadQuadrangle = 10, + Tetra = 3, + QuadTetra = 6, + Hexa = 1, + QuadHexa = 4, + Penta = 2, + QuadPenta = 5 +}; + +enum class AnalysisType +{ + Static = 0, + TimeStep = 1, + Frequency = 2, + LoadStep = 3, + UserNamed = 4 +}; + +std::map mapAnalysisTypeToStr = {{AnalysisType::Static, "Static"}, + {AnalysisType::TimeStep, "TimeStep"}, + {AnalysisType::Frequency, "Frequency"}, + {AnalysisType::LoadStep, "LoadStep"}, + {AnalysisType::UserNamed, "User"}}; + +// value format indicator +enum class Indicator +{ + Short = 0, + Long = 1, + // BinaryFloat = 2, not used + // BinaryDouble = 3 not used +}; + // number of nodes per CalculiX element type: {type, nodes} -std::map mapCcxTypeNodes = { - {11, 2}, - {12, 3}, - {7, 3}, - {8, 6}, - {9, 4}, - {10, 8}, - {3, 4}, - {6, 10}, - {1, 8}, - {4, 20}, - {2, 6}, - {5, 15}, +std::map mapCcxTypeNodes = { + {ElementType::Edge, 2}, + {ElementType::QuadEdge, 3}, + {ElementType::Triangle, 3}, + {ElementType::QuadTriangle, 6}, + {ElementType::Quadrangle, 4}, + {ElementType::QuadQuadrangle, 8}, + {ElementType::Tetra, 4}, + {ElementType::QuadTetra, 10}, + {ElementType::Hexa, 8}, + {ElementType::QuadHexa, 20}, + {ElementType::Penta, 6}, + {ElementType::QuadPenta, 15}, }; // map CalculiX nodes order to Vtk order @@ -1118,54 +1160,54 @@ void addCell(vtkSmartPointer& cellArray, const std::vector& t void fillCell(vtkSmartPointer& cellArray, std::vector& topoElem, std::vector& vtkType, - int elemType) + ElementType elemType) { switch (elemType) { - case 1: + case ElementType::Hexa: addCell(cellArray, topoElem); vtkType.emplace_back(VTK_HEXAHEDRON); break; - case 2: + case ElementType::Penta: addCell(cellArray, topoElem); vtkType.emplace_back(VTK_WEDGE); break; - case 3: + case ElementType::Tetra: addCell(cellArray, topoElem); vtkType.emplace_back(VTK_TETRA); break; - case 4: + case ElementType::QuadHexa: addCell(cellArray, topoElem); vtkType.emplace_back(VTK_QUADRATIC_HEXAHEDRON); break; - case 5: + case ElementType::QuadPenta: addCell(cellArray, topoElem); vtkType.emplace_back(VTK_QUADRATIC_WEDGE); break; - case 6: + case ElementType::QuadTetra: addCell(cellArray, topoElem); vtkType.emplace_back(VTK_QUADRATIC_TETRA); break; - case 7: + case ElementType::Triangle: addCell(cellArray, topoElem); vtkType.emplace_back(VTK_TRIANGLE); break; - case 8: + case ElementType::QuadTriangle: addCell(cellArray, topoElem); vtkType.emplace_back(VTK_QUADRATIC_TRIANGLE); break; - case 9: + case ElementType::Quadrangle: addCell(cellArray, topoElem); vtkType.emplace_back(VTK_QUAD); break; - case 10: + case ElementType::QuadQuadrangle: addCell(cellArray, topoElem); vtkType.emplace_back(VTK_QUADRATIC_QUAD); break; - case 11: + case ElementType::Edge: addCell(cellArray, topoElem); vtkType.emplace_back(VTK_LINE); break; - case 12: + case ElementType::QuadEdge: addCell(cellArray, topoElem); vtkType.emplace_back(VTK_QUADRATIC_EDGE); break; @@ -1176,22 +1218,42 @@ struct FRDResultInfo { double value; long numNodes; - int analysisType; + AnalysisType analysisType; int step; - int indicator; + Indicator indicator; + + bool operator==(const FRDResultInfo& other) const + { + return (this->step == other.step) && (this->analysisType == other.analysisType); + } + bool operator<(const FRDResultInfo& other) const + { + if (this->step < other.step) { + return true; + } + else if (this->step > other.step) { + return false; + } + else if (static_cast(this->analysisType) < static_cast(other.analysisType)) { + return true; + } + else { + return false; + } + } }; // get number of digits from format indicator -int getDigits(int indicator) +int getDigits(Indicator indicator) { int digits = 0; - if (indicator == 0) { - // short - digits = 5; - } - else if (indicator == 1) { - // long - digits = 10; + switch (indicator) { + case Indicator::Short: + digits = 5; + break; + case Indicator::Long: + digits = 10; + break; } return digits; @@ -1232,7 +1294,7 @@ readNodes(std::ifstream& ifstr, const std::string& lines, vtkSmartPointer(indicator)); points->SetNumberOfPoints(numNodes); @@ -1286,7 +1348,7 @@ std::vector readElements(std::ifstream& ifstr, sub = sub.substr(12 + 37); valueFromLine(sub.begin(), 1, indicator); - int digits = getDigits(indicator); + int digits = getDigits(static_cast(indicator)); while (elemID < numElem && std::getline(ifstr, line)) { std::string_view view {line}; if (view.rfind(keyCodeType, 0) == 0) { @@ -1309,8 +1371,8 @@ std::vector readElements(std::ifstream& ifstr, } // add cell to cellArray - if (topoElem.size() == mapCcxTypeNodes[info[0]]) { - fillCell(cellArray, topoElem, vtkType, info[0]); + if (topoElem.size() == mapCcxTypeNodes[static_cast(info[0])]) { + fillCell(cellArray, topoElem, vtkType, static_cast(info[0])); topoElem.clear(); mapElem[elem] = elemID++; } @@ -1342,13 +1404,17 @@ void readResultInfo(std::ifstream& ifstr, const std::string& lines, FRDResultInf valueFromLine(sub.begin(), 12, info.numNodes); sub = sub.substr(12 + 20); - valueFromLine(sub.begin(), 2, info.analysisType); + int anType; + valueFromLine(sub.begin(), 2, anType); + info.analysisType = static_cast(anType); sub = sub.substr(2); valueFromLine(sub.begin(), 5, info.step); sub = sub.substr(5 + 10); - valueFromLine(sub.begin(), 2, info.indicator); + int ind; + valueFromLine(sub.begin(), 2, ind); + info.indicator = static_cast(ind); } // read result from nodal result block and add result array to grid @@ -1519,6 +1585,25 @@ void readResults(std::ifstream& ifstr, grid->GetPointData()->AddArray(s); } } +vtkSmartPointer createTimeInfo(const std::string& type) +{ + auto timeInfo = vtkSmartPointer::New(); + timeInfo->SetName("TimeInfo"); + timeInfo->InsertNextValue(type); + // set unit to empty string + timeInfo->InsertNextValue(""); + + return timeInfo; +} + +vtkSmartPointer createTimeValue(const double& value) +{ + auto stepValue = vtkSmartPointer::New(); + stepValue->SetName("TimeValue"); + stepValue->InsertNextValue(value); + + return stepValue; +} vtkSmartPointer readFRD(std::ifstream& ifstr) { @@ -1526,7 +1611,9 @@ vtkSmartPointer readFRD(std::ifstream& ifstr) auto cells = vtkSmartPointer::New(); auto multiBlock = vtkSmartPointer::New(); vtkSmartPointer grid; - std::map, vtkSmartPointer> grids; + vtkSmartPointer block; + std::map> grids; + std::map> blocks; std::string line; std::map mapNodes; std::vector cellTypes; @@ -1554,12 +1641,34 @@ vtkSmartPointer readFRD(std::ifstream& ifstr) // read result info block FRDResultInfo info; readResultInfo(ifstr, line, info); - auto it = grids.find(std::pair(info.step, info.analysisType)); + auto it = grids.find(info); if (it == grids.end()) { + // create TimeInfo metadata + auto timeInfo = createTimeInfo(mapAnalysisTypeToStr[info.analysisType]); + // search analysis type block and create it if necessary + auto it2 = blocks.find(info.analysisType); + if (it2 == blocks.end()) { + block = vtkSmartPointer::New(); + block->GetFieldData()->AddArray(timeInfo); + blocks[info.analysisType] = block; + } + else { + block = it2->second; + } + // create unstructured grid grid = vtkSmartPointer::New(); grid->SetPoints(points); grid->SetCells(cellTypes.data(), cells); - grids[std::pair(info.step, info.analysisType)] = grid; + + // create TimeValue metadata + auto stepValue = createTimeValue(info.value); + + grid->GetFieldData()->AddArray(stepValue); + grid->GetFieldData()->AddArray(timeInfo); + + grids[info] = grid; + unsigned int nb = block->GetNumberOfBlocks(); + block->SetBlock(nb, grid); } else { grid = (*it).second; @@ -1570,18 +1679,25 @@ vtkSmartPointer readFRD(std::ifstream& ifstr) } int i = 0; - multiBlock->SetNumberOfBlocks(grids.size()); - for (const auto& g : grids) { - multiBlock->SetBlock(i, g.second); + for (const auto& b : blocks) { + multiBlock->SetBlock(i, b.second); ++i; } // save points and elements even without results if (grids.empty()) { + block = vtkSmartPointer::New(); grid = vtkSmartPointer::New(); grid->SetPoints(points); grid->SetCells(cellTypes.data(), cells); - multiBlock->SetBlock(0, grid); + auto timeInfo = createTimeInfo(""); + auto stepValue = createTimeValue(0); + grid->GetFieldData()->AddArray(stepValue); + grid->GetFieldData()->AddArray(timeInfo); + + block->SetBlock(0, grid); + block->GetFieldData()->AddArray(timeInfo); + multiBlock->SetBlock(0, block); } return multiBlock; @@ -1603,12 +1719,21 @@ void FemVTKTools::frdToVTK(const char* filename) std::string dir = fi.dirPath(); - auto writer = vtkSmartPointer::New(); + for (unsigned int i = 0; i < multiBlock->GetNumberOfBlocks(); ++i) { + vtkDataObject* block = multiBlock->GetBlock(i); + // get TimeInfo + vtkSmartPointer info = + vtkStringArray::SafeDownCast(block->GetFieldData()->GetAbstractArray(0)); + std::string type = info->GetValue(0).c_str(); - std::string blockFile = dir + "/" + fi.fileNamePure() + "." + writer->GetDefaultFileExtension(); - writer->SetFileName(blockFile.c_str()); - writer->SetInputData(multiBlock); - writer->Update(); + auto writer = vtkSmartPointer::New(); + + std::string blockFile = + dir + "/" + fi.fileNamePure() + type + "." + writer->GetDefaultFileExtension(); + writer->SetFileName(blockFile.c_str()); + writer->SetInputData(block); + writer->Update(); + } } } // namespace Fem