ResInsight/ApplicationLibCode/ModelVisualization/RivElementVectorResultPartMgr.cpp

528 lines
22 KiB
C++
Raw Normal View History

2020-03-02 01:55:45 -06:00
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- 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 "RivElementVectorResultPartMgr.h"
#include "RimEclipseCase.h"
#include "RimEclipseView.h"
#include "RimElementVectorResult.h"
#include "RimRegularLegendConfig.h"
#include "RigActiveCellInfo.h"
#include "RigCaseCellResultsData.h"
#include "RigCell.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseResultAddress.h"
#include "RigMainGrid.h"
#include "RigNNCData.h"
2020-03-02 01:55:45 -06:00
#include "cafDisplayCoordTransform.h"
2020-03-02 01:55:45 -06:00
#include "cafEffectGenerator.h"
#include "cvfDrawableGeo.h"
#include "cvfGeometryTools.h"
2020-03-02 01:55:45 -06:00
#include "cvfModelBasicList.h"
#include "cvfPart.h"
#include "cvfPrimitiveSetIndexedUInt.h"
#include "cvfShaderProgram.h"
#include "cvfStructGrid.h"
#include "cvfStructGridGeometryGenerator.h"
#include <cmath>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivElementVectorResultPartMgr::RivElementVectorResultPartMgr( RimEclipseView* reservoirView )
{
m_rimReservoirView = reservoirView;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivElementVectorResultPartMgr::~RivElementVectorResultPartMgr()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivElementVectorResultPartMgr::setTransform( cvf::Transform* scaleTransform )
{
m_scaleTransform = scaleTransform;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivElementVectorResultPartMgr::appendDynamicGeometryPartsToModel( cvf::ModelBasicList* model, size_t timeStepIndex )
{
CVF_ASSERT( model );
if ( m_rimReservoirView.isNull() ) return;
RimEclipseCase* eclipseCase = m_rimReservoirView->eclipseCase();
if ( !eclipseCase ) return;
RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData();
if ( !eclipseCaseData ) return;
RimElementVectorResult* result = m_rimReservoirView->elementVectorResult();
if ( !result ) return;
if ( !result->showResult() ) return;
cvf::ref<caf::DisplayCoordTransform> displayCordXf = m_rimReservoirView->displayCoordTransform();
2020-03-02 01:55:45 -06:00
std::vector<ElementVectorResultVisualization> tensorVisualizations;
double characteristicCellSize = eclipseCase->characteristicCellSize();
float arrowConstantScaling = 10.0 * result->sizeScale() * characteristicCellSize;
2020-03-02 01:55:45 -06:00
double maxAbsResult = 1.0;
{
double min, max;
result->mappingRange( min, max );
if ( min != cvf::UNDEFINED_DOUBLE && max != cvf::UNDEFINED_DOUBLE )
{
maxAbsResult = std::max( cvf::Math::abs( max ), cvf::Math::abs( min ) );
}
2020-03-02 01:55:45 -06:00
}
float arrowScaling = arrowConstantScaling / maxAbsResult;
2020-03-02 01:55:45 -06:00
std::vector<RigEclipseResultAddress> resultAddresses;
Updates after 2020.10.1 release (#7104) * Set version to 2020.10.1-RC03 * #6780 Flow Vector Result: Check if data exists before using * #7031 Delta Summary Case: Fix crash when updating case name * #7036 Well Picks : Skip import of empty lines * #7003 Python: Guard nullpointer access for summary methods * #7014 Python: Resize the result container before assigning data * #7042 File Import Dialog : Sort by numbers instead of text * Set version to 2020.10.1-RC04 * #7008 Python: Avoid terminating process as part of open/closeProject When running scripts, a project file can be opened. If other operations are issued after, the process monitor window was disconnected from the script process, and no text output from the script was visible in the process monitor text window. New behavior : Never terminate a process automatically. Never terminate process as part of open/close project. If a process is left unresponsive, the user is now responsible for manual termination of this process. * #7045 Contour map : Disable clipping of smoothed contour lines * #7046 Cross Plot : Avoid reset of curve visibility when color legend visibility changes * #7048 Grid Cross Plot: Fix inverted Y-axis for user-defined min/max range * #7055 Contour Map: Label format it should match the legend format * #7059 Well Targets : Fix index of of bound crash when building well path * Set version to 2020.10.1-RC05 * #6814 Correlation Report: Missing update of plots when changing ensemble * Set version to 2020.10.1-RC06 * #7055 Contour Map: Label format it should match the legend format * #7068 Fix missing import surface File -> Import Surface * Set version to 2020.10.1-RC07 * Prepare for release of 2020.10.1 * #5641 Avoid unnecessary regeneration of contour map * Move clearGeometry to a scheduleGeometryRegen override * Trigger update of contour maps following legend changes * Make legend config changed signal more fine grained for Contour Maps * Set version to 2020.10.1-RC08 * Prepare for release of 2020.10.1 * Set dev version after patch release Co-authored-by: Gaute Lindkvist <lindkvis@gmail.com>
2020-12-10 03:44:23 -06:00
std::vector<cvf::StructGridInterface::FaceType> directions;
RigCaseCellResultsData* resultsData = eclipseCaseData->results( RiaDefines::PorosityModelType::MATRIX_MODEL );
{
Updates after 2020.10.1 release (#7104) * Set version to 2020.10.1-RC03 * #6780 Flow Vector Result: Check if data exists before using * #7031 Delta Summary Case: Fix crash when updating case name * #7036 Well Picks : Skip import of empty lines * #7003 Python: Guard nullpointer access for summary methods * #7014 Python: Resize the result container before assigning data * #7042 File Import Dialog : Sort by numbers instead of text * Set version to 2020.10.1-RC04 * #7008 Python: Avoid terminating process as part of open/closeProject When running scripts, a project file can be opened. If other operations are issued after, the process monitor window was disconnected from the script process, and no text output from the script was visible in the process monitor text window. New behavior : Never terminate a process automatically. Never terminate process as part of open/close project. If a process is left unresponsive, the user is now responsible for manual termination of this process. * #7045 Contour map : Disable clipping of smoothed contour lines * #7046 Cross Plot : Avoid reset of curve visibility when color legend visibility changes * #7048 Grid Cross Plot: Fix inverted Y-axis for user-defined min/max range * #7055 Contour Map: Label format it should match the legend format * #7059 Well Targets : Fix index of of bound crash when building well path * Set version to 2020.10.1-RC05 * #6814 Correlation Report: Missing update of plots when changing ensemble * Set version to 2020.10.1-RC06 * #7055 Contour Map: Label format it should match the legend format * #7068 Fix missing import surface File -> Import Surface * Set version to 2020.10.1-RC07 * Prepare for release of 2020.10.1 * #5641 Avoid unnecessary regeneration of contour map * Move clearGeometry to a scheduleGeometryRegen override * Trigger update of contour maps following legend changes * Make legend config changed signal more fine grained for Contour Maps * Set version to 2020.10.1-RC08 * Prepare for release of 2020.10.1 * Set dev version after patch release Co-authored-by: Gaute Lindkvist <lindkvis@gmail.com>
2020-12-10 03:44:23 -06:00
std::vector<RigEclipseResultAddress> addresses;
result->resultAddressesIJK( addresses );
for ( size_t fluidIndex = 0; fluidIndex < addresses.size(); fluidIndex += 3 )
{
Updates after 2020.10.1 release (#7104) * Set version to 2020.10.1-RC03 * #6780 Flow Vector Result: Check if data exists before using * #7031 Delta Summary Case: Fix crash when updating case name * #7036 Well Picks : Skip import of empty lines * #7003 Python: Guard nullpointer access for summary methods * #7014 Python: Resize the result container before assigning data * #7042 File Import Dialog : Sort by numbers instead of text * Set version to 2020.10.1-RC04 * #7008 Python: Avoid terminating process as part of open/closeProject When running scripts, a project file can be opened. If other operations are issued after, the process monitor window was disconnected from the script process, and no text output from the script was visible in the process monitor text window. New behavior : Never terminate a process automatically. Never terminate process as part of open/close project. If a process is left unresponsive, the user is now responsible for manual termination of this process. * #7045 Contour map : Disable clipping of smoothed contour lines * #7046 Cross Plot : Avoid reset of curve visibility when color legend visibility changes * #7048 Grid Cross Plot: Fix inverted Y-axis for user-defined min/max range * #7055 Contour Map: Label format it should match the legend format * #7059 Well Targets : Fix index of of bound crash when building well path * Set version to 2020.10.1-RC05 * #6814 Correlation Report: Missing update of plots when changing ensemble * Set version to 2020.10.1-RC06 * #7055 Contour Map: Label format it should match the legend format * #7068 Fix missing import surface File -> Import Surface * Set version to 2020.10.1-RC07 * Prepare for release of 2020.10.1 * #5641 Avoid unnecessary regeneration of contour map * Move clearGeometry to a scheduleGeometryRegen override * Trigger update of contour maps following legend changes * Make legend config changed signal more fine grained for Contour Maps * Set version to 2020.10.1-RC08 * Prepare for release of 2020.10.1 * Set dev version after patch release Co-authored-by: Gaute Lindkvist <lindkvis@gmail.com>
2020-12-10 03:44:23 -06:00
if ( result->showVectorI() )
{
if ( fluidIndex == 0 ) directions.push_back( cvf::StructGridInterface::POS_I );
auto candidate = addresses[0 + fluidIndex];
if ( resultsData->hasResultEntry( candidate ) && !resultsData->cellScalarResults( candidate, timeStepIndex ).empty() )
Updates after 2020.10.1 release (#7104) * Set version to 2020.10.1-RC03 * #6780 Flow Vector Result: Check if data exists before using * #7031 Delta Summary Case: Fix crash when updating case name * #7036 Well Picks : Skip import of empty lines * #7003 Python: Guard nullpointer access for summary methods * #7014 Python: Resize the result container before assigning data * #7042 File Import Dialog : Sort by numbers instead of text * Set version to 2020.10.1-RC04 * #7008 Python: Avoid terminating process as part of open/closeProject When running scripts, a project file can be opened. If other operations are issued after, the process monitor window was disconnected from the script process, and no text output from the script was visible in the process monitor text window. New behavior : Never terminate a process automatically. Never terminate process as part of open/close project. If a process is left unresponsive, the user is now responsible for manual termination of this process. * #7045 Contour map : Disable clipping of smoothed contour lines * #7046 Cross Plot : Avoid reset of curve visibility when color legend visibility changes * #7048 Grid Cross Plot: Fix inverted Y-axis for user-defined min/max range * #7055 Contour Map: Label format it should match the legend format * #7059 Well Targets : Fix index of of bound crash when building well path * Set version to 2020.10.1-RC05 * #6814 Correlation Report: Missing update of plots when changing ensemble * Set version to 2020.10.1-RC06 * #7055 Contour Map: Label format it should match the legend format * #7068 Fix missing import surface File -> Import Surface * Set version to 2020.10.1-RC07 * Prepare for release of 2020.10.1 * #5641 Avoid unnecessary regeneration of contour map * Move clearGeometry to a scheduleGeometryRegen override * Trigger update of contour maps following legend changes * Make legend config changed signal more fine grained for Contour Maps * Set version to 2020.10.1-RC08 * Prepare for release of 2020.10.1 * Set dev version after patch release Co-authored-by: Gaute Lindkvist <lindkvis@gmail.com>
2020-12-10 03:44:23 -06:00
{
resultAddresses.push_back( candidate );
}
}
if ( result->showVectorJ() )
{
if ( fluidIndex == 0 ) directions.push_back( cvf::StructGridInterface::POS_J );
auto candidate = addresses[1 + fluidIndex];
if ( resultsData->hasResultEntry( candidate ) && !resultsData->cellScalarResults( candidate, timeStepIndex ).empty() )
Updates after 2020.10.1 release (#7104) * Set version to 2020.10.1-RC03 * #6780 Flow Vector Result: Check if data exists before using * #7031 Delta Summary Case: Fix crash when updating case name * #7036 Well Picks : Skip import of empty lines * #7003 Python: Guard nullpointer access for summary methods * #7014 Python: Resize the result container before assigning data * #7042 File Import Dialog : Sort by numbers instead of text * Set version to 2020.10.1-RC04 * #7008 Python: Avoid terminating process as part of open/closeProject When running scripts, a project file can be opened. If other operations are issued after, the process monitor window was disconnected from the script process, and no text output from the script was visible in the process monitor text window. New behavior : Never terminate a process automatically. Never terminate process as part of open/close project. If a process is left unresponsive, the user is now responsible for manual termination of this process. * #7045 Contour map : Disable clipping of smoothed contour lines * #7046 Cross Plot : Avoid reset of curve visibility when color legend visibility changes * #7048 Grid Cross Plot: Fix inverted Y-axis for user-defined min/max range * #7055 Contour Map: Label format it should match the legend format * #7059 Well Targets : Fix index of of bound crash when building well path * Set version to 2020.10.1-RC05 * #6814 Correlation Report: Missing update of plots when changing ensemble * Set version to 2020.10.1-RC06 * #7055 Contour Map: Label format it should match the legend format * #7068 Fix missing import surface File -> Import Surface * Set version to 2020.10.1-RC07 * Prepare for release of 2020.10.1 * #5641 Avoid unnecessary regeneration of contour map * Move clearGeometry to a scheduleGeometryRegen override * Trigger update of contour maps following legend changes * Make legend config changed signal more fine grained for Contour Maps * Set version to 2020.10.1-RC08 * Prepare for release of 2020.10.1 * Set dev version after patch release Co-authored-by: Gaute Lindkvist <lindkvis@gmail.com>
2020-12-10 03:44:23 -06:00
{
resultAddresses.push_back( candidate );
}
}
if ( result->showVectorK() )
{
if ( fluidIndex == 0 ) directions.push_back( cvf::StructGridInterface::POS_K );
auto candidate = addresses[2 + fluidIndex];
if ( resultsData->hasResultEntry( candidate ) && !resultsData->cellScalarResults( candidate, timeStepIndex ).empty() )
Updates after 2020.10.1 release (#7104) * Set version to 2020.10.1-RC03 * #6780 Flow Vector Result: Check if data exists before using * #7031 Delta Summary Case: Fix crash when updating case name * #7036 Well Picks : Skip import of empty lines * #7003 Python: Guard nullpointer access for summary methods * #7014 Python: Resize the result container before assigning data * #7042 File Import Dialog : Sort by numbers instead of text * Set version to 2020.10.1-RC04 * #7008 Python: Avoid terminating process as part of open/closeProject When running scripts, a project file can be opened. If other operations are issued after, the process monitor window was disconnected from the script process, and no text output from the script was visible in the process monitor text window. New behavior : Never terminate a process automatically. Never terminate process as part of open/close project. If a process is left unresponsive, the user is now responsible for manual termination of this process. * #7045 Contour map : Disable clipping of smoothed contour lines * #7046 Cross Plot : Avoid reset of curve visibility when color legend visibility changes * #7048 Grid Cross Plot: Fix inverted Y-axis for user-defined min/max range * #7055 Contour Map: Label format it should match the legend format * #7059 Well Targets : Fix index of of bound crash when building well path * Set version to 2020.10.1-RC05 * #6814 Correlation Report: Missing update of plots when changing ensemble * Set version to 2020.10.1-RC06 * #7055 Contour Map: Label format it should match the legend format * #7068 Fix missing import surface File -> Import Surface * Set version to 2020.10.1-RC07 * Prepare for release of 2020.10.1 * #5641 Avoid unnecessary regeneration of contour map * Move clearGeometry to a scheduleGeometryRegen override * Trigger update of contour maps following legend changes * Make legend config changed signal more fine grained for Contour Maps * Set version to 2020.10.1-RC08 * Prepare for release of 2020.10.1 * Set dev version after patch release Co-authored-by: Gaute Lindkvist <lindkvis@gmail.com>
2020-12-10 03:44:23 -06:00
{
resultAddresses.push_back( candidate );
}
}
}
2020-03-02 01:55:45 -06:00
}
2020-04-23 23:53:06 -05:00
RigActiveCellInfo* activeCellInfo = eclipseCaseData->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL );
2020-03-02 01:55:45 -06:00
const std::vector<RigCell>& cells = eclipseCase->mainGrid()->globalCellArray();
auto getFaceCenterAndNormal = [cells, arrowScaling, displayCordXf]( size_t globalCellIdx,
cvf::StructGridInterface::FaceType faceType,
cvf::Vec3d& faceCenter,
cvf::Vec3d& faceNormal )
{
faceCenter = displayCordXf->transformToDisplayCoord( cells[globalCellIdx].faceCenter( faceType ) );
cvf::Vec3d cellCenter = displayCordXf->transformToDisplayCoord( cells[globalCellIdx].center() );
faceNormal = ( faceCenter - cellCenter ).getNormalized() * arrowScaling;
};
if ( !resultAddresses.empty() && !directions.empty() )
2020-03-02 01:55:45 -06:00
{
#pragma omp parallel for
for ( int gcIdx = 0; gcIdx < static_cast<int>( cells.size() ); ++gcIdx )
2020-03-02 01:55:45 -06:00
{
if ( !cells[gcIdx].isInvalid() && activeCellInfo->isActive( gcIdx ) )
2020-03-02 01:55:45 -06:00
{
size_t resultIdx = activeCellInfo->cellResultIndex( gcIdx );
if ( result->vectorView() == RimElementVectorResult::VectorView::PER_FACE )
{
for ( int dir = 0; dir < static_cast<int>( directions.size() ); dir++ )
{
double resultValue = 0.0;
for ( size_t flIdx = dir; flIdx < resultAddresses.size(); flIdx += directions.size() )
{
resultValue += resultsData->cellScalarResults( resultAddresses[flIdx], timeStepIndex ).at( resultIdx );
}
if ( std::abs( resultValue ) >= result->threshold() )
{
cvf::Vec3d faceCenter;
cvf::Vec3d faceNormal;
getFaceCenterAndNormal( static_cast<size_t>( gcIdx ), directions[dir], faceCenter, faceNormal );
faceNormal *= std::abs( resultValue );
bool centerArrow = false;
if ( result->vectorSuraceCrossingLocation() == RimElementVectorResult::VectorSurfaceCrossingLocation::VECTOR_CENTER &&
result->vectorView() == RimElementVectorResult::VectorView::PER_FACE )
{
centerArrow = true;
}
#pragma omp critical( critical_section_RivElementVectorResultPartMgr_add_1 )
tensorVisualizations.push_back( ElementVectorResultVisualization( faceCenter,
faceNormal,
resultValue,
std::cbrt( cells[gcIdx].volume() / 3.0 ),
centerArrow ) );
}
}
}
else if ( result->vectorView() == RimElementVectorResult::VectorView::CELL_CENTER_TOTAL )
{
cvf::Vec3d aggregatedVector;
cvf::Vec3d aggregatedResult;
for ( int dir = 0; dir < static_cast<int>( directions.size() ); dir++ )
{
double resultValue = 0.0;
for ( size_t flIdx = dir; flIdx < resultAddresses.size(); flIdx += directions.size() )
{
resultValue += resultsData->cellScalarResults( resultAddresses[flIdx], timeStepIndex ).at( resultIdx );
}
2020-03-02 01:55:45 -06:00
cvf::Vec3d faceCenter;
cvf::Vec3d faceNormal;
cvf::Vec3d faceNormalScaled;
getFaceCenterAndNormal( gcIdx, directions[dir], faceCenter, faceNormal );
faceNormalScaled = faceNormal * resultValue;
aggregatedVector += faceNormalScaled;
aggregatedResult += faceNormal.getNormalized() * resultValue;
}
if ( aggregatedResult.length() >= result->threshold() )
{
bool centerArrow = false;
if ( result->vectorSuraceCrossingLocation() == RimElementVectorResult::VectorSurfaceCrossingLocation::VECTOR_CENTER )
{
centerArrow = true;
}
#pragma omp critical( critical_section_RivElementVectorResultPartMgr_add_2 )
tensorVisualizations.push_back(
ElementVectorResultVisualization( displayCordXf->transformToDisplayCoord( cells[gcIdx].center() ),
aggregatedVector,
aggregatedResult.length(),
std::cbrt( cells[gcIdx].volume() / 3.0 ),
centerArrow ) );
}
}
}
}
}
if ( result->showNncData() )
{
RigNNCData* nncData = eclipseCaseData->mainGrid()->nncData();
nncData->buildPolygonsForEclipseConnections();
std::vector<const std::vector<std::vector<double>>*> nncResultVals;
std::vector<RigEclipseResultAddress> combinedAddresses;
result->resultAddressesCombined( combinedAddresses );
Updates after 2020.10.1 release (#7104) * Set version to 2020.10.1-RC03 * #6780 Flow Vector Result: Check if data exists before using * #7031 Delta Summary Case: Fix crash when updating case name * #7036 Well Picks : Skip import of empty lines * #7003 Python: Guard nullpointer access for summary methods * #7014 Python: Resize the result container before assigning data * #7042 File Import Dialog : Sort by numbers instead of text * Set version to 2020.10.1-RC04 * #7008 Python: Avoid terminating process as part of open/closeProject When running scripts, a project file can be opened. If other operations are issued after, the process monitor window was disconnected from the script process, and no text output from the script was visible in the process monitor text window. New behavior : Never terminate a process automatically. Never terminate process as part of open/close project. If a process is left unresponsive, the user is now responsible for manual termination of this process. * #7045 Contour map : Disable clipping of smoothed contour lines * #7046 Cross Plot : Avoid reset of curve visibility when color legend visibility changes * #7048 Grid Cross Plot: Fix inverted Y-axis for user-defined min/max range * #7055 Contour Map: Label format it should match the legend format * #7059 Well Targets : Fix index of of bound crash when building well path * Set version to 2020.10.1-RC05 * #6814 Correlation Report: Missing update of plots when changing ensemble * Set version to 2020.10.1-RC06 * #7055 Contour Map: Label format it should match the legend format * #7068 Fix missing import surface File -> Import Surface * Set version to 2020.10.1-RC07 * Prepare for release of 2020.10.1 * #5641 Avoid unnecessary regeneration of contour map * Move clearGeometry to a scheduleGeometryRegen override * Trigger update of contour maps following legend changes * Make legend config changed signal more fine grained for Contour Maps * Set version to 2020.10.1-RC08 * Prepare for release of 2020.10.1 * Set dev version after patch release Co-authored-by: Gaute Lindkvist <lindkvis@gmail.com>
2020-12-10 03:44:23 -06:00
for ( auto candidate : combinedAddresses )
{
if ( candidate.resultCatType() == RiaDefines::ResultCatType::DYNAMIC_NATIVE )
{
Updates after 2020.10.1 release (#7104) * Set version to 2020.10.1-RC03 * #6780 Flow Vector Result: Check if data exists before using * #7031 Delta Summary Case: Fix crash when updating case name * #7036 Well Picks : Skip import of empty lines * #7003 Python: Guard nullpointer access for summary methods * #7014 Python: Resize the result container before assigning data * #7042 File Import Dialog : Sort by numbers instead of text * Set version to 2020.10.1-RC04 * #7008 Python: Avoid terminating process as part of open/closeProject When running scripts, a project file can be opened. If other operations are issued after, the process monitor window was disconnected from the script process, and no text output from the script was visible in the process monitor text window. New behavior : Never terminate a process automatically. Never terminate process as part of open/close project. If a process is left unresponsive, the user is now responsible for manual termination of this process. * #7045 Contour map : Disable clipping of smoothed contour lines * #7046 Cross Plot : Avoid reset of curve visibility when color legend visibility changes * #7048 Grid Cross Plot: Fix inverted Y-axis for user-defined min/max range * #7055 Contour Map: Label format it should match the legend format * #7059 Well Targets : Fix index of of bound crash when building well path * Set version to 2020.10.1-RC05 * #6814 Correlation Report: Missing update of plots when changing ensemble * Set version to 2020.10.1-RC06 * #7055 Contour Map: Label format it should match the legend format * #7068 Fix missing import surface File -> Import Surface * Set version to 2020.10.1-RC07 * Prepare for release of 2020.10.1 * #5641 Avoid unnecessary regeneration of contour map * Move clearGeometry to a scheduleGeometryRegen override * Trigger update of contour maps following legend changes * Make legend config changed signal more fine grained for Contour Maps * Set version to 2020.10.1-RC08 * Prepare for release of 2020.10.1 * Set dev version after patch release Co-authored-by: Gaute Lindkvist <lindkvis@gmail.com>
2020-12-10 03:44:23 -06:00
if ( nncData->hasScalarValues( candidate ) )
{
nncResultVals.push_back( nncData->dynamicConnectionScalarResult( candidate ) );
}
}
}
#pragma omp parallel for
for ( int nIdx = 0; nIdx < static_cast<int>( nncData->eclipseConnectionCount() ); ++nIdx )
{
const RigConnection& conn = nncData->availableConnections()[nIdx];
if ( conn.polygon().size() )
{
double resultValue = 0.0;
for ( size_t flIdx = 0; flIdx < nncResultVals.size(); flIdx++ )
{
if ( nIdx < static_cast<int>( nncResultVals.at( flIdx )->at( timeStepIndex ).size() ) )
{
resultValue += nncResultVals.at( flIdx )->at( timeStepIndex )[nIdx];
}
}
cvf::Vec3d connCenter = static_cast<cvf::Vec3d>( cvf::GeometryTools::computePolygonCenter<cvf::Vec3f>( conn.polygon() ) );
cvf::Vec3d faceCenter;
cvf::Vec3d connNormal;
getFaceCenterAndNormal( conn.c1GlobIdx(), conn.face(), faceCenter, connNormal );
connNormal *= std::abs( resultValue );
if ( std::abs( resultValue ) >= result->threshold() )
{
bool centerArrow = false;
if ( result->vectorView() == RimElementVectorResult::VectorView::CELL_CENTER_TOTAL )
{
centerArrow = true;
}
else if ( result->vectorView() == RimElementVectorResult::VectorView::PER_FACE )
{
if ( result->vectorSuraceCrossingLocation() == RimElementVectorResult::VectorSurfaceCrossingLocation::VECTOR_CENTER )
centerArrow = true;
}
#pragma omp critical( critical_section_RivElementVectorResultPartMgr_add_nnc )
tensorVisualizations.push_back( ElementVectorResultVisualization( displayCordXf->transformToDisplayCoord( connCenter ),
connNormal,
resultValue,
std::cbrt( cells[conn.c1GlobIdx()].volume() / 3.0 ),
centerArrow ) );
}
}
2020-03-02 01:55:45 -06:00
}
}
if ( !tensorVisualizations.empty() )
{
cvf::ref<cvf::Part> partIdx = createPart( *result, tensorVisualizations );
partIdx->updateBoundingBox();
model->addPart( partIdx.p() );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::Part> RivElementVectorResultPartMgr::createPart( const RimElementVectorResult& result,
const std::vector<ElementVectorResultVisualization>& tensorVisualizations ) const
2020-03-02 01:55:45 -06:00
{
std::vector<uint> shaftIndices;
shaftIndices.reserve( tensorVisualizations.size() * 2 );
std::vector<uint> headIndices;
headIndices.reserve( tensorVisualizations.size() * 6 );
2020-03-02 01:55:45 -06:00
std::vector<cvf::Vec3f> vertices;
vertices.reserve( tensorVisualizations.size() * 7 );
2020-03-02 01:55:45 -06:00
uint counter = 0;
for ( const ElementVectorResultVisualization& tensor : tensorVisualizations )
2020-03-02 01:55:45 -06:00
{
for ( const cvf::Vec3f& vertex : createArrowVertices( tensor ) )
{
vertices.push_back( vertex );
}
for ( const uint& index : createArrowShaftIndices( counter ) )
{
shaftIndices.push_back( index );
}
for ( const uint& index : createArrowHeadIndices( counter ) )
2020-03-02 01:55:45 -06:00
{
headIndices.push_back( index );
2020-03-02 01:55:45 -06:00
}
counter += 7;
2020-03-02 01:55:45 -06:00
}
cvf::ref<cvf::PrimitiveSetIndexedUInt> indexedUIntShaft = new cvf::PrimitiveSetIndexedUInt( cvf::PrimitiveType::PT_LINES );
cvf::ref<cvf::UIntArray> indexArrayShaft = new cvf::UIntArray( shaftIndices );
cvf::ref<cvf::PrimitiveSetIndexedUInt> indexedUIntHead = new cvf::PrimitiveSetIndexedUInt( cvf::PrimitiveType::PT_TRIANGLES );
cvf::ref<cvf::UIntArray> indexArrayHead = new cvf::UIntArray( headIndices );
2020-03-02 01:55:45 -06:00
cvf::ref<cvf::DrawableGeo> drawable = new cvf::DrawableGeo();
indexedUIntShaft->setIndices( indexArrayShaft.p() );
drawable->addPrimitiveSet( indexedUIntShaft.p() );
indexedUIntHead->setIndices( indexArrayHead.p() );
drawable->addPrimitiveSet( indexedUIntHead.p() );
2020-03-02 01:55:45 -06:00
cvf::ref<cvf::Vec3fArray> vertexArray = new cvf::Vec3fArray( vertices );
drawable->setVertexArray( vertexArray.p() );
cvf::ref<cvf::Vec2fArray> lineTexCoords = const_cast<cvf::Vec2fArray*>( drawable->textureCoordArray() );
if ( lineTexCoords.isNull() )
{
lineTexCoords = new cvf::Vec2fArray;
}
const cvf::ScalarMapper* activeScalerMapper = nullptr;
cvf::ref<cvf::Effect> effect;
auto vectorColors = result.vectorColors();
if ( vectorColors == RimElementVectorResult::TensorColors::RESULT_COLORS )
2020-03-02 01:55:45 -06:00
{
activeScalerMapper = result.legendConfig()->scalarMapper();
createResultColorTextureCoords( lineTexCoords.p(), tensorVisualizations, activeScalerMapper );
caf::ScalarMapperMeshEffectGenerator meshEffGen( activeScalerMapper );
effect = meshEffGen.generateCachedEffect();
}
else
{
caf::SurfaceEffectGenerator surfaceGen( result.getUniformVectorColor(), caf::PO_1 );
surfaceGen.enableLighting( !m_rimReservoirView->isLightingDisabled() );
effect = surfaceGen.generateCachedEffect();
}
drawable->setTextureCoordArray( lineTexCoords.p() );
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName( "RivElementVectorResultPartMgr::createPart" );
2020-03-02 01:55:45 -06:00
part->setDrawable( drawable.p() );
part->setEffect( effect.p() );
return part;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivElementVectorResultPartMgr::createResultColorTextureCoords( cvf::Vec2fArray* textureCoords,
const std::vector<ElementVectorResultVisualization>& elementVectorResultVisualizations,
const cvf::ScalarMapper* mapper )
2020-03-02 01:55:45 -06:00
{
CVF_ASSERT( textureCoords );
CVF_ASSERT( mapper );
size_t vertexCount = elementVectorResultVisualizations.size() * 7;
2020-03-02 01:55:45 -06:00
if ( textureCoords->size() != vertexCount ) textureCoords->reserve( vertexCount );
for ( auto& evrViz : elementVectorResultVisualizations )
2020-03-02 01:55:45 -06:00
{
for ( size_t vxIdx = 0; vxIdx < 7; ++vxIdx )
2020-03-02 01:55:45 -06:00
{
cvf::Vec2f texCoord = mapper->mapToTextureCoord( std::abs( evrViz.result ) );
2020-03-02 01:55:45 -06:00
textureCoords->add( texCoord );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::array<cvf::Vec3f, 7> RivElementVectorResultPartMgr::createArrowVertices( const ElementVectorResultVisualization& evrViz ) const
2020-03-02 01:55:45 -06:00
{
std::array<cvf::Vec3f, 7> vertices;
RimElementVectorResult* result = m_rimReservoirView->elementVectorResult();
if ( !result ) return vertices;
2020-03-02 01:55:45 -06:00
cvf::Vec3f headTop = evrViz.faceCenter + evrViz.faceNormal;
cvf::Vec3f shaftStart = evrViz.faceCenter;
if ( evrViz.centerArrow )
{
headTop = evrViz.faceCenter + evrViz.faceNormal / 2.0;
shaftStart = evrViz.faceCenter - evrViz.faceNormal / 2.0;
}
2020-03-02 01:55:45 -06:00
2020-09-30 03:47:46 -05:00
// Flip arrow for negative results and if the vector is not aggregated (in which case we do not have any negative
// result)
if ( evrViz.result < 0 )
2020-03-02 01:55:45 -06:00
{
std::swap( headTop, shaftStart );
}
float headLength = std::min<float>( evrViz.approximateCellLength / 3.0f, ( headTop - shaftStart ).length() / 2.0 );
2020-03-02 01:55:45 -06:00
// A fixed size is preferred here
cvf::Vec3f headBottom = headTop - ( headTop - shaftStart ).getNormalized() * headLength;
2020-03-02 01:55:45 -06:00
float arrowWidth = headLength / 2.0f;
cvf::Vec3f headBottomDirection1 = evrViz.faceNormal ^ evrViz.faceCenter;
cvf::Vec3f headBottomDirection2 = headBottomDirection1 ^ evrViz.faceNormal;
cvf::Vec3f arrowBottomSegment1 = headBottomDirection1.getNormalized() * arrowWidth;
cvf::Vec3f arrowBottomSegment2 = headBottomDirection2.getNormalized() * arrowWidth;
2020-03-02 01:55:45 -06:00
vertices[0] = shaftStart;
vertices[1] = headBottom;
vertices[2] = headBottom + arrowBottomSegment1;
vertices[3] = headBottom - arrowBottomSegment1;
2020-03-02 01:55:45 -06:00
vertices[4] = headTop;
vertices[5] = headBottom + arrowBottomSegment2;
vertices[6] = headBottom - arrowBottomSegment2;
2020-03-02 01:55:45 -06:00
return vertices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::array<uint, 2> RivElementVectorResultPartMgr::createArrowShaftIndices( uint startIndex ) const
2020-03-02 01:55:45 -06:00
{
std::array<uint, 2> indices;
2020-03-02 01:55:45 -06:00
indices[0] = startIndex;
indices[1] = startIndex + 1;
2020-09-22 10:20:35 -05:00
return indices;
2020-09-22 10:20:35 -05:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::array<uint, 6> RivElementVectorResultPartMgr::createArrowHeadIndices( uint startIndex ) const
{
std::array<uint, 6> indices;
indices[0] = startIndex + 2;
indices[1] = startIndex + 3;
indices[2] = startIndex + 4;
indices[3] = startIndex + 5;
indices[4] = startIndex + 6;
indices[5] = startIndex + 4;
return indices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RivElementVectorResultPartMgr::scaleLogarithmically( double value ) const
{
2020-09-30 03:47:46 -05:00
// If values are smaller than one, the logarithm would return
// increasing negative values the smaller the number is. However, small
// numbers shall remain small and not be scaled up. In order to achieve this,
// add 1.0 to small values in order to still obtain small positive numbers after scaling.
if ( value <= 1.0 )
{
value += 1.0;
}
return std::log10( value );
}