mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
#2423 Export Completions : Move Rig*-files to completion export folder
This commit is contained in:
@@ -5,10 +5,8 @@ if (${CMAKE_VERSION} VERSION_GREATER "2.8.2")
|
||||
endif()
|
||||
|
||||
set (SOURCE_GROUP_HEADER_FILES
|
||||
${CEE_CURRENT_LIST_DIR}RicCaseAndFileExportSettingsUi.h
|
||||
${CEE_CURRENT_LIST_DIR}RicEditPerforationCollectionFeature.h
|
||||
${CEE_CURRENT_LIST_DIR}RicExportFishbonesLateralsFeature.h
|
||||
${CEE_CURRENT_LIST_DIR}RicExportFishbonesWellSegmentsFeature.h
|
||||
${CEE_CURRENT_LIST_DIR}RicNewFishbonesSubsAtMeasuredDepthFeature.h
|
||||
${CEE_CURRENT_LIST_DIR}RicNewFishbonesSubsFeature.h
|
||||
${CEE_CURRENT_LIST_DIR}RicNewPerforationIntervalFeature.h
|
||||
@@ -18,10 +16,8 @@ ${CEE_CURRENT_LIST_DIR}RicWellPathImportPerforationIntervalsFeature.h
|
||||
)
|
||||
|
||||
set (SOURCE_GROUP_SOURCE_FILES
|
||||
${CEE_CURRENT_LIST_DIR}RicCaseAndFileExportSettingsUi.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RicEditPerforationCollectionFeature.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RicExportFishbonesLateralsFeature.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RicExportFishbonesWellSegmentsFeature.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RicNewFishbonesSubsAtMeasuredDepthFeature.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RicNewFishbonesSubsFeature.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RicNewPerforationIntervalFeature.cpp
|
||||
|
||||
@@ -8,11 +8,19 @@ set (SOURCE_GROUP_HEADER_FILES
|
||||
${CEE_CURRENT_LIST_DIR}RicExportCompletionDataSettingsUi.h
|
||||
${CEE_CURRENT_LIST_DIR}RicWellPathExportCompletionDataFeature.h
|
||||
${CEE_CURRENT_LIST_DIR}RicFishbonesTransmissibilityCalculationFeatureImp.h
|
||||
${CEE_CURRENT_LIST_DIR}RigCompletionData.h
|
||||
${CEE_CURRENT_LIST_DIR}RigCompletionDataGridCell.h
|
||||
${CEE_CURRENT_LIST_DIR}RicExportFishbonesWellSegmentsFeature.h
|
||||
${CEE_CURRENT_LIST_DIR}RicCaseAndFileExportSettingsUi.h
|
||||
)
|
||||
|
||||
if (RESINSIGHT_ENABLE_PROTOTYPE_FEATURE_FRACTURES)
|
||||
list (APPEND SOURCE_GROUP_HEADER_FILES
|
||||
${CEE_CURRENT_LIST_DIR}RicExportFractureCompletionsImpl.h
|
||||
${CEE_CURRENT_LIST_DIR}RigEclipseToStimPlanCellTransmissibilityCalculator.h
|
||||
${CEE_CURRENT_LIST_DIR}RigTransmissibilityCondenser.h
|
||||
${CEE_CURRENT_LIST_DIR}RigFractureTransmissibilityEquations.h
|
||||
${CEE_CURRENT_LIST_DIR}RigWellPathStimplanIntersector.h
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -21,11 +29,19 @@ set (SOURCE_GROUP_SOURCE_FILES
|
||||
${CEE_CURRENT_LIST_DIR}RicExportCompletionDataSettingsUi.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RicWellPathExportCompletionDataFeature.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RicFishbonesTransmissibilityCalculationFeatureImp.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RigCompletionData.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RigCompletionDataGridCell.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RicExportFishbonesWellSegmentsFeature.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RicCaseAndFileExportSettingsUi.cpp
|
||||
)
|
||||
|
||||
if (RESINSIGHT_ENABLE_PROTOTYPE_FEATURE_FRACTURES)
|
||||
list (APPEND SOURCE_GROUP_SOURCE_FILES
|
||||
${CEE_CURRENT_LIST_DIR}RicExportFractureCompletionsImpl.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RigEclipseToStimPlanCellTransmissibilityCalculator.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RigTransmissibilityCondenser.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RigFractureTransmissibilityEquations.cpp
|
||||
${CEE_CURRENT_LIST_DIR}RigWellPathStimplanIntersector.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../RicCaseAndFileExportSettingsUi.h"
|
||||
#include "RicCaseAndFileExportSettingsUi.h"
|
||||
|
||||
#include "cafPdmField.h"
|
||||
#include "cafAppEnum.h"
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
#include "RifEclipseDataTableFormatter.h"
|
||||
|
||||
#include "RicCaseAndFileExportSettingsUi.h"
|
||||
|
||||
#include "RicWellPathExportCompletionDataFeature.h"
|
||||
|
||||
|
||||
#include "cafCmdFeature.h"
|
||||
|
||||
class RimFishbonesCollection;
|
||||
@@ -0,0 +1,393 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2017 Statoil 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 "RigCompletionData.h"
|
||||
|
||||
#include "RiaLogging.h"
|
||||
|
||||
#include "cvfAssert.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <cmath> // Needed for HUGE_VAL on Linux
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
RigCompletionData::RigCompletionData(const QString wellName, const RigCompletionDataGridCell& cellIndex)
|
||||
: m_wellName(wellName),
|
||||
m_cellIndex(cellIndex),
|
||||
m_saturation(HUGE_VAL),
|
||||
m_transmissibility(HUGE_VAL),
|
||||
m_diameter(HUGE_VAL),
|
||||
m_kh(HUGE_VAL),
|
||||
m_skinFactor(HUGE_VAL),
|
||||
m_dFactor(HUGE_VAL),
|
||||
m_direction(DIR_UNDEF),
|
||||
m_connectionState(OPEN),
|
||||
m_count(1),
|
||||
m_wpimult(HUGE_VAL),
|
||||
m_isMainBore(false),
|
||||
m_readyForExport(false),
|
||||
m_completionType(CT_UNDEFINED)
|
||||
{
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
RigCompletionData::~RigCompletionData()
|
||||
{
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
RigCompletionData::RigCompletionData(const RigCompletionData& other)
|
||||
{
|
||||
copy(*this, other);
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
RigCompletionData RigCompletionData::combine(const std::vector<RigCompletionData>& completions)
|
||||
{
|
||||
CVF_ASSERT(!completions.empty());
|
||||
|
||||
auto it = completions.cbegin();
|
||||
RigCompletionData result(*it);
|
||||
++it;
|
||||
|
||||
for (; it != completions.cend(); ++it)
|
||||
{
|
||||
if (it->completionType() != result.completionType())
|
||||
{
|
||||
RiaLogging::error(QString("Cannot combine completions of different types in same cell [%1, %2, %3]").arg(result.m_cellIndex.localCellIndexI()).arg(result.m_cellIndex.localCellIndexJ()).arg(result.m_cellIndex.localCellIndexK()));
|
||||
continue;
|
||||
}
|
||||
if (onlyOneIsDefaulted(result.m_transmissibility, it->m_transmissibility))
|
||||
{
|
||||
RiaLogging::error("Transmissibility defaulted in one but not both, will produce erroneous result");
|
||||
}
|
||||
else
|
||||
{
|
||||
result.m_transmissibility += it->m_transmissibility;
|
||||
}
|
||||
|
||||
result.m_metadata.reserve(result.m_metadata.size() + it->m_metadata.size());
|
||||
result.m_metadata.insert(result.m_metadata.end(), it->m_metadata.begin(), it->m_metadata.end());
|
||||
|
||||
result.m_count += it->m_count;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
bool RigCompletionData::operator<(const RigCompletionData& other) const
|
||||
{
|
||||
if (m_wellName != other.m_wellName)
|
||||
{
|
||||
return (m_wellName < other.m_wellName);
|
||||
}
|
||||
|
||||
return m_cellIndex < other.m_cellIndex;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
RigCompletionData& RigCompletionData::operator=(const RigCompletionData& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
copy(*this, other);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
void RigCompletionData::setFromFracture(double transmissibility, double skinFactor)
|
||||
{
|
||||
m_completionType = FRACTURE;
|
||||
m_transmissibility = transmissibility;
|
||||
m_skinFactor = skinFactor;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
void RigCompletionData::setTransAndWPImultBackgroundDataFromFishbone(double transmissibility,
|
||||
double skinFactor,
|
||||
double diameter,
|
||||
CellDirection direction,
|
||||
bool isMainBore)
|
||||
{
|
||||
m_completionType = FISHBONES;
|
||||
m_transmissibility = transmissibility;
|
||||
m_skinFactor = skinFactor;
|
||||
m_diameter = diameter;
|
||||
m_direction = direction;
|
||||
m_isMainBore = isMainBore;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
void RigCompletionData::setTransAndWPImultBackgroundDataFromPerforation(double transmissibility,
|
||||
double skinFactor,
|
||||
double diameter,
|
||||
CellDirection direction)
|
||||
{
|
||||
m_completionType = PERFORATION;
|
||||
m_transmissibility = transmissibility;
|
||||
m_skinFactor = skinFactor;
|
||||
m_diameter = diameter;
|
||||
m_direction = direction;
|
||||
m_isMainBore = true;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
void RigCompletionData::setCombinedValuesExplicitTrans(double transmissibility,
|
||||
CompletionType completionType)
|
||||
{
|
||||
m_completionType = completionType;
|
||||
m_transmissibility = transmissibility;
|
||||
m_readyForExport = true;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
void RigCompletionData::setCombinedValuesImplicitTransWPImult(double wpimult,
|
||||
CellDirection celldirection,
|
||||
double skinFactor,
|
||||
double wellDiameter,
|
||||
CompletionType completionType)
|
||||
{
|
||||
m_wpimult = wpimult;
|
||||
m_direction = celldirection;
|
||||
m_completionType = completionType;
|
||||
m_skinFactor = skinFactor;
|
||||
m_diameter = wellDiameter;
|
||||
m_readyForExport = true;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
void RigCompletionData::addMetadata(const QString& name, const QString& comment)
|
||||
{
|
||||
m_metadata.push_back(RigCompletionMetaData(name, comment));
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
bool RigCompletionData::isDefaultValue(double val)
|
||||
{
|
||||
return val == HUGE_VAL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::vector<RigCompletionMetaData>& RigCompletionData::metadata() const
|
||||
{
|
||||
return m_metadata;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const QString& RigCompletionData::wellName() const
|
||||
{
|
||||
return m_wellName;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const RigCompletionDataGridCell& RigCompletionData::completionDataGridCell() const
|
||||
{
|
||||
return m_cellIndex;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
WellConnectionState RigCompletionData::connectionState() const
|
||||
{
|
||||
return m_connectionState;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigCompletionData::saturation() const
|
||||
{
|
||||
return m_saturation;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigCompletionData::transmissibility() const
|
||||
{
|
||||
return m_transmissibility;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigCompletionData::diameter() const
|
||||
{
|
||||
return m_diameter;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigCompletionData::kh() const
|
||||
{
|
||||
return m_kh;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigCompletionData::skinFactor() const
|
||||
{
|
||||
return m_skinFactor;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigCompletionData::dFactor() const
|
||||
{
|
||||
return m_dFactor;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
CellDirection RigCompletionData::direction() const
|
||||
{
|
||||
return m_direction;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RigCompletionData::count() const
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigCompletionData::wpimult() const
|
||||
{
|
||||
return m_wpimult;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigCompletionData::CompletionType RigCompletionData::completionType() const
|
||||
{
|
||||
return m_completionType;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RigCompletionData::isMainBore() const
|
||||
{
|
||||
return m_isMainBore;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RigCompletionData::readyForExport() const
|
||||
{
|
||||
return m_readyForExport;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
bool RigCompletionData::onlyOneIsDefaulted(double first, double second)
|
||||
{
|
||||
if (first == HUGE_VAL)
|
||||
{
|
||||
if (second == HUGE_VAL)
|
||||
{
|
||||
// Both have default values
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// First has default value, second does not
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (second == HUGE_VAL)
|
||||
{
|
||||
// Second has default value, first does not
|
||||
return true;
|
||||
}
|
||||
|
||||
// Neither has default values
|
||||
return false;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
void RigCompletionData::copy(RigCompletionData& target, const RigCompletionData& from)
|
||||
{
|
||||
target.m_metadata = from.m_metadata;
|
||||
target.m_wellName = from.m_wellName;
|
||||
target.m_cellIndex = from.m_cellIndex;
|
||||
target.m_connectionState = from.m_connectionState;
|
||||
target.m_saturation = from.m_saturation;
|
||||
target.m_transmissibility = from.m_transmissibility;
|
||||
target.m_diameter = from.m_diameter;
|
||||
target.m_kh = from.m_kh;
|
||||
target.m_skinFactor = from.m_skinFactor;
|
||||
target.m_dFactor = from.m_dFactor;
|
||||
target.m_direction = from.m_direction;
|
||||
target.m_isMainBore = from.m_isMainBore;
|
||||
target.m_readyForExport = from.m_readyForExport;
|
||||
target.m_count = from.m_count;
|
||||
target.m_wpimult = from.m_wpimult;
|
||||
target.m_completionType = from.m_completionType;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2017 Statoil 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 "RigCompletionDataGridCell.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <vector>
|
||||
|
||||
class RimEclipseCase;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
enum WellConnectionState {
|
||||
OPEN,
|
||||
SHUT,
|
||||
AUTO,
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
enum CellDirection {
|
||||
DIR_I,
|
||||
DIR_J,
|
||||
DIR_K,
|
||||
DIR_UNDEF,
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
struct RigCompletionMetaData {
|
||||
RigCompletionMetaData(const QString& name, const QString& comment) : name(name), comment(comment) {}
|
||||
|
||||
QString name;
|
||||
QString comment;
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RigCompletionData
|
||||
{
|
||||
public:
|
||||
enum CompletionType {
|
||||
FISHBONES,
|
||||
FRACTURE,
|
||||
PERFORATION,
|
||||
CT_UNDEFINED
|
||||
};
|
||||
|
||||
RigCompletionData(const QString wellName, const RigCompletionDataGridCell& cellIndex);
|
||||
~RigCompletionData();
|
||||
RigCompletionData(const RigCompletionData& other);
|
||||
|
||||
static RigCompletionData combine(const std::vector<RigCompletionData>& completions);
|
||||
|
||||
bool operator<(const RigCompletionData& other) const;
|
||||
RigCompletionData& operator=(const RigCompletionData& other);
|
||||
|
||||
void setFromFracture(double transmissibility, double skinFactor);
|
||||
|
||||
void setTransAndWPImultBackgroundDataFromFishbone(double transmissibility,
|
||||
double skinFactor,
|
||||
double diameter,
|
||||
CellDirection direction,
|
||||
bool isMainBore);
|
||||
|
||||
void setTransAndWPImultBackgroundDataFromPerforation(double transmissibility,
|
||||
double skinFactor,
|
||||
double diameter,
|
||||
CellDirection direction);
|
||||
|
||||
void setCombinedValuesExplicitTrans(double transmissibility, CompletionType completionType);
|
||||
|
||||
void setCombinedValuesImplicitTransWPImult(double wpimult,
|
||||
CellDirection celldirection,
|
||||
double skinFactor,
|
||||
double wellDiameter,
|
||||
CompletionType completionType);
|
||||
|
||||
void addMetadata(const QString& name, const QString& comment);
|
||||
static bool isDefaultValue(double val);
|
||||
|
||||
const std::vector<RigCompletionMetaData>& metadata() const;
|
||||
const QString& wellName() const;
|
||||
const RigCompletionDataGridCell& completionDataGridCell() const;
|
||||
WellConnectionState connectionState() const;
|
||||
double saturation() const;
|
||||
double transmissibility() const;
|
||||
double diameter() const; //TODO: should be ft or m
|
||||
double kh() const;
|
||||
double skinFactor() const;
|
||||
double dFactor() const;
|
||||
CellDirection direction() const;
|
||||
size_t count() const;
|
||||
double wpimult() const;
|
||||
CompletionType completionType() const;
|
||||
bool isMainBore() const;
|
||||
bool readyForExport() const;
|
||||
|
||||
std::vector<RigCompletionMetaData> m_metadata;
|
||||
|
||||
private:
|
||||
QString m_wellName;
|
||||
RigCompletionDataGridCell m_cellIndex;
|
||||
WellConnectionState m_connectionState;
|
||||
double m_saturation; //TODO: remove, always use default in Eclipse?
|
||||
double m_transmissibility;
|
||||
double m_diameter;
|
||||
double m_kh; //TODO: Remove, always use default in Eclipse?
|
||||
double m_skinFactor;
|
||||
double m_dFactor; //TODO: Remove, always use default in Eclipse?
|
||||
CellDirection m_direction;
|
||||
|
||||
bool m_isMainBore; //to use mainbore for Eclipse calculation
|
||||
bool m_readyForExport;
|
||||
|
||||
size_t m_count; //TODO: Remove, usage replaced by WPImult
|
||||
double m_wpimult;
|
||||
|
||||
CompletionType m_completionType;
|
||||
|
||||
private:
|
||||
static bool onlyOneIsDefaulted(double first, double second);
|
||||
static void copy(RigCompletionData& target, const RigCompletionData& from);
|
||||
};
|
||||
@@ -0,0 +1,127 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018 Statoil 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 "RigCompletionDataGridCell.h"
|
||||
|
||||
#include "RigMainGrid.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigCompletionDataGridCell::RigCompletionDataGridCell() {}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigCompletionDataGridCell::RigCompletionDataGridCell(size_t globalCellIndex, const RigMainGrid* mainGrid)
|
||||
: m_globalCellIndex(globalCellIndex)
|
||||
{
|
||||
if (mainGrid)
|
||||
{
|
||||
const RigCell& cell = mainGrid->globalCellArray()[globalCellIndex];
|
||||
RigGridBase* grid = cell.hostGrid();
|
||||
if (grid)
|
||||
{
|
||||
size_t gridLocalCellIndex = cell.gridLocalCellIndex();
|
||||
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
size_t k = 0;
|
||||
grid->ijkFromCellIndex(gridLocalCellIndex, &i, &j, &k);
|
||||
|
||||
m_localCellIndexI = i;
|
||||
m_localCellIndexJ = j;
|
||||
m_localCellIndexK = k;
|
||||
|
||||
if (grid != mainGrid)
|
||||
{
|
||||
m_lgrName = QString::fromStdString(grid->gridName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RigCompletionDataGridCell::operator==(const RigCompletionDataGridCell& other) const
|
||||
{
|
||||
return m_globalCellIndex == other.m_globalCellIndex;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RigCompletionDataGridCell::operator<(const RigCompletionDataGridCell& other) const
|
||||
{
|
||||
if (m_localCellIndexI != other.m_localCellIndexI) return m_localCellIndexI < other.m_localCellIndexI;
|
||||
if (m_localCellIndexJ != other.m_localCellIndexJ) return m_localCellIndexJ < other.m_localCellIndexJ;
|
||||
if (m_localCellIndexK != other.m_localCellIndexK) return m_localCellIndexK < other.m_localCellIndexK;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RigCompletionDataGridCell::globalCellIndex() const
|
||||
{
|
||||
return m_globalCellIndex;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RigCompletionDataGridCell::localCellIndexI() const
|
||||
{
|
||||
return m_localCellIndexI;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RigCompletionDataGridCell::localCellIndexJ() const
|
||||
{
|
||||
return m_localCellIndexJ;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RigCompletionDataGridCell::localCellIndexK() const
|
||||
{
|
||||
return m_localCellIndexK;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RigCompletionDataGridCell::oneBasedLocalCellIndexString() const
|
||||
{
|
||||
QString text = QString("[%1, %2, %3]").arg(m_localCellIndexI + 1).arg(m_localCellIndexJ + 1).arg(m_localCellIndexK + 1);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RigCompletionDataGridCell::lgrName() const
|
||||
{
|
||||
return m_lgrName;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018 Statoil 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 <QString>
|
||||
|
||||
class RigMainGrid;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RigCompletionDataGridCell
|
||||
{
|
||||
public:
|
||||
RigCompletionDataGridCell();
|
||||
|
||||
RigCompletionDataGridCell(size_t globalCellIndex, const RigMainGrid* mainGrid);
|
||||
|
||||
bool operator==(const RigCompletionDataGridCell& other) const;
|
||||
|
||||
bool operator<(const RigCompletionDataGridCell& other) const;
|
||||
|
||||
size_t globalCellIndex() const;
|
||||
|
||||
size_t localCellIndexI() const;
|
||||
size_t localCellIndexJ() const;
|
||||
size_t localCellIndexK() const;
|
||||
|
||||
QString oneBasedLocalCellIndexString() const;
|
||||
|
||||
QString lgrName() const;
|
||||
|
||||
private:
|
||||
size_t m_globalCellIndex;
|
||||
QString m_lgrName;
|
||||
|
||||
size_t m_localCellIndexI;
|
||||
size_t m_localCellIndexJ;
|
||||
size_t m_localCellIndexK;
|
||||
};
|
||||
@@ -0,0 +1,247 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2017 Statoil 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 "RigEclipseToStimPlanCellTransmissibilityCalculator.h"
|
||||
|
||||
#include "RigActiveCellInfo.h"
|
||||
#include "RigCaseCellResultsData.h"
|
||||
#include "RigCellGeometryTools.h"
|
||||
#include "RigEclipseCaseData.h"
|
||||
#include "RigFractureCell.h"
|
||||
#include "RigFractureTransmissibilityEquations.h"
|
||||
#include "RigMainGrid.h"
|
||||
#include "RigResultAccessorFactory.h"
|
||||
#include "RigHexIntersectionTools.h"
|
||||
|
||||
#include "RimEclipseCase.h"
|
||||
|
||||
#include "cvfGeometryTools.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigEclipseToStimPlanCellTransmissibilityCalculator::RigEclipseToStimPlanCellTransmissibilityCalculator(RimEclipseCase* caseToApply,
|
||||
cvf::Mat4d fractureTransform,
|
||||
double skinFactor,
|
||||
double cDarcy,
|
||||
const RigFractureCell& stimPlanCell)
|
||||
: m_case(caseToApply),
|
||||
m_fractureTransform(fractureTransform),
|
||||
m_fractureSkinFactor(skinFactor),
|
||||
m_cDarcy(cDarcy),
|
||||
m_stimPlanCell(stimPlanCell)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::vector<size_t>& RigEclipseToStimPlanCellTransmissibilityCalculator::globalIndeciesToContributingEclipseCells()
|
||||
{
|
||||
if (m_globalIndeciesToContributingEclipseCells.size() < 1)
|
||||
{
|
||||
calculateStimPlanCellsMatrixTransmissibility();
|
||||
}
|
||||
|
||||
return m_globalIndeciesToContributingEclipseCells;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::vector<double>& RigEclipseToStimPlanCellTransmissibilityCalculator::contributingEclipseCellTransmissibilities()
|
||||
{
|
||||
if (m_globalIndeciesToContributingEclipseCells.size() < 1)
|
||||
{
|
||||
calculateStimPlanCellsMatrixTransmissibility();
|
||||
}
|
||||
|
||||
return m_contributingEclipseCellTransmissibilities;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigEclipseToStimPlanCellTransmissibilityCalculator::calculateStimPlanCellsMatrixTransmissibility()
|
||||
{
|
||||
// Not calculating flow into fracture if stimPlan cell cond value is 0 (assumed to be outside the fracture):
|
||||
if (m_stimPlanCell.getConductivtyValue() < 1e-7) return;
|
||||
|
||||
const RigEclipseCaseData* eclipseCaseData = m_case->eclipseCaseData();
|
||||
|
||||
RiaDefines::PorosityModelType porosityModel = RiaDefines::MATRIX_MODEL;
|
||||
|
||||
cvf::ref<RigResultAccessor> dataAccessObjectDx = loadResultAndCreateResultAccessor(m_case, porosityModel, "DX");
|
||||
cvf::ref<RigResultAccessor> dataAccessObjectDy = loadResultAndCreateResultAccessor(m_case, porosityModel, "DY");
|
||||
cvf::ref<RigResultAccessor> dataAccessObjectDz = loadResultAndCreateResultAccessor(m_case, porosityModel, "DZ");
|
||||
cvf::ref<RigResultAccessor> dataAccessObjectPermX = loadResultAndCreateResultAccessor(m_case, porosityModel, "PERMX");
|
||||
cvf::ref<RigResultAccessor> dataAccessObjectPermY = loadResultAndCreateResultAccessor(m_case, porosityModel, "PERMY");
|
||||
cvf::ref<RigResultAccessor> dataAccessObjectPermZ = loadResultAndCreateResultAccessor(m_case, porosityModel, "PERMZ");
|
||||
cvf::ref<RigResultAccessor> dataAccessObjectNTG = loadResultAndCreateResultAccessor(m_case, porosityModel, "NTG");
|
||||
|
||||
const RigActiveCellInfo* activeCellInfo = eclipseCaseData->activeCellInfo(porosityModel);
|
||||
|
||||
std::vector<cvf::Vec3d> stimPlanPolygonTransformed;
|
||||
for (cvf::Vec3d v : m_stimPlanCell.getPolygon())
|
||||
{
|
||||
v.transformPoint(m_fractureTransform);
|
||||
stimPlanPolygonTransformed.push_back(v);
|
||||
}
|
||||
|
||||
std::vector<size_t> fracCells = getPotentiallyFracturedCellsForPolygon(stimPlanPolygonTransformed);
|
||||
for (size_t fracCell : fracCells)
|
||||
{
|
||||
bool cellIsActive = activeCellInfo->isActive(fracCell);
|
||||
if (!cellIsActive) continue;
|
||||
|
||||
double permX = dataAccessObjectPermX->cellScalarGlobIdx(fracCell);
|
||||
double permY = dataAccessObjectPermY->cellScalarGlobIdx(fracCell);
|
||||
double permZ = dataAccessObjectPermZ->cellScalarGlobIdx(fracCell);
|
||||
|
||||
double dx = dataAccessObjectDx->cellScalarGlobIdx(fracCell);
|
||||
double dy = dataAccessObjectDy->cellScalarGlobIdx(fracCell);
|
||||
double dz = dataAccessObjectDz->cellScalarGlobIdx(fracCell);
|
||||
|
||||
double NTG = 1.0;
|
||||
if (dataAccessObjectNTG.notNull())
|
||||
{
|
||||
NTG = dataAccessObjectNTG->cellScalarGlobIdx(fracCell);
|
||||
}
|
||||
|
||||
const RigMainGrid* mainGrid = m_case->eclipseCaseData()->mainGrid();
|
||||
std::array<cvf::Vec3d, 8> hexCorners;
|
||||
mainGrid->cellCornerVertices(fracCell, hexCorners.data());
|
||||
|
||||
std::vector<std::vector<cvf::Vec3d> > planeCellPolygons;
|
||||
bool isPlanIntersected = RigHexIntersectionTools::planeHexIntersectionPolygons(hexCorners, m_fractureTransform, planeCellPolygons);
|
||||
if (!isPlanIntersected || planeCellPolygons.size() == 0) continue;
|
||||
|
||||
cvf::Vec3d localX;
|
||||
cvf::Vec3d localY;
|
||||
cvf::Vec3d localZ;
|
||||
RigCellGeometryTools::findCellLocalXYZ(hexCorners, localX, localY, localZ);
|
||||
|
||||
//Transform planCell polygon(s) and averageZdirection to x/y coordinate system (where fracturePolygon already is located)
|
||||
cvf::Mat4d invertedTransMatrix = m_fractureTransform.getInverted();
|
||||
for (std::vector<cvf::Vec3d> & planeCellPolygon : planeCellPolygons)
|
||||
{
|
||||
for (cvf::Vec3d& v : planeCellPolygon)
|
||||
{
|
||||
v.transformPoint(invertedTransMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<cvf::Vec3d> > polygonsForStimPlanCellInEclipseCell;
|
||||
cvf::Vec3d areaVector;
|
||||
std::vector<cvf::Vec3d> stimPlanPolygon = m_stimPlanCell.getPolygon();
|
||||
|
||||
for (std::vector<cvf::Vec3d> planeCellPolygon : planeCellPolygons)
|
||||
{
|
||||
std::vector<std::vector<cvf::Vec3d> >clippedPolygons = RigCellGeometryTools::intersectPolygons(planeCellPolygon, stimPlanPolygon);
|
||||
for (std::vector<cvf::Vec3d> clippedPolygon : clippedPolygons)
|
||||
{
|
||||
polygonsForStimPlanCellInEclipseCell.push_back(clippedPolygon);
|
||||
}
|
||||
}
|
||||
|
||||
if (polygonsForStimPlanCellInEclipseCell.size() == 0) continue;
|
||||
|
||||
double area;
|
||||
std::vector<double> areaOfFractureParts;
|
||||
double length;
|
||||
std::vector<double> lengthXareaOfFractureParts;
|
||||
double Ax = 0.0, Ay = 0.0, Az = 0.0;
|
||||
|
||||
for (std::vector<cvf::Vec3d> fracturePartPolygon : polygonsForStimPlanCellInEclipseCell)
|
||||
{
|
||||
areaVector = cvf::GeometryTools::polygonAreaNormal3D(fracturePartPolygon);
|
||||
area = areaVector.length();
|
||||
areaOfFractureParts.push_back(area);
|
||||
|
||||
length = RigCellGeometryTools::polygonLengthInLocalXdirWeightedByArea(fracturePartPolygon);
|
||||
lengthXareaOfFractureParts.push_back(length * area);
|
||||
|
||||
cvf::Plane fracturePlane;
|
||||
fracturePlane.setFromPointAndNormal(static_cast<cvf::Vec3d>(m_fractureTransform.translation()),
|
||||
static_cast<cvf::Vec3d>(m_fractureTransform.col(2)));
|
||||
|
||||
Ax += fabs(area*(fracturePlane.normal().dot(localY)));
|
||||
Ay += fabs(area*(fracturePlane.normal().dot(localX)));
|
||||
Az += fabs(area*(fracturePlane.normal().dot(localZ)));
|
||||
}
|
||||
|
||||
double fractureArea = 0.0;
|
||||
for (double area : areaOfFractureParts) fractureArea += area;
|
||||
|
||||
double totalAreaXLength = 0.0;
|
||||
for (double lengtXarea : lengthXareaOfFractureParts) totalAreaXLength += lengtXarea;
|
||||
|
||||
double fractureAreaWeightedlength = totalAreaXLength / fractureArea;
|
||||
|
||||
double transmissibility_X = RigFractureTransmissibilityEquations::matrixToFractureTrans(permY, NTG, Ay, dx, m_fractureSkinFactor, fractureAreaWeightedlength, m_cDarcy);
|
||||
double transmissibility_Y = RigFractureTransmissibilityEquations::matrixToFractureTrans(permX, NTG, Ax, dy, m_fractureSkinFactor, fractureAreaWeightedlength, m_cDarcy);
|
||||
double transmissibility_Z = RigFractureTransmissibilityEquations::matrixToFractureTrans(permZ, 1.0, Az, dz, m_fractureSkinFactor, fractureAreaWeightedlength, m_cDarcy);
|
||||
|
||||
double transmissibility = sqrt(transmissibility_X * transmissibility_X
|
||||
+ transmissibility_Y * transmissibility_Y
|
||||
+ transmissibility_Z * transmissibility_Z);
|
||||
|
||||
|
||||
m_globalIndeciesToContributingEclipseCells.push_back(fracCell);
|
||||
m_contributingEclipseCellTransmissibilities.push_back(transmissibility);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<size_t> RigEclipseToStimPlanCellTransmissibilityCalculator::getPotentiallyFracturedCellsForPolygon(std::vector<cvf::Vec3d> polygon)
|
||||
{
|
||||
std::vector<size_t> cellIndices;
|
||||
|
||||
const RigMainGrid* mainGrid = m_case->eclipseCaseData()->mainGrid();
|
||||
if (!mainGrid) return cellIndices;
|
||||
|
||||
cvf::BoundingBox polygonBBox;
|
||||
for (cvf::Vec3d nodeCoord : polygon) polygonBBox.add(nodeCoord);
|
||||
|
||||
mainGrid->findIntersectingCells(polygonBBox, &cellIndices);
|
||||
|
||||
return cellIndices;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::ref<RigResultAccessor> RigEclipseToStimPlanCellTransmissibilityCalculator::loadResultAndCreateResultAccessor(
|
||||
RimEclipseCase* eclipseCase,
|
||||
RiaDefines::PorosityModelType porosityModel,
|
||||
const QString& uiResultName)
|
||||
{
|
||||
CVF_ASSERT(eclipseCase);
|
||||
|
||||
RigCaseCellResultsData* gridCellResults = eclipseCase->results(porosityModel);
|
||||
|
||||
// Calling this function will force loading of result from file
|
||||
gridCellResults->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, uiResultName);
|
||||
|
||||
const RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData();
|
||||
|
||||
// Create result accessor object for main grid at time step zero (static result date is always at first time step
|
||||
return RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, porosityModel, 0, uiResultName);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2017 Statoil 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 "RiaPorosityModel.h"
|
||||
|
||||
#include "cvfBase.h"
|
||||
#include "cvfObject.h"
|
||||
#include "cvfMatrix4.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class QString;
|
||||
|
||||
class RimEclipseCase;
|
||||
class RigFractureCell;
|
||||
class RigEclipseCaseData;
|
||||
class RigResultAccessor;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
|
||||
class RigEclipseToStimPlanCellTransmissibilityCalculator
|
||||
{
|
||||
public:
|
||||
explicit RigEclipseToStimPlanCellTransmissibilityCalculator(RimEclipseCase* caseToApply,
|
||||
cvf::Mat4d fractureTransform,
|
||||
double skinFactor,
|
||||
double cDarcy,
|
||||
const RigFractureCell& stimPlanCell);
|
||||
|
||||
const std::vector<size_t>& globalIndeciesToContributingEclipseCells();
|
||||
const std::vector<double>& contributingEclipseCellTransmissibilities();
|
||||
|
||||
private:
|
||||
void calculateStimPlanCellsMatrixTransmissibility();
|
||||
std::vector<size_t> getPotentiallyFracturedCellsForPolygon(std::vector<cvf::Vec3d> polygon);
|
||||
|
||||
static cvf::ref<RigResultAccessor>
|
||||
loadResultAndCreateResultAccessor(RimEclipseCase* eclipseCase,
|
||||
RiaDefines::PorosityModelType porosityModel,
|
||||
const QString& uiResultName);
|
||||
|
||||
private:
|
||||
RimEclipseCase* m_case;
|
||||
double m_cDarcy;
|
||||
double m_fractureSkinFactor;
|
||||
cvf::Mat4d m_fractureTransform;
|
||||
const RigFractureCell& m_stimPlanCell;
|
||||
|
||||
std::vector<size_t> m_globalIndeciesToContributingEclipseCells;
|
||||
std::vector<double> m_contributingEclipseCellTransmissibilities;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2017- Statoil 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 "RigFractureTransmissibilityEquations.h"
|
||||
#include "cvfBase.h"
|
||||
#include "cvfMath.h"
|
||||
#include <cmath>
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigFractureTransmissibilityEquations::centerToEdgeFractureCellTrans(double conductivity,
|
||||
double sideLengthParallellTrans,
|
||||
double sideLengthNormalTrans,
|
||||
double cDarcyForRelevantUnit)
|
||||
{
|
||||
double transmissibility = cDarcyForRelevantUnit * conductivity * sideLengthNormalTrans / (sideLengthParallellTrans / 2);
|
||||
return transmissibility;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigFractureTransmissibilityEquations::centerToCenterFractureCellTrans(double conductivityCell1,
|
||||
double sideLengthParallellTransCell1,
|
||||
double sideLengthNormalTransCell1,
|
||||
double conductivityCell2,
|
||||
double sideLengthParallellTransCell2,
|
||||
double sideLengthNormalTransCell2,
|
||||
double cDarcyForRelevantUnit)
|
||||
{
|
||||
double transCell1 = centerToEdgeFractureCellTrans(conductivityCell1, sideLengthParallellTransCell1, sideLengthNormalTransCell1, cDarcyForRelevantUnit);
|
||||
double transCell2 = centerToEdgeFractureCellTrans(conductivityCell2, sideLengthParallellTransCell2, sideLengthNormalTransCell2, cDarcyForRelevantUnit);
|
||||
|
||||
double totalTrans = 1 / ( (1 / transCell1) + (1 / transCell2));
|
||||
|
||||
return totalTrans;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigFractureTransmissibilityEquations::fractureCellToWellRadialTrans(double fractureCellConductivity,
|
||||
double fractureCellSizeX,
|
||||
double fractureCellSizeZ,
|
||||
double wellRadius,
|
||||
double skinFactor,
|
||||
double cDarcyForRelevantUnit)
|
||||
{
|
||||
double ro = 0.14 * cvf::Math::sqrt(
|
||||
pow(fractureCellSizeX, 2.0) + pow(fractureCellSizeZ, 2));
|
||||
|
||||
if (ro < (wellRadius * 1.01))
|
||||
{
|
||||
ro = wellRadius * 1.01;
|
||||
}
|
||||
|
||||
double Tc = 2 * cvf::PI_D * cDarcyForRelevantUnit * fractureCellConductivity /
|
||||
(log(ro / wellRadius) + skinFactor );
|
||||
|
||||
CVF_TIGHT_ASSERT(Tc > 0);
|
||||
return Tc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigFractureTransmissibilityEquations::fractureCellToWellLinearTrans(double fractureCellConductivity,
|
||||
double fractureCellSizeX,
|
||||
double fractureCellSizeZ,
|
||||
double perforationLengthVertical,
|
||||
double perforationLengthHorizontal,
|
||||
double perforationEfficiency,
|
||||
double skinfactor,
|
||||
double cDarcyForRelevantUnit)
|
||||
{
|
||||
double TcPrefix = 8 * cDarcyForRelevantUnit * fractureCellConductivity;
|
||||
|
||||
double DzPerf = perforationLengthVertical * perforationEfficiency;
|
||||
double DxPerf = perforationLengthHorizontal * perforationEfficiency;
|
||||
|
||||
double TcZ = TcPrefix * DzPerf /
|
||||
(fractureCellSizeX + skinfactor * DzPerf / cvf::PI_D);
|
||||
|
||||
double TcX = TcPrefix * DxPerf /
|
||||
(fractureCellSizeZ + skinfactor* DxPerf / cvf::PI_D);
|
||||
|
||||
double Tc = cvf::Math::sqrt(pow(TcX, 2) + pow(TcZ, 2));
|
||||
return Tc;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigFractureTransmissibilityEquations::matrixToFractureTrans(double perm,
|
||||
double NTG,
|
||||
double A,
|
||||
double cellSizeLength,
|
||||
double skinfactor,
|
||||
double fractureAreaWeightedlength,
|
||||
double cDarcy)
|
||||
{
|
||||
double transmissibility;
|
||||
|
||||
double slDivPi = 0.0;
|
||||
if ( cvf::Math::abs(skinfactor) > 1e-9)
|
||||
{
|
||||
slDivPi = (skinfactor * fractureAreaWeightedlength) / cvf::PI_D;
|
||||
}
|
||||
|
||||
transmissibility = 8 * cDarcy * (perm * NTG) * A / (cellSizeLength + slDivPi);
|
||||
|
||||
CVF_ASSERT(transmissibility == transmissibility);
|
||||
return transmissibility;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2017- Statoil 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
|
||||
|
||||
|
||||
class RigFractureTransmissibilityEquations
|
||||
{
|
||||
public:
|
||||
static double centerToEdgeFractureCellTrans(double conductivity,
|
||||
double sideLengthParallellTrans,
|
||||
double sideLengthNormalTrans,
|
||||
double cDarcyForRelevantUnit);
|
||||
|
||||
static double centerToCenterFractureCellTrans(double conductivityCell1,
|
||||
double sideLengthParallellTransCell1,
|
||||
double sideLengthNormalTransCell1,
|
||||
double conductivityCell2,
|
||||
double sideLengthParallellTransCell2,
|
||||
double sideLengthNormalTransCell2,
|
||||
double cDarcyForRelevantUnit);
|
||||
|
||||
static double fractureCellToWellRadialTrans(double fractureCellConductivity,
|
||||
double fractureCellSizeX,
|
||||
double fractureCellSizeZ,
|
||||
double wellRadius,
|
||||
double skinFactor,
|
||||
double cDarcyForRelevantUnit);
|
||||
|
||||
static double fractureCellToWellLinearTrans(double fractureConductivity,
|
||||
double fractureCellSizeX,
|
||||
double fractureCellSizeZ,
|
||||
double perforationLengthVertical,
|
||||
double perforationLengthHorizontal,
|
||||
double perforationEfficiency,
|
||||
double skinfactor,
|
||||
double cDarcyForRelevantUnit);
|
||||
|
||||
static double matrixToFractureTrans(double permX,
|
||||
double NTG,
|
||||
double Ay,
|
||||
double dx,
|
||||
double skinfactor,
|
||||
double fractureAreaWeightedlength,
|
||||
double cDarcy);
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2017 - Statoil 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 "RigTransmissibilityCondenser.h"
|
||||
|
||||
#include "RiaLogging.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/LU>
|
||||
#include <iomanip>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigTransmissibilityCondenser::addNeighborTransmissibility(CellAddress cell1, CellAddress cell2, double transmissibility)
|
||||
{
|
||||
if (transmissibility < 1e-9) return;
|
||||
|
||||
m_condensedTransmissibilities.clear();
|
||||
m_externalCellAddrSet.clear();
|
||||
if ( cell1 < cell2 )
|
||||
m_neighborTransmissibilities[cell1][cell2] += transmissibility;
|
||||
else
|
||||
m_neighborTransmissibilities[cell2][cell1] += transmissibility;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<RigTransmissibilityCondenser::CellAddress> RigTransmissibilityCondenser::externalCells()
|
||||
{
|
||||
calculateCondensedTransmissibilitiesIfNeeded();
|
||||
|
||||
return m_externalCellAddrSet;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigTransmissibilityCondenser::condensedTransmissibility(CellAddress externalCell1, CellAddress externalCell2)
|
||||
{
|
||||
CAF_ASSERT(!(externalCell1 == externalCell2));
|
||||
|
||||
calculateCondensedTransmissibilitiesIfNeeded();
|
||||
|
||||
if ( externalCell2 < externalCell1 ) std::swap(externalCell1, externalCell2);
|
||||
|
||||
const auto& adrToAdrTransMapPair = m_condensedTransmissibilities.find(externalCell1);
|
||||
if ( adrToAdrTransMapPair != m_condensedTransmissibilities.end() )
|
||||
{
|
||||
const auto& adrTransPair = adrToAdrTransMapPair->second.find(externalCell2);
|
||||
if ( adrTransPair != adrToAdrTransMapPair->second.end() )
|
||||
{
|
||||
return adrTransPair->second;
|
||||
}
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigTransmissibilityCondenser::calculateCondensedTransmissibilitiesIfNeeded()
|
||||
{
|
||||
if (m_condensedTransmissibilities.size()) return;
|
||||
|
||||
// Find all equations, and their total ordering
|
||||
|
||||
union
|
||||
{
|
||||
int idxToFirstExternalEquation;
|
||||
int internalEquationCount;
|
||||
};
|
||||
idxToFirstExternalEquation = -1;
|
||||
int totalEquationCount = -1;
|
||||
|
||||
std::map<CellAddress, int> cellAddressToEqIdxMap;
|
||||
std::vector<CellAddress> eqIdxToCellAddressMapping;
|
||||
{
|
||||
for ( const auto& adrEqIdxPair : m_neighborTransmissibilities )
|
||||
{
|
||||
cellAddressToEqIdxMap.insert({ adrEqIdxPair.first, -1 });
|
||||
for ( const auto& adrTranspair : adrEqIdxPair.second )
|
||||
{
|
||||
cellAddressToEqIdxMap.insert({ adrTranspair.first, -1 });
|
||||
}
|
||||
}
|
||||
|
||||
int currentEqIdx = 0;
|
||||
|
||||
for ( auto& adrEqIdxPair : cellAddressToEqIdxMap)
|
||||
{
|
||||
adrEqIdxPair.second = currentEqIdx;
|
||||
eqIdxToCellAddressMapping.push_back(adrEqIdxPair.first);
|
||||
|
||||
if ( idxToFirstExternalEquation == -1 && adrEqIdxPair.first.m_isExternal )
|
||||
{
|
||||
idxToFirstExternalEquation = currentEqIdx;
|
||||
}
|
||||
++currentEqIdx;
|
||||
}
|
||||
totalEquationCount = currentEqIdx;
|
||||
}
|
||||
|
||||
CAF_ASSERT(idxToFirstExternalEquation != -1);
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
MatrixXd totalSystem = MatrixXd::Zero(totalEquationCount, totalEquationCount);
|
||||
|
||||
for (const auto& adrToAdrTransMapPair : m_neighborTransmissibilities)
|
||||
{
|
||||
CAF_ASSERT(cellAddressToEqIdxMap.count(adrToAdrTransMapPair.first)); // Remove when stabilized
|
||||
int c1EquationIdx = cellAddressToEqIdxMap[adrToAdrTransMapPair.first];
|
||||
for (const auto& adrTranspair : adrToAdrTransMapPair.second)
|
||||
{
|
||||
CAF_ASSERT(cellAddressToEqIdxMap.count(adrTranspair.first)); // Remove when stabilized
|
||||
|
||||
int c2EquationIdx = cellAddressToEqIdxMap[adrTranspair.first];
|
||||
|
||||
totalSystem(c1EquationIdx, c2EquationIdx) += adrTranspair.second;
|
||||
totalSystem(c2EquationIdx, c1EquationIdx) += adrTranspair.second;
|
||||
totalSystem(c1EquationIdx, c1EquationIdx) -= adrTranspair.second;
|
||||
totalSystem(c2EquationIdx, c2EquationIdx) -= adrTranspair.second;
|
||||
}
|
||||
|
||||
++c1EquationIdx;
|
||||
}
|
||||
|
||||
// std::cout << "T = " << std::endl << totalSystem << std::endl;
|
||||
|
||||
int externalEquationCount = totalEquationCount - internalEquationCount;
|
||||
MatrixXd condensedSystem = totalSystem.bottomRightCorner(externalEquationCount, externalEquationCount)
|
||||
- totalSystem.bottomLeftCorner(externalEquationCount, internalEquationCount)
|
||||
* totalSystem.topLeftCorner(internalEquationCount, internalEquationCount).inverse()
|
||||
* totalSystem.topRightCorner(internalEquationCount, externalEquationCount );
|
||||
|
||||
// std::cout << "Te = " << std::endl << condensedSystem << std::endl << std::endl;
|
||||
|
||||
for (int exEqIdx = 0; exEqIdx < externalEquationCount; ++exEqIdx)
|
||||
{
|
||||
for (int exColIdx = exEqIdx +1; exColIdx < externalEquationCount; ++exColIdx)
|
||||
{
|
||||
double T = condensedSystem(exEqIdx, exColIdx);
|
||||
//if (T != 0.0)
|
||||
{
|
||||
CellAddress cell1 = eqIdxToCellAddressMapping[exEqIdx + internalEquationCount];
|
||||
CellAddress cell2 = eqIdxToCellAddressMapping[exColIdx + internalEquationCount];
|
||||
if (cell1 < cell2) m_condensedTransmissibilities[cell1][cell2] = T;
|
||||
else m_condensedTransmissibilities[cell2][cell1] = T;
|
||||
|
||||
m_externalCellAddrSet.insert(cell1);
|
||||
m_externalCellAddrSet.insert(cell2);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "RimStimPlanFractureTemplate.h"
|
||||
#include "RigMainGrid.h"
|
||||
#include "RigFractureCell.h"
|
||||
|
||||
void printCellAddress(std::stringstream& str,
|
||||
const RigMainGrid* mainGrid,
|
||||
const RigFractureGrid* fractureGrid,
|
||||
RigTransmissibilityCondenser::CellAddress cellAddr)
|
||||
{
|
||||
using CellAddress = RigTransmissibilityCondenser::CellAddress;
|
||||
|
||||
str << (cellAddr.m_isExternal ? "E " : "I ");
|
||||
|
||||
switch (cellAddr.m_cellIndexSpace) {
|
||||
case CellAddress::ECLIPSE:
|
||||
{
|
||||
if (cellAddr.m_globalCellIdx > mainGrid->cellCount())
|
||||
{
|
||||
str << "ECL - LGR CELL ";
|
||||
}
|
||||
else
|
||||
{
|
||||
str << "ECL ";
|
||||
size_t i, j, k;
|
||||
mainGrid->ijkFromCellIndex(cellAddr.m_globalCellIdx, &i, &j, &k);
|
||||
str << std::setw(5) << i+1 << std::setw(5) << j+1 << std::setw(5) << k+1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CellAddress::STIMPLAN:
|
||||
{
|
||||
str << "STP ";
|
||||
const RigFractureCell& stpCell = fractureGrid->cellFromIndex(cellAddr.m_globalCellIdx);
|
||||
str << std::setw(5) << stpCell.getI()+1 << std::setw(5) << stpCell.getJ()+1 << std::setw(5) << " ";
|
||||
}
|
||||
break;
|
||||
|
||||
case CellAddress::WELL:
|
||||
{
|
||||
str << "WEL ";
|
||||
str << std::setw(5) << cellAddr.m_globalCellIdx << std::setw(5) << " " << std::setw(5) << " ";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
str << " ";
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::string RigTransmissibilityCondenser::neighborTransDebugOutput(const RigMainGrid* mainGrid, const RigFractureGrid* fractureGrid)
|
||||
{
|
||||
std::stringstream debugText;
|
||||
for ( const auto& adrEqIdxPair : m_neighborTransmissibilities )
|
||||
{
|
||||
for (const auto& adrTransPair :adrEqIdxPair.second)
|
||||
{
|
||||
debugText << "-- ";
|
||||
printCellAddress(debugText, mainGrid, fractureGrid, adrEqIdxPair.first);
|
||||
printCellAddress(debugText, mainGrid, fractureGrid, adrTransPair.first);
|
||||
|
||||
debugText << " Trans: " << std::setprecision(10) << std::fixed << adrTransPair.second;
|
||||
debugText << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return debugText.str();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::string RigTransmissibilityCondenser::condensedTransDebugOutput(const RigMainGrid* mainGrid, const RigFractureGrid* fractureGrid)
|
||||
{
|
||||
std::stringstream debugText;
|
||||
for ( const auto& adrEqIdxPair : m_condensedTransmissibilities )
|
||||
{
|
||||
for (const auto& adrTransPair :adrEqIdxPair.second)
|
||||
{
|
||||
debugText << "-- ";
|
||||
printCellAddress(debugText, mainGrid, fractureGrid, adrEqIdxPair.first);
|
||||
printCellAddress(debugText, mainGrid, fractureGrid, adrTransPair.first);
|
||||
|
||||
debugText << " Trans: " << std::setprecision(10) << std::fixed << adrTransPair.second;
|
||||
debugText << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return debugText.str();
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2017 - Statoil 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 "cafAssert.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
class RigMainGrid;
|
||||
class RimStimPlanFractureTemplate;
|
||||
class RigFractureGrid;
|
||||
|
||||
class RigTransmissibilityCondenser
|
||||
{
|
||||
public:
|
||||
class CellAddress
|
||||
{
|
||||
public:
|
||||
enum CellIndexSpace { ECLIPSE, STIMPLAN, WELL};
|
||||
|
||||
CellAddress(): m_isExternal(false),
|
||||
m_cellIndexSpace(STIMPLAN),
|
||||
m_globalCellIdx(-1)
|
||||
{}
|
||||
CellAddress(bool isExternal,
|
||||
CellIndexSpace cellType,
|
||||
size_t globalCellIdx)
|
||||
: m_isExternal(isExternal),
|
||||
m_cellIndexSpace(cellType),
|
||||
m_globalCellIdx(globalCellIdx)
|
||||
{}
|
||||
|
||||
bool m_isExternal;
|
||||
CellIndexSpace m_cellIndexSpace;
|
||||
size_t m_globalCellIdx;
|
||||
|
||||
|
||||
bool operator==(const CellAddress& o)
|
||||
{
|
||||
return (m_isExternal == o.m_isExternal) && (m_cellIndexSpace == o.m_cellIndexSpace) && (m_globalCellIdx == o.m_globalCellIdx);
|
||||
}
|
||||
|
||||
// Ordering external after internal is important for the matrix order internally
|
||||
|
||||
bool operator<(const CellAddress& other) const
|
||||
{
|
||||
if (m_isExternal != other.m_isExternal) return !m_isExternal; // Internal cells < External cells
|
||||
if (m_cellIndexSpace != other.m_cellIndexSpace)return m_cellIndexSpace < other.m_cellIndexSpace; // Eclipse < StimPlan
|
||||
if (m_globalCellIdx != other.m_globalCellIdx) return m_globalCellIdx < other.m_globalCellIdx;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void addNeighborTransmissibility(CellAddress cell1, CellAddress cell2, double transmissibility);
|
||||
|
||||
std::set<CellAddress> externalCells();
|
||||
|
||||
double condensedTransmissibility( CellAddress externalCell1, CellAddress externalCell2);
|
||||
|
||||
std::string neighborTransDebugOutput(const RigMainGrid* mainGrid, const RigFractureGrid* fractureGrid);
|
||||
std::string condensedTransDebugOutput(const RigMainGrid* mainGrid, const RigFractureGrid* fractureGrid);
|
||||
|
||||
private:
|
||||
void calculateCondensedTransmissibilitiesIfNeeded();
|
||||
|
||||
std::map<CellAddress, std::map<CellAddress, double> > m_neighborTransmissibilities;
|
||||
std::map<CellAddress, std::map<CellAddress, double> > m_condensedTransmissibilities;
|
||||
std::set<CellAddress> m_externalCellAddrSet;
|
||||
};
|
||||
@@ -0,0 +1,226 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2017- Statoil 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 "RigWellPathStimplanIntersector.h"
|
||||
|
||||
#include "RigCellGeometryTools.h"
|
||||
#include "RigFractureCell.h"
|
||||
#include "RigFractureGrid.h"
|
||||
#include "RigWellPath.h"
|
||||
|
||||
#include "RimFracture.h"
|
||||
#include "RimFractureTemplate.h"
|
||||
#include "RimSimWellFracture.h"
|
||||
#include "RimStimPlanFractureTemplate.h"
|
||||
|
||||
#include "cvfBase.h"
|
||||
#include "cvfMath.h"
|
||||
#include "cvfMatrix4.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigWellPathStimplanIntersector::RigWellPathStimplanIntersector(const RigWellPath* wellpathGeom, const RimFracture* rimFracture)
|
||||
{
|
||||
std::vector<cvf::Vec3d> wellPathPoints = wellpathGeom->wellPathPointsIncludingInterpolatedIntersectionPoint(rimFracture->fractureMD());
|
||||
cvf::Mat4d fractureXf = rimFracture->transformMatrix();
|
||||
double wellRadius = rimFracture->wellRadius(rimFracture->fractureUnit());
|
||||
std::vector<std::vector<cvf::Vec3d> > stpCellPolygons;
|
||||
{
|
||||
RimFractureTemplate* fractureTemplate = rimFracture->fractureTemplate();
|
||||
|
||||
if(fractureTemplate)
|
||||
{
|
||||
const std::vector<RigFractureCell>& stpCells = fractureTemplate->fractureGrid()->fractureCells();
|
||||
for ( const auto& stpCell: stpCells ) stpCellPolygons.push_back(stpCell.getPolygon());
|
||||
}
|
||||
}
|
||||
double perforationLength = rimFracture->perforationLength();
|
||||
|
||||
calculate(fractureXf, wellPathPoints, wellRadius, perforationLength, stpCellPolygons, m_stimPlanCellIdxToIntersectionInfoMap);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::map<size_t, RigWellPathStimplanIntersector::RigWellPathStimplanIntersector::WellCellIntersection >& RigWellPathStimplanIntersector::intersections() const
|
||||
{
|
||||
return m_stimPlanCellIdxToIntersectionInfoMap;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Todo: Use only the perforated parts of the well path
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigWellPathStimplanIntersector::calculate(const cvf::Mat4d &fractureXf,
|
||||
const std::vector<cvf::Vec3d>& wellPathPointsOrg,
|
||||
double wellRadius,
|
||||
double perforationLength,
|
||||
const std::vector<std::vector<cvf::Vec3d> >& stpCellPolygons,
|
||||
std::map<size_t, WellCellIntersection>& m_stimPlanCellIdxToIntersectionInfoMap)
|
||||
{
|
||||
cvf::Mat4d toFractureXf = fractureXf.getInverted();
|
||||
|
||||
std::vector<cvf::Vec3d> perforationLengthBoundingBoxPolygon;
|
||||
double cicleRadius = perforationLength / 2;
|
||||
int pointsInCirclePolygon = 20;
|
||||
for (int i = 0; i < pointsInCirclePolygon; i++)
|
||||
{
|
||||
double x = cicleRadius * cvf::Math::cos(i * (2 * cvf::PI_D / pointsInCirclePolygon));
|
||||
double y = cicleRadius * cvf::Math::sin(i * (2 * cvf::PI_D / pointsInCirclePolygon));
|
||||
perforationLengthBoundingBoxPolygon.push_back(cvf::Vec3d(x, y, 0));
|
||||
}
|
||||
|
||||
// Convert well path to fracture template system
|
||||
|
||||
std::vector<cvf::Vec3d> fractureRelativeWellPathPoints;
|
||||
for ( auto & wellPPoint : wellPathPointsOrg ) fractureRelativeWellPathPoints.push_back(wellPPoint.getTransformedPoint( toFractureXf));
|
||||
|
||||
// Clip well path to fracture domain
|
||||
|
||||
std::vector<std::vector<cvf::Vec3d> > wellPathPartsWithinFracture =
|
||||
RigCellGeometryTools::clipPolylineByPolygon(fractureRelativeWellPathPoints,
|
||||
perforationLengthBoundingBoxPolygon,
|
||||
RigCellGeometryTools::INTERPOLATE_LINE_Z);
|
||||
|
||||
// Remove the part of the well path that is more than well radius away from the fracture plane
|
||||
|
||||
std::vector< std::vector< cvf::Vec3d > > intersectingWellPathParts;
|
||||
|
||||
for ( const auto& part : wellPathPartsWithinFracture )
|
||||
{
|
||||
std::vector< cvf::Vec3d > currentIntersectingWpPart;
|
||||
for ( size_t vxIdx = 0; vxIdx < part.size() -1; ++vxIdx )
|
||||
{
|
||||
double thisAbsZ = fabs(part[vxIdx].z());
|
||||
double nextAbsZ = fabs(part[vxIdx + 1].z());
|
||||
double thisZ = part[vxIdx].z();
|
||||
double nextZ = part[vxIdx + 1].z();
|
||||
|
||||
if ( thisAbsZ >= wellRadius && nextAbsZ >= wellRadius )
|
||||
{
|
||||
if ( (thisZ >= 0 && nextZ >= 0)
|
||||
|| (thisZ <= 0 && nextZ <= 0 ) )
|
||||
{
|
||||
continue; // Outside
|
||||
}
|
||||
else // In and out
|
||||
{
|
||||
{
|
||||
double wellRadiusDistFromPlane = thisZ > 0 ? wellRadius: -wellRadius;
|
||||
|
||||
double fraction = (wellRadiusDistFromPlane - thisZ)/ (nextZ - thisZ);
|
||||
|
||||
cvf::Vec3d intersectPoint = part[vxIdx] + fraction * (part[vxIdx+1] - part[vxIdx]);
|
||||
currentIntersectingWpPart.push_back(intersectPoint);
|
||||
}
|
||||
{
|
||||
double wellRadiusDistFromPlane = nextZ > 0 ? wellRadius: -wellRadius;
|
||||
|
||||
double fraction = (wellRadiusDistFromPlane - thisZ)/ (nextZ - thisZ);
|
||||
|
||||
cvf::Vec3d intersectPoint = part[vxIdx] + fraction * (part[vxIdx+1] - part[vxIdx]);
|
||||
currentIntersectingWpPart.push_back(intersectPoint);
|
||||
|
||||
intersectingWellPathParts.push_back(currentIntersectingWpPart);
|
||||
currentIntersectingWpPart.clear();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ( thisAbsZ < wellRadius && nextAbsZ < wellRadius ) // Inside
|
||||
{
|
||||
currentIntersectingWpPart.push_back(part[vxIdx]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( thisAbsZ < wellRadius && nextAbsZ >= wellRadius ) // Going out
|
||||
{
|
||||
currentIntersectingWpPart.push_back(part[vxIdx]);
|
||||
|
||||
double wellRadiusDistFromPlane = nextZ > 0 ? wellRadius: -wellRadius;
|
||||
|
||||
double fraction = (wellRadiusDistFromPlane - thisZ)/ (nextZ - thisZ);
|
||||
|
||||
cvf::Vec3d intersectPoint = part[vxIdx] + fraction * (part[vxIdx+1] - part[vxIdx]);
|
||||
currentIntersectingWpPart.push_back(intersectPoint);
|
||||
|
||||
intersectingWellPathParts.push_back(currentIntersectingWpPart);
|
||||
currentIntersectingWpPart.clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( thisAbsZ >= wellRadius && nextAbsZ < wellRadius ) // Going in
|
||||
{
|
||||
double wellRadiusDistFromPlane = thisZ > 0 ? wellRadius: -wellRadius;
|
||||
|
||||
double fraction = (wellRadiusDistFromPlane - thisZ)/ (nextZ - thisZ);
|
||||
|
||||
cvf::Vec3d intersectPoint = part[vxIdx] + fraction * (part[vxIdx+1] - part[vxIdx]);
|
||||
currentIntersectingWpPart.push_back(intersectPoint);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Add last point if it is within the radius
|
||||
|
||||
if (part.size() > 1 && fabs(part.back().z()) < wellRadius)
|
||||
{
|
||||
currentIntersectingWpPart.push_back(part.back());
|
||||
}
|
||||
|
||||
if ( !currentIntersectingWpPart.empty() )
|
||||
{
|
||||
intersectingWellPathParts.push_back(currentIntersectingWpPart);
|
||||
}
|
||||
}
|
||||
|
||||
// Find the StimPlan cells touched by the intersecting well path parts
|
||||
|
||||
for ( size_t cIdx = 0; cIdx < stpCellPolygons.size(); ++ cIdx )
|
||||
{
|
||||
const std::vector<cvf::Vec3d>& cellPolygon = stpCellPolygons[cIdx];
|
||||
for ( const auto& wellpathPart :intersectingWellPathParts )
|
||||
{
|
||||
std::vector<std::vector<cvf::Vec3d> > wellPathPartsInPolygon =
|
||||
RigCellGeometryTools::clipPolylineByPolygon(wellpathPart,
|
||||
cellPolygon,
|
||||
RigCellGeometryTools::USE_HUGEVAL);
|
||||
for ( const auto& wellPathPartInCell: wellPathPartsInPolygon )
|
||||
{
|
||||
if ( !wellPathPartInCell.empty() )
|
||||
{
|
||||
int endpointCount = 0;
|
||||
if ( wellPathPartInCell.front().z() != HUGE_VAL ) ++endpointCount;
|
||||
if ( wellPathPartInCell.back().z() != HUGE_VAL ) ++endpointCount;
|
||||
|
||||
cvf::Vec3d intersectionLength = (wellPathPartInCell.back() - wellPathPartInCell.front());
|
||||
double xLengthInCell = fabs(intersectionLength.x());
|
||||
double yLengthInCell = fabs(intersectionLength.y());
|
||||
|
||||
m_stimPlanCellIdxToIntersectionInfoMap[cIdx].endpointCount += endpointCount;
|
||||
m_stimPlanCellIdxToIntersectionInfoMap[cIdx].hlength += xLengthInCell;
|
||||
m_stimPlanCellIdxToIntersectionInfoMap[cIdx].vlength += yLengthInCell;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2017- Statoil 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 "cvfBase.h"
|
||||
#include "cvfMatrix4.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class RigWellPath;
|
||||
class RimFracture;
|
||||
class RigWellPathStimplanIntersectorTester;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
class RigWellPathStimplanIntersector
|
||||
{
|
||||
public:
|
||||
struct WellCellIntersection
|
||||
{
|
||||
WellCellIntersection():hlength(0.0), vlength(0.0), endpointCount(0) {}
|
||||
double hlength;
|
||||
double vlength;
|
||||
int endpointCount;
|
||||
};
|
||||
|
||||
RigWellPathStimplanIntersector(const RigWellPath* wellpathGeom, const RimFracture* rimFracture);
|
||||
|
||||
const std::map<size_t, WellCellIntersection >& intersections() const;
|
||||
|
||||
private:
|
||||
friend class RigWellPathStimplanIntersectorTester;
|
||||
static void calculate(const cvf::Mat4d& fractureXf,
|
||||
const std::vector<cvf::Vec3d>& wellPathPoints,
|
||||
double wellRadius,
|
||||
double perforationLength,
|
||||
const std::vector<std::vector<cvf::Vec3d> >& stpCellPolygons,
|
||||
std::map<size_t, WellCellIntersection>& stimPlanCellIdxToIntersectionInfoMap);
|
||||
|
||||
std::map<size_t, WellCellIntersection > m_stimPlanCellIdxToIntersectionInfoMap;
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
class RigWellPathStimplanIntersectorTester
|
||||
{
|
||||
public:
|
||||
static void testCalculate(const cvf::Mat4d& fractureXf,
|
||||
const std::vector<cvf::Vec3d>& wellPathPoints,
|
||||
double wellRadius,
|
||||
double perforationLength,
|
||||
const std::vector<std::vector<cvf::Vec3d> >& stpCellPolygons,
|
||||
std::map<size_t, RigWellPathStimplanIntersector::WellCellIntersection>& stimPlanCellIdxToIntersectionInfoMap)
|
||||
{
|
||||
RigWellPathStimplanIntersector::calculate(fractureXf, wellPathPoints, wellRadius, perforationLength, stpCellPolygons, stimPlanCellIdxToIntersectionInfoMap);
|
||||
}
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user