#7818 Modeled Well Path : Add support for creation of N laterals based on a template

This commit is contained in:
Magne Sjaastad
2021-06-28 14:17:46 +02:00
parent 95463c6521
commit 73f8046353
15 changed files with 970 additions and 16 deletions

View File

@@ -20,6 +20,8 @@ ${CMAKE_CURRENT_LIST_DIR}/RicImportWellMeasurementsFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicNewWellPathLateralAtDepthFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicNewWellPathLateralFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicPasteModeledWellPathFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicCreateMultipleWellPathLaterals.h
${CMAKE_CURRENT_LIST_DIR}/RicCreateMultipleWellPathLateralsUi.h
${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/Ric3dObjectEditorHandle.h
${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPointTangentManipulator.h
${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicWellTarget3dEditor.h
@@ -50,6 +52,8 @@ ${CMAKE_CURRENT_LIST_DIR}/RicImportWellMeasurementsFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewWellPathLateralAtDepthFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewWellPathLateralFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicPasteModeledWellPathFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicCreateMultipleWellPathLaterals.cpp
${CMAKE_CURRENT_LIST_DIR}/RicCreateMultipleWellPathLateralsUi.cpp
${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/Ric3dObjectEditorHandle.cpp
${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPointTangentManipulator.cpp
${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicWellTarget3dEditor.cpp
@@ -73,6 +77,7 @@ ${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicWellTarget3dEditor.h
${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicWellPathGeometry3dEditor.h
${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPolyline3dEditor.h
${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPolylineTarget3dEditor.h
${CMAKE_CURRENT_LIST_DIR}/RicCreateMultipleWellPathLaterals.h
)
source_group( "CommandFeature\\WellPath" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake )

View File

@@ -0,0 +1,193 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2021 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 "RicCreateMultipleWellPathLaterals.h"
#include "RigWellPath.h"
#include "RimModeledWellPath.h"
#include "RimProject.h"
#include "RimTools.h"
#include "RimWellPathCollection.h"
#include "RimWellPathGeometryDef.h"
#include "RimWellPathTarget.h"
#include "RimWellPathTieIn.h"
#include "Riu3DMainWindowTools.h"
#include "cafPdmUiPropertyViewDialog.h"
#include "cafSelectionManager.h"
#include "cafSelectionManagerTools.h"
#include <QAction>
#include <QDialogButtonBox>
#include <QPushButton>
#include <memory>
CAF_CMD_SOURCE_INIT( RicCreateMultipleWellPathLaterals, "RicCreateMultipleWellPathLaterals" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicCreateMultipleWellPathLaterals::isCommandEnabled()
{
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateMultipleWellPathLaterals::onActionTriggered( bool isChecked )
{
m_ui = std::make_unique<RicCreateMultipleWellPathLateralsUi>();
if ( m_ui.get() == nullptr ) m_ui = std::make_unique<RicCreateMultipleWellPathLateralsUi>();
auto selected = dynamic_cast<RimModeledWellPath*>( caf::SelectionManager::instance()->selectedItem() );
if ( selected )
{
m_ui->setSourceLateral( selected );
double startMD = 0.0;
double endMD = 0.0;
if ( auto tieIn = selected->wellPathTieIn() )
{
startMD = selected->wellPathTieIn()->tieInMeasuredDepth() + 50.0;
endMD = startMD + 50.0;
if ( auto parentWell = selected->wellPathTieIn()->parentWell() )
{
if ( !parentWell->wellPathGeometry()->measuredDepths().empty() )
{
double candidate = parentWell->wellPathGeometry()->measuredDepths().back() - 50.0;
if ( candidate > startMD ) endMD = candidate;
}
}
}
m_ui->setDefaultValues( startMD, endMD );
}
{
caf::PdmUiPropertyViewDialog propertyDialog( Riu3DMainWindowTools::mainWindowWidget(),
m_ui.get(),
"Create Multiple Well Path Laterals",
"" );
propertyDialog.resize( QSize( 700, 450 ) );
QDialogButtonBox* dialogButtonBox = propertyDialog.dialogButtonBox();
dialogButtonBox->clear();
{
QPushButton* pushButton = dialogButtonBox->addButton( "Create Laterals", QDialogButtonBox::ActionRole );
connect( pushButton, SIGNAL( clicked() ), this, SLOT( slotAppendFractures() ) );
pushButton->setDefault( false );
pushButton->setAutoDefault( false );
pushButton->setToolTip( "Add new fractures" );
}
{
QPushButton* pushButton = dialogButtonBox->addButton( "Close", QDialogButtonBox::ActionRole );
connect( pushButton, SIGNAL( clicked() ), &propertyDialog, SLOT( close() ) );
pushButton->setDefault( false );
pushButton->setAutoDefault( false );
}
propertyDialog.exec();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateMultipleWellPathLaterals::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setText( "Create Multiple Well Path Laterals" );
actionToSetup->setIcon( QIcon( ":/Well.svg" ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateMultipleWellPathLaterals::slotAppendFractures()
{
RimModeledWellPath* sourceLateral = m_ui->sourceLateral();
if ( !sourceLateral ) return;
if ( !sourceLateral->wellPathTieIn()->parentWell() ) return;
auto sourceLocationOfFirstWellTarget = sourceLateral->geometryDefinition()->firstActiveTarget()->targetPointXYZ();
RimWellPathCollection* wellPathCollection = RimTools::wellPathCollection();
if ( wellPathCollection )
{
int index = 0;
for ( auto measuredDepth : m_ui->locationConfig()->locations() )
{
RimModeledWellPath* newModeledWellPath = dynamic_cast<RimModeledWellPath*>(
sourceLateral->xmlCapability()->copyByXmlSerialization( caf::PdmDefaultObjectFactory::instance() ) );
QString name = sourceLateral->name() + QString( " (# %1)" ).arg( index++ );
newModeledWellPath->setName( name );
newModeledWellPath->wellPathTieIn()->setTieInMeasuredDepth( measuredDepth );
wellPathCollection->addWellPath( newModeledWellPath, false );
newModeledWellPath->resolveReferencesRecursively();
newModeledWellPath->updateReferencePoint();
updateLocationOfTargets( newModeledWellPath, sourceLocationOfFirstWellTarget );
newModeledWellPath->updateWellPathVisualization();
}
wellPathCollection->uiCapability()->updateConnectedEditors();
RimProject::current()->scheduleCreateDisplayModelAndRedrawAllViews();
m_ui->updateConnectedEditors();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateMultipleWellPathLaterals::updateLocationOfTargets( RimModeledWellPath* newModeledWellPath,
const cvf::Vec3d& sourceLocationOfFirstWellTarget )
{
newModeledWellPath->updateTieInLocationFromParentWell();
newModeledWellPath->wellPathTieIn()->updateFirstTargetFromParentWell();
auto firstTarget = newModeledWellPath->geometryDefinition()->firstActiveTarget();
auto locationOfFirstWellTarget = firstTarget->targetPointXYZ();
auto offsetFirstTarget = locationOfFirstWellTarget - sourceLocationOfFirstWellTarget;
auto targets = newModeledWellPath->geometryDefinition()->activeWellTargets();
for ( auto wellTarget : targets )
{
// Skip first target, as this is already updated by wellPathTieIn()->updateFirstTargetFromParentWell()
if ( wellTarget == firstTarget ) continue;
auto newTargetLocationXYZ = wellTarget->targetPointXYZ() + offsetFirstTarget;
wellTarget->setPointXYZ( newTargetLocationXYZ );
}
}

View File

@@ -0,0 +1,52 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2021 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
#include "RicCreateMultipleWellPathLateralsUi.h"
#include "cvfVector3.h"
#include <memory>
class RimModeledWellPath;
//==================================================================================================
///
//==================================================================================================
class RicCreateMultipleWellPathLaterals : public caf::CmdFeature
{
Q_OBJECT
CAF_CMD_HEADER_INIT;
protected:
bool isCommandEnabled() override;
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
private slots:
void slotAppendFractures();
void updateLocationOfTargets( RimModeledWellPath* newModeledWellPath,
const cvf::Vec3d& sourceLocationOfFirstWellTarget );
private:
std::unique_ptr<RicCreateMultipleWellPathLateralsUi> m_ui;
};

View File

@@ -0,0 +1,124 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2021 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 "RicCreateMultipleWellPathLateralsUi.h"
#include "RifTextDataTableFormatter.h"
#include "RigMainGrid.h"
#include "RigWellPath.h"
#include "RimModeledWellPath.h"
#include "RimTools.h"
#include "RimWellPathCollection.h"
#include "RimWellPathTieIn.h"
#include "cafCmdFeatureMenuBuilder.h"
#include "cafPdmUiPropertyViewDialog.h"
#include "cafPdmUiTableViewEditor.h"
#include "cafPdmUiTextEditor.h"
#include "cafSelectionManagerTools.h"
#include "cvfBoundingBox.h"
#include <algorithm>
CAF_PDM_SOURCE_INIT( RicCreateMultipleWellPathLateralsUi, "RicCreateMultipleWellPathLateralsUi" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RicCreateMultipleWellPathLateralsUi::RicCreateMultipleWellPathLateralsUi()
{
CAF_PDM_InitFieldNoDefault( &m_sourceLateral, "SourceLaterals", "Source Well Path Lateral", "", "", "" );
CAF_PDM_InitFieldNoDefault( &m_locations, "Locations", "Locations", "", "", "" );
m_locations = new RimMultipleLocations;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateMultipleWellPathLateralsUi::setSourceLateral( RimModeledWellPath* lateral )
{
m_sourceLateral = lateral;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateMultipleWellPathLateralsUi::setDefaultValues( double start, double end )
{
m_locations->setRange( start, end );
m_locations->computeRangesAndLocations();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimModeledWellPath* RicCreateMultipleWellPathLateralsUi::sourceLateral() const
{
return m_sourceLateral;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimMultipleLocations* RicCreateMultipleWellPathLateralsUi::locationConfig() const
{
return m_locations;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCreateMultipleWellPathLateralsUi::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_sourceLateral );
{
auto group = uiOrdering.addNewGroup( "Locations" );
m_locations->uiOrdering( uiConfigName, *group );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo>
RicCreateMultipleWellPathLateralsUi::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions,
bool* useOptionsOnly )
{
QList<caf::PdmOptionItemInfo> options;
if ( fieldNeedingOptions == &m_sourceLateral )
{
if ( sourceLateral()->wellPathTieIn() && sourceLateral()->wellPathTieIn()->parentWell() )
{
auto parentWell = sourceLateral()->wellPathTieIn()->parentWell();
auto laterals = RimTools::wellPathCollection()->connectedWellPathLaterals( parentWell );
for ( auto lateral : laterals )
{
options.push_back( caf::PdmOptionItemInfo( lateral->name(), lateral ) );
}
}
}
return options;
}

View File

@@ -0,0 +1,65 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2021 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimMultipleLocations.h"
#include "cafPdmChildArrayField.h"
#include "cafPdmChildField.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmProxyValueField.h"
#include "cafPdmPtrField.h"
#include <QPointer>
class RimModeledWellPath;
namespace caf
{
class PdmUiPropertyViewDialog;
}
//==================================================================================================
///
//==================================================================================================
class RicCreateMultipleWellPathLateralsUi : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
RicCreateMultipleWellPathLateralsUi();
void setSourceLateral( RimModeledWellPath* lateral );
void setDefaultValues( double start, double end );
RimModeledWellPath* sourceLateral() const;
RimMultipleLocations* locationConfig() const;
private:
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions,
bool* useOptionsOnly ) override;
private:
caf::PdmPtrField<RimModeledWellPath*> m_sourceLateral;
caf::PdmChildField<RimMultipleLocations*> m_locations;
};

View File

@@ -25,6 +25,7 @@ CAF_CMD_SOURCE_INIT( RicPasteModeledWellPathFeature, "RicPasteModeledWellPathFea
#include "RimModeledWellPath.h"
#include "RimOilField.h"
#include "RimWellPathCollection.h"
#include "RimWellPathTieIn.h"
#include "cafPdmObjectGroup.h"
#include "cafSelectionManager.h"
@@ -36,7 +37,7 @@ CAF_CMD_SOURCE_INIT( RicPasteModeledWellPathFeature, "RicPasteModeledWellPathFea
//--------------------------------------------------------------------------------------------------
bool RicPasteModeledWellPathFeature::isCommandEnabled()
{
if ( !modeledWellPaths().empty() ) return true;
if ( !modeledWellPathsFromClipboard().empty() ) return true;
{
std::vector<RimWellPathCollection*> objects;
caf::SelectionManager::instance()->objectsByType( &objects );
@@ -55,7 +56,7 @@ bool RicPasteModeledWellPathFeature::isCommandEnabled()
//--------------------------------------------------------------------------------------------------
void RicPasteModeledWellPathFeature::onActionTriggered( bool isChecked )
{
if ( modeledWellPaths().empty() ) return;
if ( modeledWellPathsFromClipboard().empty() ) return;
RimProject* proj = RimProject::current();
@@ -65,21 +66,28 @@ void RicPasteModeledWellPathFeature::onActionTriggered( bool isChecked )
if ( wellPathCollection )
{
for ( auto souceWellPath : modeledWellPaths() )
RimModeledWellPath* wellPathToSelect = nullptr;
for ( auto sourceWellPath : modeledWellPathsFromClipboard() )
{
RimModeledWellPath* newModeledWellPath = dynamic_cast<RimModeledWellPath*>(
souceWellPath->xmlCapability()->copyByXmlSerialization( caf::PdmDefaultObjectFactory::instance() ) );
RimModeledWellPath* destinationWellPath = dynamic_cast<RimModeledWellPath*>(
sourceWellPath->xmlCapability()->copyByXmlSerialization( caf::PdmDefaultObjectFactory::instance() ) );
QString name = souceWellPath->name() + " (copy)";
newModeledWellPath->setName( name );
QString name = sourceWellPath->name() + " (copy)";
destinationWellPath->setName( name );
wellPathCollection->addWellPath( newModeledWellPath, false );
wellPathCollection->uiCapability()->updateConnectedEditors();
wellPathCollection->addWellPath( destinationWellPath, false );
wellPathToSelect = destinationWellPath;
proj->scheduleCreateDisplayModelAndRedrawAllViews();
Riu3DMainWindowTools::selectAsCurrentItem( newModeledWellPath );
duplicateLaterals( sourceWellPath, destinationWellPath );
}
RimTools::wellPathCollection()->rebuildWellPathNodes();
wellPathCollection->uiCapability()->updateConnectedEditors();
proj->scheduleCreateDisplayModelAndRedrawAllViews();
Riu3DMainWindowTools::selectAsCurrentItem( wellPathToSelect );
}
}
}
@@ -96,7 +104,7 @@ void RicPasteModeledWellPathFeature::setupActionLook( QAction* actionToSetup )
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimModeledWellPath*> RicPasteModeledWellPathFeature::modeledWellPaths()
std::vector<RimModeledWellPath*> RicPasteModeledWellPathFeature::modeledWellPathsFromClipboard()
{
caf::PdmObjectGroup objectGroup;
RicPasteFeatureImpl::findObjectsFromClipboardRefs( &objectGroup );
@@ -112,3 +120,32 @@ std::vector<RimModeledWellPath*> RicPasteModeledWellPathFeature::modeledWellPath
return wellPaths;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicPasteModeledWellPathFeature::duplicateLaterals( RimModeledWellPath* source, RimModeledWellPath* destination )
{
auto wpc = RimTools::wellPathCollection();
auto sourceLaterals = wpc->connectedWellPathLaterals( source );
destination->createWellPathGeometry();
for ( auto lateral : sourceLaterals )
{
auto sourceLateral = dynamic_cast<RimModeledWellPath*>( lateral );
if ( !sourceLateral ) continue;
auto* destinationLateral = dynamic_cast<RimModeledWellPath*>(
sourceLateral->xmlCapability()->copyByXmlSerialization( caf::PdmDefaultObjectFactory::instance() ) );
QString name = sourceLateral->name() + " (copy)";
destinationLateral->setName( name );
wpc->addWellPath( destinationLateral, false );
destinationLateral->connectWellPaths( destination, sourceLateral->wellPathTieIn()->tieInMeasuredDepth() );
duplicateLaterals( sourceLateral, destinationLateral );
}
}

View File

@@ -34,5 +34,7 @@ protected:
void setupActionLook( QAction* actionToSetup ) override;
private:
static std::vector<RimModeledWellPath*> modeledWellPaths();
static std::vector<RimModeledWellPath*> modeledWellPathsFromClipboard();
void duplicateLaterals( RimModeledWellPath* source, RimModeledWellPath* destination );
};