#12414 GeoMech: import geomech data from VTK.

This commit is contained in:
Kristian Bendiksen
2025-05-30 08:38:51 +02:00
parent eb27d8a772
commit fe9cac4fba
9 changed files with 748 additions and 13 deletions
@@ -331,6 +331,10 @@ RiaDefines::ImportFileType RiaDefines::obtainFileTypeFromFileName( const QString
{
return ImportFileType::GEOMECH_INP_FILE;
}
else if ( fileName.endsWith( "PVD", Qt::CaseInsensitive ) )
{
return ImportFileType::GEOMECH_VTK_FILE;
}
else if ( fileName.endsWith( ".rsp", Qt::CaseInsensitive ) || fileName.endsWith( ".rip", Qt::CaseInsensitive ) )
{
return ImportFileType::RESINSIGHT_PROJECT_FILE;
+2 -1
View File
@@ -134,9 +134,10 @@ enum class ImportFileType : uint32_t
GEOMECH_INP_FILE = 1 << 7,
EM_H5GRID = 1 << 8,
ROFF_FILE = 1 << 9,
GEOMECH_VTK_FILE = 1 << 10,
ECLIPSE_RESULT_GRID = ECLIPSE_GRID_FILE | ECLIPSE_EGRID_FILE,
ANY_ECLIPSE_FILE = ECLIPSE_RESULT_GRID | ECLIPSE_INPUT_FILE | ECLIPSE_SUMMARY_FILE | ROFF_FILE | EM_H5GRID,
ANY_GEOMECH_FILE = GEOMECH_ODB_FILE | GEOMECH_INP_FILE,
ANY_GEOMECH_FILE = GEOMECH_ODB_FILE | GEOMECH_INP_FILE | GEOMECH_VTK_FILE,
ANY_IMPORT_FILE = ANY_ECLIPSE_FILE | ANY_GEOMECH_FILE | RESINSIGHT_PROJECT_FILE
};
@@ -38,7 +38,8 @@ void RicImportGeoMechCaseFeature::onActionTriggered( bool isChecked )
#if USE_ODB_API
filterStr += "Abaqus results (*.odb);;";
#endif
filterStr += "Abaqus input file (*.inp)";
filterStr += "Abaqus input file (*.inp);;";
filterStr += "VTK file (*.pvd)";
QString defaultDir = app->lastUsedDialogDirectory( "GEOMECH_MODEL" );
QStringList fileNames = RiuFileDialogTools::getOpenFileNames( nullptr, "Import Geo-Mechanical Model", defaultDir, filterStr );
@@ -47,6 +47,21 @@ std::vector<cvf::Vec3d> RifVtkImportUtil::readPoints( const pugi::xml_node& piec
return vertices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<cvf::Vec3f> RifVtkImportUtil::readDisplacements( const pugi::xml_node& piece )
{
auto pointData = piece.child( "PointData" );
if ( !pointData ) return {};
auto dataArray = pointData.child( "DataArray" );
if ( !dataArray || std::string( dataArray.attribute( "Name" ).value() ) != "disp" ) return {};
std::string_view text = dataArray.text().get();
return parseVec3fs( text );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -42,6 +42,7 @@ public:
static std::vector<PvdDataset> parsePvdDatasets( const std::filesystem::path& filepath );
static std::vector<cvf::Vec3d> readPoints( const pugi::xml_node& piece );
static std::vector<cvf::Vec3f> readDisplacements( const pugi::xml_node& piece );
static std::vector<unsigned> readConnectivity( const pugi::xml_node& piece );
static std::map<std::string, std::vector<float>> readProperties( const pugi::xml_node& piece );
@@ -26,6 +26,7 @@
#include "RigGeoMechCaseData.h"
#include "RifInpReader.h"
#include "RifVtkReader.h"
#ifdef USE_ODB_API
#include "RifOdbReader.h"
#endif
@@ -99,6 +100,10 @@ bool RigGeoMechCaseData::open( std::string* errorMessage )
{
m_readerInterface = new RifInpReader();
}
else if ( filename.ends_with( ".PVD" ) )
{
m_readerInterface = new RifVtkReader();
}
#ifdef USE_ODB_API
else if ( filename.ends_with( ".ODB" ) )
{
@@ -143,17 +148,20 @@ bool RigGeoMechCaseData::readFemParts( std::string* errorMessage, const std::vec
progress.incrementProgress();
progress.setProgressDescription( "Calculating element neighbors" );
m_elementPropertyReader = new RifElementPropertyReader( m_femParts->part( 0 )->elementIdxToId() );
// Initialize results containers
m_femPartResultsColl = new RigFemPartResultsCollection( m_readerInterface.p(), m_elementPropertyReader.p(), m_femParts.p() );
// Calculate derived Fem data
for ( int pIdx = 0; pIdx < m_femParts->partCount(); ++pIdx )
if ( m_femParts->partCount() > 0 )
{
m_femParts->part( pIdx )->assertNodeToElmIndicesIsCalculated();
m_femParts->part( pIdx )->assertElmNeighborsIsCalculated();
m_elementPropertyReader = new RifElementPropertyReader( m_femParts->part( 0 )->elementIdxToId() );
// Initialize results containers
m_femPartResultsColl = new RigFemPartResultsCollection( m_readerInterface.p(), m_elementPropertyReader.p(), m_femParts.p() );
// Calculate derived Fem data
for ( int pIdx = 0; pIdx < m_femParts->partCount(); ++pIdx )
{
m_femParts->part( pIdx )->assertNodeToElmIndicesIsCalculated();
m_femParts->part( pIdx )->assertElmNeighborsIsCalculated();
}
return true;
}
return true;
}
}
@@ -8,8 +8,14 @@ endif()
add_library(
${PROJECT_NAME}
RifInpReader.h RifInpReader.cpp RifGeoMechReaderInterface.h
RifGeoMechReaderInterface.cpp RifInpIncludeReader.h RifInpIncludeReader.cpp
RifInpReader.h
RifInpReader.cpp
RifGeoMechReaderInterface.h
RifGeoMechReaderInterface.cpp
RifInpIncludeReader.h
RifInpIncludeReader.cpp
RifVtkReader.h
RifVtkReader.cpp
)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
@@ -0,0 +1,583 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifVtkReader.h"
#include "RifVtkImportUtil.h"
#include "RigFemPart.h"
#include "RigFemPartCollection.h"
#include "RigFemResultPosEnum.h"
#include "RigFemTypes.h"
#include "RiaLogging.h"
#include "cafProgressInfo.h"
#include <QString>
#include <map>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifVtkReader::RifVtkReader()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifVtkReader::~RifVtkReader()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifVtkReader::close()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifVtkReader::populateDerivedResultNames() const
{
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifVtkReader::openFile( const std::string& fileName, std::string* errorMessage )
{
std::filesystem::path filePath( fileName );
auto dataset = RifVtkImportUtil::parsePvdDatasets( filePath );
if ( dataset.empty() )
{
RiaLogging::error( "No timesteps found" );
m_inputPath.clear();
return false;
}
else
{
RiaLogging::info( QString( "Found %1 timesteps" ).arg( dataset.size() ) );
m_inputPath = filePath;
return true;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifVtkReader::isOpen() const
{
return !m_inputPath.empty();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifVtkReader::readFemParts( RigFemPartCollection* femParts )
{
CVF_ASSERT( femParts );
// The key in the maps is the part ID
std::map<int, std::string> parts;
std::map<int, std::vector<std::pair<int, cvf::Vec3d>>> nodes;
std::map<int, std::vector<std::pair<int, std::vector<int>>>> elements;
std::map<int, std::vector<std::pair<std::string, std::vector<size_t>>>> elementSets;
std::map<int, std::vector<std::map<std::string, std::vector<float>>>> properties;
auto result = read( m_inputPath, parts, nodes, elements, elementSets, properties, m_displacements, m_stepNames );
if ( !result )
{
RiaLogging::error( QString::fromStdString( result.error() ) );
return false;
}
auto elementType = result.value();
if ( m_stepNames.empty() ) m_stepNames.push_back( "Geostatic" );
RiaLogging::debug( QString( "Read FEM parts: %1, steps: %2, element type: %3" )
.arg( parts.size() )
.arg( m_stepNames.size() )
.arg( QString::fromStdString( RigFemTypes::elementTypeText( elementType ) ) ) );
if ( !RigFemTypes::is8NodeElement( elementType ) )
{
RiaLogging::error( QString( "Unsupported element type." ) );
return false;
}
caf::ProgressInfo modelProgress( parts.size() * 2, "Reading Inp Parts" );
for ( const auto& [partId, partName] : parts )
{
modelProgress.setProgressDescription( QString::fromStdString( partName ) + ": Reading Nodes" );
RigFemPart* femPart = new RigFemPart;
femPart->setName( partName );
// Extract nodes
std::vector<std::pair<int, cvf::Vec3d>> partNodes = nodes[partId];
std::map<int, int> nodeIdToIdxMap;
int nodeCount = partNodes.size();
femPart->nodes().nodeIds.resize( nodeCount );
femPart->nodes().coordinates.resize( nodeCount );
for ( int nIdx = 0; nIdx < nodeCount; ++nIdx )
{
auto [nodeId, pos] = partNodes[nIdx];
femPart->nodes().nodeIds[nIdx] = nodeId;
femPart->nodes().coordinates[nIdx].set( pos[0], pos[1], pos[2] );
nodeIdToIdxMap[nodeId] = nIdx;
}
modelProgress.incrementProgress();
modelProgress.setProgressDescription( QString::fromStdString( partName ) + ": Reading Elements" );
// Extract elements
std::vector<std::pair<int, std::vector<int>>> partElements = elements[partId];
int elmCount = partElements.size();
femPart->preAllocateElementStorage( elmCount );
std::vector<int> indexBasedConnectivities;
std::map<int, int> elementIdToIdxMap;
for ( int elmIdx = 0; elmIdx < elmCount; ++elmIdx )
{
auto [elmId, nodesInElement] = partElements[elmIdx];
elementIdToIdxMap[elmId] = elmIdx;
int nodeCount = RigFemTypes::elementNodeCount( elementType );
indexBasedConnectivities.resize( nodeCount );
for ( int lnIdx = 0; lnIdx < nodeCount; ++lnIdx )
{
indexBasedConnectivities[lnIdx] = nodeIdToIdxMap[nodesInElement[lnIdx]];
}
femPart->appendElement( elementType, elmId, indexBasedConnectivities.data() );
}
// read element sets
auto& elementSetsForPart = elementSets[partId];
for ( auto& [setName, elementSet] : elementSetsForPart )
{
femPart->addElementSet( setName, elementSet );
}
femPart->setElementPartId( femParts->partCount() );
femParts->addFemPart( femPart );
modelProgress.incrementProgress();
}
size_t elementCount = femParts->part( 0 )->elementCount();
readScalarData( femParts, parts, properties, elementCount );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::expected<RigElementType, std::string>
RifVtkReader::read( const std::filesystem::path& filePath,
std::map<int, std::string>& parts,
std::map<int, std::vector<std::pair<int, cvf::Vec3d>>>& nodes,
std::map<int, std::vector<std::pair<int, std::vector<int>>>>& elements,
std::map<int, std::vector<std::pair<std::string, std::vector<size_t>>>>& elementSets,
std::map<int, std::vector<std::map<std::string, std::vector<float>>>>& properties,
std::map<int, std::vector<std::vector<cvf::Vec3f>>>& displacements,
std::vector<std::string>& stepNames )
{
RigElementType elementType = RigElementType::UNKNOWN_ELM_TYPE;
int partId = 0;
std::string partName;
int stepId = -1;
std::string stepName;
int timeSteps = 0;
auto dataset = RifVtkImportUtil::parsePvdDatasets( filePath );
// Only one part supported
parts[partId] = "Model";
//
elementSets[partId] = {};
bool isFirst = true;
for ( const RifVtkImportUtil::PvdDataset& d : dataset )
{
stepNames.push_back( "Dataset " + std::to_string( d.timestep ) );
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file( d.filepath.string().c_str() );
if ( !result ) return std::unexpected( "File did load: " + d.filepath.string() );
auto root = doc.child( "VTKFile" );
if ( !root ) return std::unexpected( "Missing VTKFile tag: " + d.filepath.string() );
auto grid = root.child( "UnstructuredGrid" );
if ( !grid ) return std::unexpected( "Missing UnstructedGrid tag: " + d.filepath.string() );
auto piece = grid.child( "Piece" );
if ( !piece ) return std::unexpected( "Missing Piece tag: " + d.filepath.string() );
// Read points
std::vector<cvf::Vec3d> vertices = RifVtkImportUtil::readPoints( piece );
if ( vertices.empty() ) return std::unexpected( "No points found: " + d.filepath.string() );
// Read connectivity
std::vector<unsigned> connectivity = RifVtkImportUtil::readConnectivity( piece );
if ( connectivity.empty() ) return std::unexpected( "No connectivity found: " + d.filepath.string() );
// Read connectivity
std::vector<cvf::Vec3f> partDisplacements = RifVtkImportUtil::readDisplacements( piece );
if ( partDisplacements.empty() ) return std::unexpected( "No displacements found: " + d.filepath.string() );
RiaLogging::info( QString( "Found %1 vertices, %2 connectivities, and %3 displacements." )
.arg( vertices.size() )
.arg( connectivity.size() )
.arg( partDisplacements.size() ) );
// Use the geometry from the first time step only.
// The geometry is assumed to not change between time steps.
if ( isFirst )
{
std::vector<std::pair<int, cvf::Vec3d>> partNodes;
for ( size_t i = 0; i < vertices.size(); i++ )
{
partNodes.push_back( { i, vertices[i] } );
}
nodes[partId] = partNodes;
std::vector<std::pair<int, std::vector<int>>> partElements;
int numNodesPerElement = 8;
int numCells = connectivity.size() / numNodesPerElement;
for ( int i = 0; i < numCells; i++ )
{
std::vector<int> els( numNodesPerElement );
for ( int x = 0; x < numNodesPerElement; x++ )
{
els[x] = connectivity[i * numNodesPerElement + x];
}
partElements.emplace_back( i, els );
}
elements[partId] = partElements;
elementType = RigElementType::HEX8P;
}
const std::map<std::string, std::vector<float>> partProperties = RifVtkImportUtil::readProperties( piece );
properties[partId].push_back( partProperties );
displacements[partId].push_back( partDisplacements );
isFirst = false;
}
return elementType;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::string> RifVtkReader::allStepNames() const
{
return m_stepNames;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::string> RifVtkReader::filteredStepNames() const
{
// no filter supported
return RifVtkReader::allStepNames();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RifVtkReader::frameTimes( int stepIndex ) const
{
// only one frame from INP file
std::vector<double> frameValues( { 1.0 } );
return frameValues;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RifVtkReader::frameCount( int stepIndex ) const
{
return frameTimes( stepIndex ).size();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::string> RifVtkReader::elementSetNames( int partIndex, std::string partName )
{
if ( partIndex >= (int)m_partElementSetNames.size() ) return {};
return m_partElementSetNames.at( partIndex );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<size_t> RifVtkReader::elementSet( int partIndex, std::string partName, int setIndex )
{
// TODO: not implemented yet
std::vector<size_t> elementIndexes;
return elementIndexes;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::map<std::string, std::vector<std::string>> RifVtkReader::scalarNodeFieldAndComponentNames()
{
std::map<std::string, std::vector<std::string>> retVal;
for ( auto& entry : m_propertyPartDataNodes )
{
retVal[entry.first] = {};
}
return retVal;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::map<std::string, std::vector<std::string>> RifVtkReader::scalarElementFieldAndComponentNames()
{
std::map<std::string, std::vector<std::string>> retVal;
for ( auto& entry : m_propertyPartDataElements )
{
retVal[entry.first] = {};
}
return retVal;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::map<std::string, std::vector<std::string>> RifVtkReader::scalarElementNodeFieldAndComponentNames()
{
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::map<std::string, std::vector<std::string>> RifVtkReader::scalarIntegrationPointFieldAndComponentNames()
{
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifVtkReader::readDisplacements( int partIndex, int stepIndex, int frameIndex, std::vector<cvf::Vec3f>* displacements )
{
CVF_ASSERT( displacements );
if ( auto it = m_displacements.find( partIndex ); it != m_displacements.end() )
{
*displacements = it->second[stepIndex];
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifVtkReader::readField( RigFemResultPosEnum resultType,
const std::string& fieldName,
int partIndex,
int stepIndex,
std::vector<std::vector<float>*>* resultValues )
{
CVF_ASSERT( resultValues );
auto dataMap = propertyDataMap( resultType );
if ( dataMap == nullptr ) return;
if ( dataMap->count( fieldName ) == 0 ) return;
// is there only a static result? Use it for all steps.
if ( ( *dataMap )[fieldName].count( stepIndex ) == 0 )
{
if ( ( *dataMap )[fieldName].count( -1 ) == 0 ) return;
stepIndex = -1;
}
if ( ( *dataMap )[fieldName][stepIndex].count( partIndex ) == 0 ) return;
auto dataSize = ( *dataMap )[fieldName][stepIndex][partIndex].size();
( *resultValues )[0]->resize( dataSize );
std::vector<float>* singleComponentValues = ( *resultValues )[0];
for ( size_t i = 0; i < dataSize; i++ )
{
( *singleComponentValues )[i] = (float)( *dataMap )[fieldName][stepIndex][partIndex][i];
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifVtkReader::readNodeField( const std::string& fieldName,
int partIndex,
int stepIndex,
int frameIndex,
std::vector<std::vector<float>*>* resultValues )
{
readField( RigFemResultPosEnum::RIG_NODAL, fieldName, partIndex, stepIndex, resultValues );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifVtkReader::readElementField( const std::string& fieldName,
int partIndex,
int stepIndex,
int frameIndex,
std::vector<std::vector<float>*>* resultValues )
{
readField( RigFemResultPosEnum::RIG_ELEMENT, fieldName, partIndex, stepIndex, resultValues );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifVtkReader::readElementNodeField( const std::string& fieldName,
int partIndex,
int stepIndex,
int frameIndex,
std::vector<std::vector<float>*>* resultValues )
{
readField( RigFemResultPosEnum::RIG_ELEMENT_NODAL, fieldName, partIndex, stepIndex, resultValues );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifVtkReader::readIntegrationPointField( const std::string& fieldName,
int partIndex,
int stepIndex,
int frameIndex,
std::vector<std::vector<float>*>* resultValues )
{
readField( RigFemResultPosEnum::RIG_INTEGRATION_POINT, fieldName, partIndex, stepIndex, resultValues );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifVtkReader::readScalarData( RigFemPartCollection* femParts,
std::map<int, std::string>& parts,
const std::map<int, std::vector<std::map<std::string, std::vector<float>>>>& properties,
size_t numElements )
{
for ( auto [partId, partName] : parts )
{
if ( auto partProperties = properties.find( partId ); partProperties != properties.end() )
{
int stepId = 0;
for ( const auto& propertiesPerTimeStep : partProperties->second )
{
for ( const auto& [propertyName, values] : propertiesPerTimeStep )
{
RigFemResultPosEnum resultType = values.size() == numElements ? RigFemResultPosEnum::RIG_ELEMENT
: RigFemResultPosEnum::RIG_NODAL;
// TODO: handle other result types...
if ( resultType == RigFemResultPosEnum::RIG_ELEMENT )
{
auto map = propertyDataMap( resultType );
if ( map == nullptr ) continue;
if ( map->count( propertyName ) == 0 )
{
( *map )[propertyName] = {};
}
if ( ( *map )[propertyName].count( stepId ) == 0 )
{
( *map )[propertyName][stepId] = {};
}
for ( int partId = 0; partId < femParts->partCount(); partId++ )
{
( *map )[propertyName][stepId][partId] = {};
size_t dataSize = 0;
if ( resultType == RigFemResultPosEnum::RIG_NODAL )
{
dataSize = femParts->part( partId )->nodeCount();
}
if ( resultType == RigFemResultPosEnum::RIG_ELEMENT )
{
dataSize = femParts->part( partId )->elementCount();
}
std::vector<double> valuesAsDouble( dataSize, 0.0 );
// TODO: fix annoying conversion from float to double
for ( size_t i = 0; i < dataSize; i++ )
{
valuesAsDouble[i] = values[i];
}
( *map )[propertyName][stepId][partId] = valuesAsDouble;
}
}
}
stepId++;
}
}
}
}
//--------------------------------------------------------------------------------------------------
/// Map keys: result name / time step / part id
//--------------------------------------------------------------------------------------------------
std::map<std::string, std::map<int, std::map<int, std::vector<double>>>>* RifVtkReader::propertyDataMap( RigFemResultPosEnum resultType )
{
if ( resultType == RigFemResultPosEnum::RIG_ELEMENT ) return &m_propertyPartDataElements;
if ( resultType == RigFemResultPosEnum::RIG_NODAL ) return &m_propertyPartDataNodes;
return nullptr;
}
@@ -0,0 +1,116 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifGeoMechReaderInterface.h"
#include "RigFemResultPosEnum.h"
#include "RigFemTypes.h"
#include <expected>
#include <filesystem>
#include <map>
#include <string>
#include <utility>
class RigFemPartCollection;
//==================================================================================================
//
//==================================================================================================
class RifVtkReader : public RifGeoMechReaderInterface
{
public:
RifVtkReader();
~RifVtkReader() override;
bool openFile( const std::string& fileName, std::string* errorMessage ) override;
bool isOpen() const override;
bool readFemParts( RigFemPartCollection* geoMechCase ) override;
std::vector<std::string> allStepNames() const override;
std::vector<std::string> filteredStepNames() const override;
std::vector<double> frameTimes( int stepIndex ) const override;
int frameCount( int stepIndex ) const override;
std::vector<std::string> elementSetNames( int partIndex, std::string partName ) override;
std::vector<size_t> elementSet( int partIndex, std::string partName, int setIndex ) override;
std::map<std::string, std::vector<std::string>> scalarNodeFieldAndComponentNames() override;
std::map<std::string, std::vector<std::string>> scalarElementFieldAndComponentNames() override;
std::map<std::string, std::vector<std::string>> scalarElementNodeFieldAndComponentNames() override;
std::map<std::string, std::vector<std::string>> scalarIntegrationPointFieldAndComponentNames() override;
void readDisplacements( int partIndex, int stepIndex, int frameIndex, std::vector<cvf::Vec3f>* displacements ) override;
void readNodeField( const std::string& fieldName,
int partIndex,
int stepIndex,
int frameIndex,
std::vector<std::vector<float>*>* resultValues ) override;
void readElementField( const std::string& fieldName,
int partIndex,
int stepIndex,
int frameIndex,
std::vector<std::vector<float>*>* resultValues ) override;
void readElementNodeField( const std::string& fieldName,
int partIndex,
int stepIndex,
int frameIndex,
std::vector<std::vector<float>*>* resultValues ) override;
void readIntegrationPointField( const std::string& fieldName,
int partIndex,
int stepIndex,
int frameIndex,
std::vector<std::vector<float>*>* resultValues ) override;
bool populateDerivedResultNames() const override;
private:
void close();
void readField( RigFemResultPosEnum resultType,
const std::string& fieldName,
int partIndex,
int stepIndex,
std::vector<std::vector<float>*>* resultValues );
void readScalarData( RigFemPartCollection* femParts,
std::map<int, std::string>& parts,
const std::map<int, std::vector<std::map<std::string, std::vector<float>>>>& properties,
size_t numElements );
std::map<std::string, std::map<int, std::map<int, std::vector<double>>>>* propertyDataMap( RigFemResultPosEnum resultType );
static std::expected<RigElementType, std::string> read( const std::filesystem::path& filePath,
std::map<int, std::string>& parts,
std::map<int, std::vector<std::pair<int, cvf::Vec3d>>>& nodes,
std::map<int, std::vector<std::pair<int, std::vector<int>>>>& elements,
std::map<int, std::vector<std::pair<std::string, std::vector<size_t>>>>& elementSets,
std::map<int, std::vector<std::map<std::string, std::vector<float>>>>& properties,
std::map<int, std::vector<std::vector<cvf::Vec3f>>>& displacements,
std::vector<std::string>& stepNames );
private:
std::map<int, std::vector<std::string>> m_partElementSetNames;
std::vector<std::string> m_stepNames;
std::filesystem::path m_inputPath;
std::map<std::string, std::map<int, std::map<int, std::vector<double>>>> m_propertyPartDataNodes;
std::map<std::string, std::map<int, std::map<int, std::vector<double>>>> m_propertyPartDataElements;
std::map<int, std::vector<std::vector<cvf::Vec3f>>> m_displacements;
};