Fem: Add metadata info to blocks

This commit is contained in:
marioalexis
2025-02-17 08:26:03 -03:00
parent da614ecc2c
commit fc22f5d2be

View File

@@ -39,6 +39,7 @@
#include <vtkDataSetReader.h>
#include <vtkDataSetWriter.h>
#include <vtkDoubleArray.h>
#include <vtkFloatArray.h>
#include <vtkHexahedron.h>
#include <vtkIdList.h>
#include <vtkLine.h>
@@ -53,6 +54,7 @@
#include <vtkQuadraticTetra.h>
#include <vtkQuadraticTriangle.h>
#include <vtkQuadraticWedge.h>
#include <vtkStringArray.h>
#include <vtkTetra.h>
#include <vtkTriangle.h>
#include <vtkUnsignedCharArray.h>
@@ -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<AnalysisType, std::string> 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<int, unsigned int> 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<ElementType, unsigned int> 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<vtkCellArray>& cellArray, const std::vector<int>& t
void fillCell(vtkSmartPointer<vtkCellArray>& cellArray,
std::vector<int>& topoElem,
std::vector<int>& vtkType,
int elemType)
ElementType elemType)
{
switch (elemType) {
case 1:
case ElementType::Hexa:
addCell<vtkHexahedron>(cellArray, topoElem);
vtkType.emplace_back(VTK_HEXAHEDRON);
break;
case 2:
case ElementType::Penta:
addCell<vtkWedge>(cellArray, topoElem);
vtkType.emplace_back(VTK_WEDGE);
break;
case 3:
case ElementType::Tetra:
addCell<vtkTetra>(cellArray, topoElem);
vtkType.emplace_back(VTK_TETRA);
break;
case 4:
case ElementType::QuadHexa:
addCell<vtkQuadraticHexahedron>(cellArray, topoElem);
vtkType.emplace_back(VTK_QUADRATIC_HEXAHEDRON);
break;
case 5:
case ElementType::QuadPenta:
addCell<vtkQuadraticWedge>(cellArray, topoElem);
vtkType.emplace_back(VTK_QUADRATIC_WEDGE);
break;
case 6:
case ElementType::QuadTetra:
addCell<vtkQuadraticTetra>(cellArray, topoElem);
vtkType.emplace_back(VTK_QUADRATIC_TETRA);
break;
case 7:
case ElementType::Triangle:
addCell<vtkTriangle>(cellArray, topoElem);
vtkType.emplace_back(VTK_TRIANGLE);
break;
case 8:
case ElementType::QuadTriangle:
addCell<vtkQuadraticTriangle>(cellArray, topoElem);
vtkType.emplace_back(VTK_QUADRATIC_TRIANGLE);
break;
case 9:
case ElementType::Quadrangle:
addCell<vtkQuad>(cellArray, topoElem);
vtkType.emplace_back(VTK_QUAD);
break;
case 10:
case ElementType::QuadQuadrangle:
addCell<vtkQuadraticQuad>(cellArray, topoElem);
vtkType.emplace_back(VTK_QUADRATIC_QUAD);
break;
case 11:
case ElementType::Edge:
addCell<vtkLine>(cellArray, topoElem);
vtkType.emplace_back(VTK_LINE);
break;
case 12:
case ElementType::QuadEdge:
addCell<vtkQuadraticEdge>(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<int>(this->analysisType) < static_cast<int>(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<vtkPoi
sub = sub.substr(12 + 37);
valueFromLine(sub.begin(), 1, indicator);
int digits = getDigits(indicator);
int digits = getDigits(static_cast<Indicator>(indicator));
points->SetNumberOfPoints(numNodes);
@@ -1286,7 +1348,7 @@ std::vector<int> readElements(std::ifstream& ifstr,
sub = sub.substr(12 + 37);
valueFromLine(sub.begin(), 1, indicator);
int digits = getDigits(indicator);
int digits = getDigits(static_cast<Indicator>(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<int> 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<ElementType>(info[0])]) {
fillCell(cellArray, topoElem, vtkType, static_cast<ElementType>(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<AnalysisType>(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<Indicator>(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<vtkStringArray> createTimeInfo(const std::string& type)
{
auto timeInfo = vtkSmartPointer<vtkStringArray>::New();
timeInfo->SetName("TimeInfo");
timeInfo->InsertNextValue(type);
// set unit to empty string
timeInfo->InsertNextValue("");
return timeInfo;
}
vtkSmartPointer<vtkFloatArray> createTimeValue(const double& value)
{
auto stepValue = vtkSmartPointer<vtkFloatArray>::New();
stepValue->SetName("TimeValue");
stepValue->InsertNextValue(value);
return stepValue;
}
vtkSmartPointer<vtkMultiBlockDataSet> readFRD(std::ifstream& ifstr)
{
@@ -1526,7 +1611,9 @@ vtkSmartPointer<vtkMultiBlockDataSet> readFRD(std::ifstream& ifstr)
auto cells = vtkSmartPointer<vtkCellArray>::New();
auto multiBlock = vtkSmartPointer<vtkMultiBlockDataSet>::New();
vtkSmartPointer<vtkUnstructuredGrid> grid;
std::map<std::pair<int, int>, vtkSmartPointer<vtkUnstructuredGrid>> grids;
vtkSmartPointer<vtkMultiBlockDataSet> block;
std::map<FRDResultInfo, vtkSmartPointer<vtkUnstructuredGrid>> grids;
std::map<AnalysisType, vtkSmartPointer<vtkMultiBlockDataSet>> blocks;
std::string line;
std::map<int, int> mapNodes;
std::vector<int> cellTypes;
@@ -1554,12 +1641,34 @@ vtkSmartPointer<vtkMultiBlockDataSet> readFRD(std::ifstream& ifstr)
// read result info block
FRDResultInfo info;
readResultInfo(ifstr, line, info);
auto it = grids.find(std::pair<int, int>(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<vtkMultiBlockDataSet>::New();
block->GetFieldData()->AddArray(timeInfo);
blocks[info.analysisType] = block;
}
else {
block = it2->second;
}
// create unstructured grid
grid = vtkSmartPointer<vtkUnstructuredGrid>::New();
grid->SetPoints(points);
grid->SetCells(cellTypes.data(), cells);
grids[std::pair<int, int>(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<vtkMultiBlockDataSet> 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<vtkMultiBlockDataSet>::New();
grid = vtkSmartPointer<vtkUnstructuredGrid>::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<vtkXMLMultiBlockDataWriter>::New();
for (unsigned int i = 0; i < multiBlock->GetNumberOfBlocks(); ++i) {
vtkDataObject* block = multiBlock->GetBlock(i);
// get TimeInfo
vtkSmartPointer<vtkStringArray> 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<vtkXMLMultiBlockDataWriter>::New();
std::string blockFile =
dir + "/" + fi.fileNamePure() + type + "." + writer->GetDefaultFileExtension();
writer->SetFileName(blockFile.c_str());
writer->SetInputData(block);
writer->Update();
}
}
} // namespace Fem