Fem: Add metadata info to blocks
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user