mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-01 03:37:15 -06:00
055c0d4c8c
Fixes #11198. Fixes #10565.
461 lines
20 KiB
C++
461 lines
20 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) Statoil ASA
|
|
// Copyright (C) Ceetron Solutions AS
|
|
//
|
|
// 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 "RiuFemResultTextBuilder.h"
|
|
|
|
#include "RigFemAddressDefines.h"
|
|
#include "RigFemClosestResultIndexCalculator.h"
|
|
#include "RigFemPart.h"
|
|
#include "RigFemPartCollection.h"
|
|
#include "RigFemPartGrid.h"
|
|
#include "RigFemPartResultsCollection.h"
|
|
#include "RigFormationNames.h"
|
|
#include "RigGeoMechCaseData.h"
|
|
|
|
#include "Rim2dIntersectionView.h"
|
|
#include "RimFormationNames.h"
|
|
#include "RimGeoMechCase.h"
|
|
#include "RimGeoMechResultDefinition.h"
|
|
#include "RimGeoMechView.h"
|
|
|
|
#include "RiuGeoMechXfTensorResultAccessor.h"
|
|
|
|
#include "RivExtrudedCurveIntersectionPartMgr.h"
|
|
|
|
#include "cafDisplayCoordTransform.h"
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RiuFemResultTextBuilder::RiuFemResultTextBuilder( RimGridView* displayCoordView,
|
|
RimGeoMechResultDefinition* geomResDef,
|
|
int gridIndex,
|
|
int cellIndex,
|
|
int timeStepIndex,
|
|
int frameIndex )
|
|
: m_isIntersectionTriangleSet( false )
|
|
{
|
|
m_displayCoordView = displayCoordView;
|
|
m_geomResDef = geomResDef;
|
|
m_gridIndex = gridIndex;
|
|
m_cellIndex = cellIndex;
|
|
m_timeStepIndex = timeStepIndex;
|
|
m_frameIndex = frameIndex;
|
|
|
|
m_intersectionPointInDisplay = cvf::Vec3d::UNDEFINED;
|
|
m_face = cvf::StructGridInterface::NO_FACE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuFemResultTextBuilder::setIntersectionPointInDisplay( cvf::Vec3d intersectionPointInDisplay )
|
|
{
|
|
m_intersectionPointInDisplay = intersectionPointInDisplay;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuFemResultTextBuilder::setIntersectionTriangle( const std::array<cvf::Vec3f, 3>& triangle )
|
|
{
|
|
m_intersectionTriangle = triangle;
|
|
m_isIntersectionTriangleSet = true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuFemResultTextBuilder::set2dIntersectionView( Rim2dIntersectionView* intersectionView )
|
|
{
|
|
m_2dIntersectionView = intersectionView;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuFemResultTextBuilder::setFace( int face )
|
|
{
|
|
m_face = face;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RiuFemResultTextBuilder::mainResultText()
|
|
{
|
|
QString text;
|
|
|
|
text = closestNodeResultText( m_geomResDef );
|
|
|
|
if ( !text.isEmpty() ) text += "\n";
|
|
|
|
QString topoText = geometrySelectionText( "\n" );
|
|
text += topoText;
|
|
appendDetails( text, formationDetails() );
|
|
text += "\n";
|
|
|
|
if ( m_geomResDef->resultPositionType() != RIG_ELEMENT )
|
|
{
|
|
appendDetails( text, gridResultDetails() );
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RiuFemResultTextBuilder::geometrySelectionText( QString itemSeparator )
|
|
{
|
|
QString text;
|
|
|
|
if ( m_geomResDef->geoMechCase() )
|
|
{
|
|
RigGeoMechCaseData* geomData = m_geomResDef->geoMechCase()->geoMechData();
|
|
if ( geomData )
|
|
{
|
|
RigFemPart* femPart = geomData->femParts()->part( m_gridIndex );
|
|
int elementId = femPart->elmId( m_cellIndex );
|
|
auto elementType = femPart->elementType( m_cellIndex );
|
|
|
|
text +=
|
|
QString( "Element : Id[%1], Type[%2]" ).arg( elementId ).arg( QString::fromStdString( RigFemTypes::elementTypeText( elementType ) ) );
|
|
|
|
size_t i = 0;
|
|
size_t j = 0;
|
|
size_t k = 0;
|
|
if ( geomData->femParts()->part( m_gridIndex )->getOrCreateStructGrid()->ijkFromCellIndex( m_cellIndex, &i, &j, &k ) )
|
|
{
|
|
// Adjust to 1-based Eclipse indexing
|
|
i++;
|
|
j++;
|
|
k++;
|
|
|
|
text += QString( ", ijk[%1, %2, %3]" ).arg( i ).arg( j ).arg( k ) + itemSeparator;
|
|
|
|
QString formattedText;
|
|
if ( m_2dIntersectionView )
|
|
{
|
|
formattedText = QString( "Horizontal length from well start: %1" ).arg( m_intersectionPointInDisplay.x(), 5, 'f', 2 );
|
|
text += formattedText + itemSeparator;
|
|
|
|
cvf::Mat4d t = m_2dIntersectionView->flatIntersectionPartMgr()->unflattenTransformMatrix( m_intersectionPointInDisplay );
|
|
if ( !t.isZero() )
|
|
{
|
|
cvf::Vec3d intPt = m_intersectionPointInDisplay.getTransformedPoint( t );
|
|
formattedText = QString( "Intersection point : [E: %1, N: %2, Depth: %3]" )
|
|
.arg( intPt.x(), 5, 'f', 2 )
|
|
.arg( intPt.y(), 5, 'f', 2 )
|
|
.arg( -intPt.z(), 5, 'f', 2 );
|
|
text += formattedText;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( m_displayCoordView )
|
|
{
|
|
cvf::ref<caf::DisplayCoordTransform> transForm = m_displayCoordView->displayCoordTransform();
|
|
cvf::Vec3d domainCoord = transForm->translateToDomainCoord( m_intersectionPointInDisplay );
|
|
|
|
formattedText = QString( "Intersection point : [E: %1, N: %2, Depth: %3]" )
|
|
.arg( domainCoord.x(), 5, 'f', 2 )
|
|
.arg( domainCoord.y(), 5, 'f', 2 )
|
|
.arg( -domainCoord.z(), 5, 'f', 2 );
|
|
text += formattedText;
|
|
}
|
|
}
|
|
}
|
|
std::array<cvf::Vec3d, 8> cornerCoords;
|
|
if ( femPart->fillElementCoordinates( m_cellIndex, cornerCoords ) )
|
|
{
|
|
text += "\n\nElement corners:\n";
|
|
|
|
for ( auto p : cornerCoords )
|
|
{
|
|
text +=
|
|
QString( " [E: %1, N: %2, Depth: %3]\n" ).arg( p.x(), 5, 'f', 2 ).arg( p.y(), 5, 'f', 2 ).arg( -p.z(), 5, 'f', 2 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RiuFemResultTextBuilder::gridResultDetails()
|
|
{
|
|
QString text;
|
|
|
|
if ( m_geomResDef->geoMechCase() && m_geomResDef->geoMechCase()->geoMechData() )
|
|
{
|
|
RigGeoMechCaseData* eclipseCaseData = m_geomResDef->geoMechCase()->geoMechData();
|
|
|
|
appendTextFromResultColors( eclipseCaseData, m_gridIndex, m_cellIndex, m_timeStepIndex, m_frameIndex, m_geomResDef, &text );
|
|
|
|
if ( !text.isEmpty() )
|
|
{
|
|
text.prepend( "-- Element result details --\n" );
|
|
}
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RiuFemResultTextBuilder::formationDetails()
|
|
{
|
|
QString text;
|
|
RimCase* rimCase = m_geomResDef->geoMechCase();
|
|
if ( rimCase )
|
|
{
|
|
if ( rimCase->activeFormationNames() && rimCase->activeFormationNames()->formationNamesData() )
|
|
{
|
|
RigFormationNames* formNames = rimCase->activeFormationNames()->formationNamesData();
|
|
|
|
size_t k = cvf::UNDEFINED_SIZE_T;
|
|
{
|
|
if ( m_geomResDef->geoMechCase() )
|
|
{
|
|
RigGeoMechCaseData* geomData = m_geomResDef->geoMechCase()->geoMechData();
|
|
if ( geomData )
|
|
{
|
|
size_t i = 0;
|
|
size_t j = 0;
|
|
geomData->femParts()->part( m_gridIndex )->getOrCreateStructGrid()->ijkFromCellIndex( m_cellIndex, &i, &j, &k );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( k != cvf::UNDEFINED_SIZE_T )
|
|
{
|
|
QString formName = formNames->formationNameFromKLayerIdx( k );
|
|
if ( !formName.isEmpty() )
|
|
{
|
|
// text += "-- Formation details --\n";
|
|
|
|
text += QString( "Formation Name: %1\n" ).arg( formName );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return text;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuFemResultTextBuilder::appendTextFromResultColors( RigGeoMechCaseData* geomData,
|
|
int gridIndex,
|
|
int cellIndex,
|
|
int timeStepIndex,
|
|
int frameIndex,
|
|
RimGeoMechResultDefinition* resultDefinition,
|
|
QString* resultInfoText )
|
|
{
|
|
if ( !resultDefinition )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( resultDefinition->hasResult() )
|
|
{
|
|
auto address = RigFemAddressDefines::getResultLookupAddress( resultDefinition->resultAddress() );
|
|
const std::vector<float>& scalarResults = geomData->femPartResults()->resultValues( address, gridIndex, timeStepIndex, frameIndex );
|
|
if ( !scalarResults.empty() )
|
|
{
|
|
caf::AppEnum<RigFemResultPosEnum> resPosAppEnum = address.resultPosType;
|
|
resultInfoText->append( resPosAppEnum.uiText() + ", " );
|
|
resultInfoText->append( resultDefinition->resultFieldUiName() + ", " );
|
|
resultInfoText->append( resultDefinition->resultComponentUiName() + ":\n" );
|
|
|
|
if ( address.resultPosType != RIG_ELEMENT_NODAL_FACE )
|
|
{
|
|
RigFemPart* femPart = geomData->femParts()->part( gridIndex );
|
|
RigElementType elmType = femPart->elementType( cellIndex );
|
|
const int* elementConn = femPart->connectivities( cellIndex );
|
|
int elmNodeCount = RigFemTypes::elementNodeCount( elmType );
|
|
const int* lElmNodeToIpMap = RigFemTypes::localElmNodeToIntegrationPointMapping( elmType );
|
|
|
|
for ( int lNodeIdx = 0; lNodeIdx < elmNodeCount; ++lNodeIdx )
|
|
{
|
|
float scalarValue = std::numeric_limits<float>::infinity();
|
|
int nodeIdx = elementConn[lNodeIdx];
|
|
if ( address.resultPosType == RIG_NODAL ||
|
|
( address.resultPosType == RIG_DIFFERENTIALS &&
|
|
resultDefinition->resultFieldName() == QString::fromStdString( RigFemAddressDefines::porBar() ) ) )
|
|
{
|
|
scalarValue = scalarResults[nodeIdx];
|
|
}
|
|
else if ( resultDefinition->resultPositionType() == RIG_ELEMENT )
|
|
{
|
|
scalarValue = scalarResults[cellIndex];
|
|
}
|
|
else
|
|
{
|
|
size_t resIdx = femPart->elementNodeResultIdx( cellIndex, lNodeIdx );
|
|
scalarValue = scalarResults[resIdx];
|
|
}
|
|
|
|
if ( resultDefinition->resultPositionType() == RIG_INTEGRATION_POINT )
|
|
{
|
|
resultInfoText->append( QString( "\tIP:%1 \t: %2 \tAss. Node: \t%3" )
|
|
.arg( lElmNodeToIpMap[lNodeIdx] + 1 )
|
|
.arg( scalarValue )
|
|
.arg( femPart->nodes().nodeIds[nodeIdx] ) );
|
|
}
|
|
else
|
|
{
|
|
resultInfoText->append( QString( "\tN:%1 \t: %2" ).arg( femPart->nodes().nodeIds[nodeIdx] ).arg( scalarValue ) );
|
|
}
|
|
|
|
cvf::Vec3f nodeCoord = femPart->nodes().coordinates[nodeIdx];
|
|
resultInfoText->append( QString( "\t( %3, %4, %5)\n" ).arg( nodeCoord[0] ).arg( nodeCoord[1] ).arg( nodeCoord[2] ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int elmNodeFaceStartResIdx = cellIndex * 24;
|
|
|
|
resultInfoText->append( QString( "Pos I Face:\n" ) );
|
|
for ( int ptIdx = 0; ptIdx < 4; ++ptIdx )
|
|
{
|
|
resultInfoText->append( QString( "\t%2\n" ).arg( scalarResults[elmNodeFaceStartResIdx + ptIdx] ) );
|
|
}
|
|
|
|
resultInfoText->append( QString( "Neg I Face:\n" ) );
|
|
for ( int ptIdx = 4; ptIdx < 8; ++ptIdx )
|
|
{
|
|
resultInfoText->append( QString( "\t%2\n" ).arg( scalarResults[elmNodeFaceStartResIdx + ptIdx] ) );
|
|
}
|
|
|
|
resultInfoText->append( QString( "Pos J Face:\n" ) );
|
|
for ( int ptIdx = 8; ptIdx < 12; ++ptIdx )
|
|
{
|
|
resultInfoText->append( QString( "\t%2\n" ).arg( scalarResults[elmNodeFaceStartResIdx + ptIdx] ) );
|
|
}
|
|
|
|
resultInfoText->append( QString( "Neg J Face:\n" ) );
|
|
for ( int ptIdx = 12; ptIdx < 16; ++ptIdx )
|
|
{
|
|
resultInfoText->append( QString( "\t%2\n" ).arg( scalarResults[elmNodeFaceStartResIdx + ptIdx] ) );
|
|
}
|
|
|
|
resultInfoText->append( QString( "Pos K Face:\n" ) );
|
|
for ( int ptIdx = 16; ptIdx < 20; ++ptIdx )
|
|
{
|
|
resultInfoText->append( QString( "\t%2\n" ).arg( scalarResults[elmNodeFaceStartResIdx + ptIdx] ) );
|
|
}
|
|
|
|
resultInfoText->append( QString( "Neg K Face:\n" ) );
|
|
for ( int ptIdx = 20; ptIdx < 24; ++ptIdx )
|
|
{
|
|
resultInfoText->append( QString( "\t%2\n" ).arg( scalarResults[elmNodeFaceStartResIdx + ptIdx] ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuFemResultTextBuilder::appendDetails( QString& text, const QString& details )
|
|
{
|
|
if ( !details.isEmpty() )
|
|
{
|
|
text += "\n";
|
|
text += details;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RiuFemResultTextBuilder::closestNodeResultText( RimGeoMechResultDefinition* resultColors )
|
|
{
|
|
QString text;
|
|
if ( !resultColors )
|
|
{
|
|
return text;
|
|
}
|
|
|
|
if ( resultColors->hasResult() )
|
|
{
|
|
if ( !( m_geomResDef->geoMechCase() && m_geomResDef->geoMechCase()->geoMechData() ) ) return text;
|
|
|
|
RigGeoMechCaseData* geomData = m_geomResDef->geoMechCase()->geoMechData();
|
|
|
|
auto address = RigFemAddressDefines::getResultLookupAddress( resultColors->resultAddress() );
|
|
|
|
const std::vector<float>& scalarResults =
|
|
geomData->femPartResults()->resultValues( address, m_gridIndex, m_timeStepIndex, m_frameIndex );
|
|
|
|
if ( !scalarResults.empty() && m_displayCoordView )
|
|
{
|
|
RigFemPart* femPart = geomData->femParts()->part( m_gridIndex );
|
|
RigFemResultPosEnum activeResultPosition = address.resultPosType;
|
|
|
|
cvf::Vec3d intersectionPointInDomain =
|
|
m_displayCoordView->displayCoordTransform()->translateToDomainCoord( m_intersectionPointInDisplay );
|
|
|
|
RigFemClosestResultIndexCalculator closestIndexCalc( femPart, activeResultPosition, m_cellIndex, m_face, intersectionPointInDomain );
|
|
|
|
int resultIndex = closestIndexCalc.resultIndexToClosestResult();
|
|
int closestNodeId = closestIndexCalc.closestNodeId();
|
|
int closestElmNodResIdx = closestIndexCalc.closestElementNodeResIdx();
|
|
|
|
float scalarValue = ( resultIndex >= 0 ) ? scalarResults[resultIndex] : std::numeric_limits<float>::infinity();
|
|
|
|
if ( activeResultPosition == RIG_ELEMENT )
|
|
{
|
|
text.append( QString( "Element result: %1\n" ).arg( scalarValue ) );
|
|
}
|
|
else if ( activeResultPosition != RIG_ELEMENT_NODAL_FACE )
|
|
{
|
|
text.append( QString( "Closest result: N[%1], %2\n" ).arg( closestNodeId ).arg( scalarValue ) );
|
|
}
|
|
else if ( m_face != -1 )
|
|
{
|
|
text.append( QString( "Closest result: N[%1], on face: %2, %3\n" )
|
|
.arg( closestNodeId )
|
|
.arg( caf::AppEnum<cvf::StructGridInterface::FaceType>::textFromIndex( m_face ) )
|
|
.arg( scalarValue ) );
|
|
}
|
|
else if ( m_isIntersectionTriangleSet && activeResultPosition == RIG_ELEMENT_NODAL_FACE )
|
|
{
|
|
RiuGeoMechXfTensorResultAccessor tensAccessor( geomData->femPartResults(), address, m_gridIndex, m_timeStepIndex, m_frameIndex );
|
|
float tensValue = tensAccessor.calculateElmNodeValue( m_intersectionTriangle, closestElmNodResIdx );
|
|
|
|
text.append( QString( "Closest result: N[%1], in Element[%2] transformed onto intersection: %3 \n" )
|
|
.arg( closestNodeId )
|
|
.arg( femPart->elmId( m_cellIndex ) )
|
|
.arg( tensValue ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
return text;
|
|
}
|