mirror of
https://github.com/OPM/ResInsight.git
synced 2026-08-27 05:37:21 -05:00
#12414 GeoMech: import geomech data from VTK.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
Reference in New Issue
Block a user