mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-25 14:40:26 -05:00
Migrate all assert macros in ApplicationLibCode to CAF_ASSERT and remove every use of cvfAssert.h. CVF_ASSERT is replaced one to one. CVF_TIGHT_ASSERT is also replaced by CAF_ASSERT, which is semantically exact: CVF_ENABLE_TIGHT_ASSERTS is 1 only under _DEBUG, and that is what CAF_ASSERT now does. The two CVF_FAIL_MSG sites become CAF_ASSERT( false && "message" ), preserving the message with the idiom already used elsewhere in the code base. Counts before and after: CVF_ASSERT 1044 to 0, CVF_TIGHT_ASSERT 66 to 0, CVF_FAIL_MSG 2 to 0, cvfAssert.h references 154 to 0. Include handling: files that included cvfAssert.h directly now include cafAssert.h instead, includes left dead by the migration are removed, and files that were relying on cvfAssert.h transitively get an explicit cafAssert.h. Files that reach cafAssert.h through another caf header are left unchanged; a missing include here is a compile error, not a silently disabled assert. ResultStatisticsCache links only LibCore and therefore had no path to cafAssert.h. Add the cafPdmCore directory as a private include path rather than linking the library, since cafAssert.h is header only. Note that this stops these asserts from firing in Release and RelWithDebInfo, where CVF_ASSERT was previously active.
991 lines
38 KiB
C++
991 lines
38 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2017-2018 Statoil ASA
|
|
// Copyright (C) 2018- 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 "RimFracture.h"
|
|
|
|
#include "RiaApplication.h"
|
|
#include "RiaColorTables.h"
|
|
#include "RiaCompletionTypeCalculationScheduler.h"
|
|
#include "RiaEclipseUnitTools.h"
|
|
#include "RiaLogging.h"
|
|
#include "RiuMessageDialog.h"
|
|
|
|
#include "Riu3DMainWindowTools.h"
|
|
|
|
#include "RigMainGrid.h"
|
|
|
|
#include "Rim3dView.h"
|
|
#include "RimEclipseCase.h"
|
|
#include "RimEclipseCellColors.h"
|
|
#include "RimEclipseView.h"
|
|
#include "RimEllipseFractureTemplate.h"
|
|
#include "RimFractureContainment.h"
|
|
#include "RimFractureTemplate.h"
|
|
#include "RimFractureTemplateCollection.h"
|
|
#include "RimOilField.h"
|
|
#include "RimProject.h"
|
|
#include "RimReservoirCellResultsStorage.h"
|
|
#include "RimStimPlanColors.h"
|
|
#include "RimStimPlanFractureTemplate.h"
|
|
|
|
#include "RivWellFracturePartMgr.h"
|
|
|
|
#include "FractureCommands/RicNewEllipseFractureTemplateFeature.h"
|
|
#include "FractureCommands/RicNewStimPlanFractureTemplateFeature.h"
|
|
|
|
#include "cafHexGridIntersectionTools/cafHexGridIntersectionTools.h"
|
|
|
|
#include "cafPdmUiDoubleSliderEditor.h"
|
|
#include "cafPdmUiToolButtonEditor.h"
|
|
#include "cafPdmUiTreeOrdering.h"
|
|
|
|
#include "cvfBoundingBox.h"
|
|
#include "cvfGeometryTools.h"
|
|
#include "cvfMath.h"
|
|
#include "cvfPlane.h"
|
|
|
|
#include <QString>
|
|
|
|
#include <cmath>
|
|
|
|
CAF_PDM_XML_ABSTRACT_SOURCE_INIT( RimFracture, "Fracture" );
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void setDefaultFractureColorResult()
|
|
{
|
|
RiaApplication* app = RiaApplication::instance();
|
|
RimProject* proj = app->project();
|
|
|
|
for ( RimEclipseCase* const eclCase : proj->eclipseCases() )
|
|
{
|
|
for ( Rim3dView* const view : eclCase->views() )
|
|
{
|
|
std::vector<RimStimPlanColors*> fractureColors = view->descendantsIncludingThisOfType<RimStimPlanColors>();
|
|
for ( RimStimPlanColors* const stimPlanColors : fractureColors )
|
|
{
|
|
stimPlanColors->setDefaultResultName();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimFracture::RimFracture()
|
|
{
|
|
CAF_PDM_InitObject( "Fracture" );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_fractureTemplate, "FractureDef", "Fracture Template" );
|
|
CAF_PDM_InitField( &m_editFractureTemplate, "EditTemplate", false, "Edit" );
|
|
m_editFractureTemplate.uiCapability()->setUiEditorTypeName( caf::PdmUiToolButtonEditor::uiEditorTypeName() );
|
|
m_editFractureTemplate.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::LabelPosition::HIDDEN );
|
|
|
|
CAF_PDM_InitField( &m_autoUpdateWellPathDepthAtFractureFromTemplate,
|
|
"AutoUpdateWellPathDepthAtFractureFromTemplate",
|
|
true,
|
|
"Auto-Update From Template" );
|
|
|
|
CAF_PDM_InitField( &m_wellPathDepthAtFracture, "WellPathDepthAtFracture", 0.0, "Well/Fracture Intersection Depth" );
|
|
m_wellPathDepthAtFracture.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_anchorPosition, "AnchorPosition", "Anchor Position" );
|
|
m_anchorPosition.uiCapability()->setUiHidden( true );
|
|
m_anchorPosition.xmlCapability()->disableIO();
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_uiAnchorPosition, "ui_positionAtWellpath", "Fracture Position" );
|
|
m_uiAnchorPosition.registerGetMethod( this, &RimFracture::fracturePositionForUi );
|
|
m_uiAnchorPosition.uiCapability()->setUiReadOnly( true );
|
|
|
|
CAF_PDM_InitField( &m_azimuth, "Azimuth", 0.0, "Azimuth" );
|
|
m_azimuth.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
|
|
|
|
CAF_PDM_InitField( &m_perforationLength, "PerforationLength", 1.0, "Perforation Length" );
|
|
CAF_PDM_InitField( &m_perforationEfficiency, "PerforationEfficiency", 1.0, "Perforation Efficiency" );
|
|
m_perforationEfficiency.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
|
|
|
|
CAF_PDM_InitField( &m_wellDiameter, "WellDiameter", 0.216, "Well Diameter at Fracture" );
|
|
CAF_PDM_InitField( &m_dip, "Dip", 0.0, "Dip" );
|
|
CAF_PDM_InitField( &m_tilt, "Tilt", 0.0, "Tilt" );
|
|
|
|
CAF_PDM_InitField( &m_fractureUnit,
|
|
"FractureUnit",
|
|
caf::AppEnum<RiaDefines::EclipseUnitSystem>( RiaDefines::EclipseUnitSystem::UNITS_METRIC ),
|
|
"Fracture Unit System" );
|
|
m_fractureUnit.uiCapability()->setUiReadOnly( true );
|
|
|
|
CAF_PDM_InitField( &m_stimPlanTimeIndexToPlot, "TimeIndexToPlot", 0, "StimPlan Time Step" );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_uiWellPathAzimuth, "WellPathAzimuth", "Well Path Azimuth" );
|
|
m_uiWellPathAzimuth.registerGetMethod( this, &RimFracture::wellAzimuthAtFracturePositionText );
|
|
m_uiWellPathAzimuth.uiCapability()->setUiReadOnly( true );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_uiWellFractureAzimuthDiff, "WellFractureAzimuthDiff", "Azimuth Difference Between\nFracture and Well" );
|
|
m_uiWellFractureAzimuthDiff.registerGetMethod( this, &RimFracture::wellFractureAzimuthDiffText );
|
|
m_uiWellFractureAzimuthDiff.uiCapability()->setUiReadOnly( true );
|
|
|
|
CAF_PDM_InitField( &m_wellFractureAzimuthAngleWarning,
|
|
"WellFractureAzimithAngleWarning",
|
|
QString( "Difference is below 10 degrees. Consider longitudinal fracture" ),
|
|
"" );
|
|
m_wellFractureAzimuthAngleWarning.uiCapability()->setUiReadOnly( true );
|
|
m_wellFractureAzimuthAngleWarning.xmlCapability()->disableIO();
|
|
|
|
m_fracturePartMgr = new RivWellFracturePartMgr( this );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimFracture::~RimFracture()
|
|
{
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimFracture::perforationLength() const
|
|
{
|
|
return m_perforationLength();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimFracture::perforationEfficiency() const
|
|
{
|
|
return m_perforationEfficiency();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::setStimPlanTimeIndexToPlot( int timeIndex )
|
|
{
|
|
m_stimPlanTimeIndexToPlot = timeIndex;
|
|
if ( m_autoUpdateWellPathDepthAtFractureFromTemplate )
|
|
{
|
|
placeUsingTemplateData();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<size_t> RimFracture::getPotentiallyFracturedCells( const RigMainGrid* mainGrid ) const
|
|
{
|
|
if ( !mainGrid ) return {};
|
|
|
|
cvf::BoundingBox fractureBBox = boundingBoxInDomainCoords();
|
|
return mainGrid->findIntersectingCells( fractureBBox );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
|
{
|
|
if ( changedField == &m_fractureTemplate )
|
|
{
|
|
if ( fractureUnit() != m_fractureTemplate->fractureTemplateUnit() )
|
|
{
|
|
QString fractureUnitText = caf::AppEnum<RiaDefines::EclipseUnitSystem>::uiText( fractureUnit() );
|
|
|
|
QString warningText = QString( "Using a fracture template defined in a different unit is not supported.\n\nPlease select a "
|
|
"fracture template of unit '%1'" )
|
|
.arg( fractureUnitText );
|
|
|
|
RiuMessageDialog::showError( nullptr, "Fracture Template Selection", warningText );
|
|
|
|
PdmObjectHandle* prevValue = oldValue.value<caf::PdmPointer<PdmObjectHandle>>().rawPtr();
|
|
auto prevTemplate = dynamic_cast<RimFractureTemplate*>( prevValue );
|
|
|
|
m_fractureTemplate = prevTemplate;
|
|
}
|
|
|
|
setFractureTemplate( m_fractureTemplate );
|
|
}
|
|
else if ( changedField == &m_editFractureTemplate )
|
|
{
|
|
m_editFractureTemplate = false;
|
|
if ( m_fractureTemplate != nullptr )
|
|
{
|
|
Riu3DMainWindowTools::selectAsCurrentItem( m_fractureTemplate() );
|
|
}
|
|
}
|
|
else if ( changedField == &m_autoUpdateWellPathDepthAtFractureFromTemplate )
|
|
{
|
|
if ( m_autoUpdateWellPathDepthAtFractureFromTemplate && m_fractureTemplate() )
|
|
{
|
|
m_wellPathDepthAtFracture = m_fractureTemplate->wellPathDepthAtFracture();
|
|
placeUsingTemplateData();
|
|
}
|
|
updateFractureGrid();
|
|
RimProject::current()->scheduleCreateDisplayModelAndRedrawAllViews();
|
|
}
|
|
|
|
else if ( changedField == &m_wellPathDepthAtFracture )
|
|
{
|
|
updateFractureGrid();
|
|
RimProject::current()->scheduleCreateDisplayModelAndRedrawAllViews();
|
|
}
|
|
|
|
if ( changedField == &m_stimPlanTimeIndexToPlot )
|
|
{
|
|
if ( m_autoUpdateWellPathDepthAtFractureFromTemplate() ) placeUsingTemplateData();
|
|
}
|
|
|
|
if ( changedField == &m_azimuth || changedField == &m_fractureTemplate || changedField == &m_stimPlanTimeIndexToPlot ||
|
|
changedField == objectToggleField() || changedField == &m_dip || changedField == &m_tilt || changedField == &m_perforationLength )
|
|
{
|
|
clearCachedNonDarcyProperties();
|
|
|
|
auto eclipseCase = firstAncestorOrThisOfType<RimEclipseCase>();
|
|
if ( eclipseCase )
|
|
{
|
|
RiaCompletionTypeCalculationScheduler::instance()->scheduleRecalculateCompletionTypeAndRedrawAllViews( { eclipseCase } );
|
|
}
|
|
else
|
|
{
|
|
RiaCompletionTypeCalculationScheduler::instance()->scheduleRecalculateCompletionTypeAndRedrawAllViews();
|
|
}
|
|
|
|
RimProject::current()->scheduleCreateDisplayModelAndRedrawAllViews();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
cvf::Vec3d RimFracture::fracturePosition() const
|
|
{
|
|
return m_anchorPosition;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const NonDarcyData& RimFracture::nonDarcyProperties() const
|
|
{
|
|
CAF_ASSERT( !m_cachedFractureProperties.isDirty() );
|
|
|
|
return m_cachedFractureProperties;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::ensureValidNonDarcyProperties()
|
|
{
|
|
// The computation of non-Darcy properties is expensive, so we cache the results.
|
|
// Make sure that the calling function calls this function before using the properties.
|
|
// https://github.com/OPM/ResInsight/issues/11663
|
|
|
|
if ( m_cachedFractureProperties.isDirty() )
|
|
{
|
|
NonDarcyData props;
|
|
|
|
if ( m_fractureTemplate )
|
|
{
|
|
props.width = m_fractureTemplate->computeFractureWidth( this );
|
|
props.conductivity = m_fractureTemplate->computeKh( this );
|
|
props.dFactor = m_fractureTemplate->computeDFactor( this );
|
|
props.effectivePermeability = m_fractureTemplate->computeEffectivePermeability( this );
|
|
props.eqWellRadius = m_fractureTemplate->computeWellRadiusForDFactorCalculation( this );
|
|
props.betaFactor = m_fractureTemplate->getOrComputeBetaFactor( this );
|
|
|
|
props.isDataDirty = false;
|
|
}
|
|
m_cachedFractureProperties = props;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::clearCachedNonDarcyProperties()
|
|
{
|
|
m_cachedFractureProperties = NonDarcyData();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RiaDefines::WellPathComponentType RimFracture::componentType() const
|
|
{
|
|
return RiaDefines::WellPathComponentType::FRACTURE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RimFracture::componentLabel() const
|
|
{
|
|
return name();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RimFracture::componentTypeLabel() const
|
|
{
|
|
return "Fracture";
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
cvf::Color3f RimFracture::defaultComponentColor() const
|
|
{
|
|
return RiaColorTables::wellPathComponentColors()[componentType()];
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimFracture::startMD() const
|
|
{
|
|
if ( fractureTemplate() && fractureTemplate()->orientationType() == RimFractureTemplate::ALONG_WELL_PATH )
|
|
{
|
|
return fractureMD() - 0.5 * perforationLength();
|
|
}
|
|
else
|
|
{
|
|
return fractureMD();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimFracture::endMD() const
|
|
{
|
|
if ( !fractureTemplate() ) return startMD();
|
|
|
|
if ( fractureTemplate()->orientationType() == RimFractureTemplate::ALONG_WELL_PATH )
|
|
{
|
|
return startMD() + perforationLength();
|
|
}
|
|
else
|
|
{
|
|
return startMD() + fractureTemplate()->computeFractureWidth( this );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// https://stackoverflow.com/a/52432897
|
|
//--------------------------------------------------------------------------------------------------
|
|
double getAbsoluteDiff2Angles( const double x, const double y, const double c )
|
|
{
|
|
// c can be PI (for radians) or 180.0 (for degrees);
|
|
return c - fabs( fmod( fabs( x - y ), 2 * c ) - c );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimFracture::wellFractureAzimuthDiff() const
|
|
{
|
|
// Compute the relative difference between two lines
|
|
// See https://github.com/OPM/ResInsight/issues/5899
|
|
|
|
double angle1 = wellAzimuthAtFracturePosition();
|
|
double angle2 = m_azimuth;
|
|
|
|
double diffDegrees = getAbsoluteDiff2Angles( angle1, angle2, 180.0 );
|
|
double smallesDiffDegrees = std::min( 180.0 - diffDegrees, diffDegrees );
|
|
|
|
return smallesDiffDegrees;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RimFracture::wellFractureAzimuthDiffText() const
|
|
{
|
|
double wellDifference = wellFractureAzimuthDiff();
|
|
return QString::number( wellDifference, 'f', 2 );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RimFracture::wellAzimuthAtFracturePositionText() const
|
|
{
|
|
double wellAzimuth = wellAzimuthAtFracturePosition();
|
|
return QString::number( wellAzimuth, 'f', 2 );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
cvf::BoundingBox RimFracture::boundingBoxInDomainCoords() const
|
|
{
|
|
std::vector<cvf::Vec3f> nodeCoordVec;
|
|
std::vector<cvf::uint> triangleIndices;
|
|
|
|
triangleGeometryTransformed( &triangleIndices, &nodeCoordVec, true );
|
|
|
|
cvf::BoundingBox fractureBBox;
|
|
for ( const auto& nodeCoord : nodeCoordVec )
|
|
fractureBBox.add( nodeCoord );
|
|
|
|
return fractureBBox;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimFracture::wellRadius() const
|
|
{
|
|
if ( m_fractureUnit == RiaDefines::EclipseUnitSystem::UNITS_METRIC )
|
|
{
|
|
return m_wellDiameter / 2.0;
|
|
}
|
|
else if ( m_fractureUnit == RiaDefines::EclipseUnitSystem::UNITS_FIELD )
|
|
{
|
|
return RiaEclipseUnitTools::inchToFeet( m_wellDiameter / 2.0 );
|
|
}
|
|
|
|
return cvf::UNDEFINED_DOUBLE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
cvf::Vec3d RimFracture::anchorPosition() const
|
|
{
|
|
return m_anchorPosition();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
cvf::Mat4d RimFracture::transformMatrix() const
|
|
{
|
|
cvf::Vec3d center = anchorPosition();
|
|
|
|
// Dip (in XY plane)
|
|
cvf::Mat4d dipRotation = cvf::Mat4d::fromRotation( cvf::Vec3d::Z_AXIS, cvf::Math::toRadians( m_dip() ) );
|
|
|
|
// Dip (out of XY plane)
|
|
cvf::Mat4d tiltRotation = cvf::Mat4d::fromRotation( cvf::Vec3d::X_AXIS, cvf::Math::toRadians( m_tilt() ) );
|
|
|
|
// Ellipsis geometry is produced in XY-plane, rotate 90 deg around X to get zero azimuth along Y
|
|
cvf::Mat4d rotationFromTesselator = cvf::Mat4d::fromRotation( cvf::Vec3d::X_AXIS, cvf::Math::toRadians( 90.0f ) );
|
|
|
|
// Azimuth rotation
|
|
cvf::Mat4d azimuthRotation = cvf::Mat4d::fromRotation( cvf::Vec3d::Z_AXIS, cvf::Math::toRadians( -m_azimuth() - 90 ) );
|
|
|
|
cvf::Mat4d m = azimuthRotation * rotationFromTesselator * dipRotation * tiltRotation;
|
|
m.setTranslation( center );
|
|
|
|
return m;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimFracture::dip() const
|
|
{
|
|
return m_dip();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::setDip( double dip )
|
|
{
|
|
m_dip = dip;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimFracture::tilt() const
|
|
{
|
|
return m_tilt();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::setTilt( double tilt )
|
|
{
|
|
m_tilt = tilt;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::setAzimuth( double azimuth )
|
|
{
|
|
m_azimuth = azimuth;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimFracture::azimuth() const
|
|
{
|
|
return m_azimuth();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::setFractureTemplateNoUpdate( RimFractureTemplate* fractureTemplate )
|
|
{
|
|
if ( fractureTemplate && fractureTemplate->fractureTemplateUnit() != fractureUnit() )
|
|
{
|
|
QString fractureUnitText = caf::AppEnum<RiaDefines::EclipseUnitSystem>::uiText( fractureUnit() );
|
|
|
|
QString warningText = QString( "Using a fracture template defined in a different unit is not supported.\n\nPlease select a "
|
|
"fracture template of unit '%1'" )
|
|
.arg( fractureUnitText );
|
|
|
|
RiuMessageDialog::showError( nullptr, "Fracture Template Selection", warningText );
|
|
|
|
return;
|
|
}
|
|
|
|
if ( m_fractureTemplate )
|
|
{
|
|
m_fractureTemplate->wellPathDepthAtFractureChanged.disconnect( this );
|
|
}
|
|
|
|
m_fractureTemplate = fractureTemplate;
|
|
|
|
if ( m_fractureTemplate )
|
|
{
|
|
m_fractureTemplate->wellPathDepthAtFractureChanged.connect( this, &RimFracture::onWellPathDepthAtFractureInTemplateChanged );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::triangleGeometry( std::vector<cvf::Vec3f>* nodeCoords, std::vector<cvf::uint>* triangleIndices ) const
|
|
{
|
|
triangleGeometryTransformed( triangleIndices, nodeCoords, false );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::triangleGeometryTransformed( std::vector<cvf::uint>* triangleIndices, std::vector<cvf::Vec3f>* nodeCoords, bool transform ) const
|
|
{
|
|
RimFractureTemplate* fractureDef = fractureTemplate();
|
|
if ( fractureDef )
|
|
{
|
|
fractureDef->fractureTriangleGeometry( nodeCoords, triangleIndices, m_wellPathDepthAtFracture );
|
|
}
|
|
|
|
if ( transform )
|
|
{
|
|
cvf::Mat4d m = transformMatrix();
|
|
|
|
for ( cvf::Vec3f& v : *nodeCoords )
|
|
{
|
|
cvf::Vec3d vd( v );
|
|
|
|
vd.transformPoint( m );
|
|
|
|
v = cvf::Vec3f( vd );
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
cvf::Vec3d RimFracture::fracturePositionForUi() const
|
|
{
|
|
cvf::Vec3d v = m_anchorPosition;
|
|
|
|
v.z() = -v.z();
|
|
|
|
return v;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QList<caf::PdmOptionItemInfo> RimFracture::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
|
|
{
|
|
QList<caf::PdmOptionItemInfo> options;
|
|
|
|
RimProject* proj = RimProject::current();
|
|
CAF_ASSERT( proj );
|
|
|
|
if ( fieldNeedingOptions == &m_fractureTemplate )
|
|
{
|
|
RimOilField* oilField = proj->activeOilField();
|
|
if ( oilField && oilField->fractureDefinitionCollection() )
|
|
{
|
|
RimFractureTemplateCollection* fracDefColl = oilField->fractureDefinitionCollection();
|
|
|
|
for ( RimFractureTemplate* fracDef : fracDefColl->fractureTemplates() )
|
|
{
|
|
QString displayText = fracDef->nameAndUnit();
|
|
if ( fracDef->fractureTemplateUnit() != fractureUnit() )
|
|
{
|
|
displayText += " (non-matching unit)";
|
|
}
|
|
|
|
options.push_back( caf::PdmOptionItemInfo( displayText, fracDef ) );
|
|
}
|
|
}
|
|
}
|
|
else if ( fieldNeedingOptions == &m_stimPlanTimeIndexToPlot )
|
|
{
|
|
if ( fractureTemplate() )
|
|
{
|
|
RimFractureTemplate* fracTemplate = fractureTemplate();
|
|
if ( dynamic_cast<RimMeshFractureTemplate*>( fracTemplate ) )
|
|
{
|
|
RimMeshFractureTemplate* fracTemplateStimPlan = dynamic_cast<RimMeshFractureTemplate*>( fracTemplate );
|
|
std::vector<double> timeValues = fracTemplateStimPlan->timeSteps();
|
|
int index = 0;
|
|
for ( double value : timeValues )
|
|
{
|
|
options.push_back( caf::PdmOptionItemInfo( QString::number( value ), index ) );
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
|
{
|
|
if ( m_fractureUnit() == RiaDefines::EclipseUnitSystem::UNITS_METRIC )
|
|
{
|
|
m_wellDiameter.uiCapability()->setUiName( "Well Diameter [m]" );
|
|
m_perforationLength.uiCapability()->setUiName( "Perforation Length [m]" );
|
|
}
|
|
else if ( m_fractureUnit() == RiaDefines::EclipseUnitSystem::UNITS_FIELD )
|
|
{
|
|
m_wellDiameter.uiCapability()->setUiName( "Well Diameter [inches]" );
|
|
m_perforationLength.uiCapability()->setUiName( "Perforation Length [ft]" );
|
|
}
|
|
|
|
uiOrdering.addNewButton( "Ellipse Template",
|
|
[this]() { RicNewEllipseFractureTemplateFeature::createNewTemplateForFractureAndUpdate( this ); },
|
|
{ .newRow = false } );
|
|
uiOrdering.addNewButton( "StimPlan Template",
|
|
[this]() { RicNewStimPlanFractureTemplateFeature::createNewTemplateForFractureAndUpdate( this ); },
|
|
{ .newRow = false } );
|
|
|
|
if ( fractureTemplate() )
|
|
{
|
|
if ( fractureTemplate()->orientationType() == RimFractureTemplate::ALONG_WELL_PATH ||
|
|
fractureTemplate()->orientationType() == RimFractureTemplate::TRANSVERSE_WELL_PATH )
|
|
{
|
|
m_uiWellPathAzimuth.uiCapability()->setUiHidden( true );
|
|
m_uiWellFractureAzimuthDiff.uiCapability()->setUiHidden( true );
|
|
m_wellFractureAzimuthAngleWarning.uiCapability()->setUiHidden( true );
|
|
}
|
|
|
|
else if ( fractureTemplate()->orientationType() == RimFractureTemplate::AZIMUTH )
|
|
{
|
|
m_uiWellPathAzimuth.uiCapability()->setUiHidden( false );
|
|
m_uiWellFractureAzimuthDiff.uiCapability()->setUiHidden( false );
|
|
if ( wellFractureAzimuthDiff() < 10 || ( wellFractureAzimuthDiff() > 170 && wellFractureAzimuthDiff() < 190 ) ||
|
|
wellFractureAzimuthDiff() > 350 )
|
|
{
|
|
m_wellFractureAzimuthAngleWarning.uiCapability()->setUiHidden( false );
|
|
}
|
|
else
|
|
{
|
|
m_wellFractureAzimuthAngleWarning.uiCapability()->setUiHidden( true );
|
|
}
|
|
}
|
|
|
|
m_wellPathDepthAtFracture.uiCapability()->setUiName( fractureTemplate()->wellPathDepthAtFractureUiName() );
|
|
|
|
if ( fractureTemplate()->orientationType() == RimFractureTemplate::ALONG_WELL_PATH ||
|
|
fractureTemplate()->orientationType() == RimFractureTemplate::TRANSVERSE_WELL_PATH )
|
|
{
|
|
m_azimuth.uiCapability()->setUiReadOnly( true );
|
|
}
|
|
else if ( fractureTemplate()->orientationType() == RimFractureTemplate::AZIMUTH )
|
|
{
|
|
m_azimuth.uiCapability()->setUiReadOnly( false );
|
|
}
|
|
|
|
fractureTemplate()->useUserDefinedPerforationLength();
|
|
|
|
if ( fractureTemplate()->orientationType() == RimFractureTemplate::ALONG_WELL_PATH ||
|
|
( fractureTemplate()->orientationType() == RimFractureTemplate::AZIMUTH && fractureTemplate()->useUserDefinedPerforationLength() ) )
|
|
{
|
|
m_perforationEfficiency.uiCapability()->setUiHidden( false );
|
|
m_perforationLength.uiCapability()->setUiHidden( false );
|
|
}
|
|
else
|
|
{
|
|
m_perforationEfficiency.uiCapability()->setUiHidden( true );
|
|
m_perforationLength.uiCapability()->setUiHidden( true );
|
|
}
|
|
|
|
if ( fractureTemplate()->useFiniteConductivityInFracture() )
|
|
{
|
|
m_wellDiameter.uiCapability()->setUiHidden( false );
|
|
}
|
|
else if ( fractureTemplate()->conductivityType() == RimFractureTemplate::INFINITE_CONDUCTIVITY )
|
|
{
|
|
m_wellDiameter.uiCapability()->setUiHidden( true );
|
|
}
|
|
|
|
RimFractureTemplate* fracTemplate = fractureTemplate();
|
|
if ( dynamic_cast<RimMeshFractureTemplate*>( fracTemplate ) )
|
|
{
|
|
m_stimPlanTimeIndexToPlot.uiCapability()->setUiHidden( false );
|
|
|
|
m_stimPlanTimeIndexToPlot.uiCapability()->setUiReadOnly( true );
|
|
}
|
|
else
|
|
{
|
|
m_stimPlanTimeIndexToPlot.uiCapability()->setUiHidden( true );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_stimPlanTimeIndexToPlot.uiCapability()->setUiHidden( true );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
|
|
{
|
|
if ( field == &m_azimuth )
|
|
{
|
|
caf::PdmUiDoubleSliderEditorAttribute* myAttr = dynamic_cast<caf::PdmUiDoubleSliderEditorAttribute*>( attribute );
|
|
if ( myAttr )
|
|
{
|
|
myAttr->m_minimum = 0;
|
|
myAttr->m_maximum = 360;
|
|
}
|
|
}
|
|
|
|
if ( field == &m_perforationEfficiency )
|
|
{
|
|
caf::PdmUiDoubleSliderEditorAttribute* myAttr = dynamic_cast<caf::PdmUiDoubleSliderEditorAttribute*>( attribute );
|
|
if ( myAttr )
|
|
{
|
|
myAttr->m_minimum = 0;
|
|
myAttr->m_maximum = 1.0;
|
|
}
|
|
}
|
|
|
|
if ( field == &m_wellPathDepthAtFracture )
|
|
{
|
|
caf::PdmUiDoubleSliderEditorAttribute* myAttr = dynamic_cast<caf::PdmUiDoubleSliderEditorAttribute*>( attribute );
|
|
if ( myAttr )
|
|
{
|
|
if ( fractureTemplate() )
|
|
{
|
|
auto [minimum, maximum] = fractureTemplate()->wellPathDepthAtFractureRange();
|
|
myAttr->m_minimum = minimum;
|
|
myAttr->m_maximum = maximum;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::setAnchorPosition( const cvf::Vec3d& pos )
|
|
{
|
|
m_anchorPosition = pos;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RiaDefines::EclipseUnitSystem RimFracture::fractureUnit() const
|
|
{
|
|
return m_fractureUnit();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::setFractureUnit( RiaDefines::EclipseUnitSystem unitSystem )
|
|
{
|
|
m_fractureUnit = unitSystem;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimFracture::isEclipseCellOpenForFlow( const RigMainGrid* mainGrid,
|
|
const std::set<size_t>& reservoirCellIndicesOpenForFlow,
|
|
size_t globalCellIndex ) const
|
|
{
|
|
CAF_ASSERT( fractureTemplate() );
|
|
if ( !fractureTemplate()->fractureContainment()->isEnabled() ) return true;
|
|
|
|
return fractureTemplate()->fractureContainment()->isEclipseCellOpenForFlow( mainGrid, globalCellIndex, reservoirCellIndicesOpenForFlow );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::setFractureTemplate( RimFractureTemplate* fractureTemplate )
|
|
{
|
|
setFractureTemplateNoUpdate( fractureTemplate );
|
|
|
|
if ( !fractureTemplate )
|
|
{
|
|
return;
|
|
}
|
|
|
|
RimStimPlanFractureTemplate* stimPlanFracTemplate = dynamic_cast<RimStimPlanFractureTemplate*>( fractureTemplate );
|
|
if ( stimPlanFracTemplate )
|
|
{
|
|
m_stimPlanTimeIndexToPlot = stimPlanFracTemplate->activeTimeStepIndex();
|
|
m_wellPathDepthAtFracture = stimPlanFracTemplate->wellPathDepthAtFracture();
|
|
double templateFormationDip = stimPlanFracTemplate->formationDip();
|
|
if ( templateFormationDip != HUGE_VAL ) m_dip = templateFormationDip;
|
|
}
|
|
else
|
|
{
|
|
m_wellPathDepthAtFracture = fractureTemplate->wellPathDepthAtFracture();
|
|
}
|
|
|
|
if ( fractureTemplate->orientationType() == RimFractureTemplate::AZIMUTH )
|
|
{
|
|
m_azimuth = fractureTemplate->azimuthAngle();
|
|
}
|
|
else
|
|
{
|
|
updateAzimuthBasedOnWellAzimuthAngle();
|
|
}
|
|
m_wellDiameter = fractureTemplate->wellDiameter();
|
|
m_perforationLength = fractureTemplate->perforationLength();
|
|
|
|
clearCachedNonDarcyProperties();
|
|
|
|
setDefaultFractureColorResult();
|
|
updateFractureGrid();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimFractureTemplate* RimFracture::fractureTemplate() const
|
|
{
|
|
return m_fractureTemplate();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RivWellFracturePartMgr* RimFracture::fracturePartManager()
|
|
{
|
|
CAF_ASSERT( m_fracturePartMgr.notNull() );
|
|
|
|
return m_fracturePartMgr.p();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::updateFractureGrid()
|
|
{
|
|
m_fractureGrid = nullptr;
|
|
|
|
if ( m_fractureTemplate() )
|
|
{
|
|
m_fractureGrid = m_fractureTemplate->createFractureGrid( m_wellPathDepthAtFracture );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const RigFractureGrid* RimFracture::fractureGrid() const
|
|
{
|
|
return m_fractureGrid.p();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::initAfterRead()
|
|
{
|
|
if ( RimProject::current()->isProjectFileVersionEqualOrOlderThan( "2020.10.2" ) )
|
|
{
|
|
if ( m_fractureTemplate() )
|
|
{
|
|
RimStimPlanFractureTemplate* stimPlanFracTemplate = dynamic_cast<RimStimPlanFractureTemplate*>( m_fractureTemplate() );
|
|
RimEllipseFractureTemplate* ellipseFracTemplate = dynamic_cast<RimEllipseFractureTemplate*>( m_fractureTemplate() );
|
|
|
|
if ( stimPlanFracTemplate )
|
|
{
|
|
m_wellPathDepthAtFracture = stimPlanFracTemplate->wellPathDepthAtFracture();
|
|
}
|
|
else if ( ellipseFracTemplate )
|
|
{
|
|
// This is a bit awkward, but initAfterRead for the templates
|
|
// happens after initAfterRead for the fracture. The value
|
|
// has not been corrected in the template at this point, so we
|
|
// have to calculate it explicitly.
|
|
m_wellPathDepthAtFracture = ellipseFracTemplate->computeLegacyWellDepthAtFracture();
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( m_fractureTemplate() )
|
|
{
|
|
m_fractureTemplate->wellPathDepthAtFractureChanged.connect( this, &RimFracture::onWellPathDepthAtFractureInTemplateChanged );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::onWellPathDepthAtFractureInTemplateChanged( const caf::SignalEmitter* emitter, double newDepth )
|
|
{
|
|
if ( m_autoUpdateWellPathDepthAtFractureFromTemplate )
|
|
{
|
|
m_wellPathDepthAtFracture = newDepth;
|
|
updateFractureGrid();
|
|
RimProject::current()->scheduleCreateDisplayModelAndRedrawAllViews();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimFracture::placeUsingTemplateData()
|
|
{
|
|
}
|