#2423 Export Completions : Move Rig*-files to completion export folder

This commit is contained in:
Magne Sjaastad
2018-01-30 15:35:03 +01:00
parent f0f7c954cc
commit e989b3afc9
25 changed files with 23 additions and 23 deletions

View File

@@ -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

View File

@@ -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()

View File

@@ -18,7 +18,7 @@
#pragma once
#include "../RicCaseAndFileExportSettingsUi.h"
#include "RicCaseAndFileExportSettingsUi.h"
#include "cafPdmField.h"
#include "cafAppEnum.h"

View File

@@ -21,9 +21,9 @@
#include "RifEclipseDataTableFormatter.h"
#include "RicCaseAndFileExportSettingsUi.h"
#include "RicWellPathExportCompletionDataFeature.h"
#include "cafCmdFeature.h"
class RimFishbonesCollection;

View File

@@ -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;
}

View File

@@ -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);
};

View File

@@ -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;
}

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -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;
};

View File

@@ -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;
}

View File

@@ -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);
};

View File

@@ -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();
}

View File

@@ -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;
};

View File

@@ -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;
}
}
}
}
}

View File

@@ -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);
}
};