mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-08 07:03:25 -06:00
952e766c2f
* Update to clang-format-15 Removed two custom .clang-format files in subfolders of AppFwk * Fixes by clang-format
375 lines
15 KiB
C++
375 lines
15 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2023- Equinor ASA
|
|
//
|
|
// ResInsight is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
|
// for more details.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "RigWellAllocationOverTime.h"
|
|
|
|
#include "cafAssert.h"
|
|
|
|
#include "RigAccWellFlowCalculator.h"
|
|
#include "RigFlowDiagResultAddress.h"
|
|
#include "RigWellResultPoint.h"
|
|
|
|
#include <set>
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RigWellAllocationOverTime::RigWellAllocationOverTime( const std::vector<QDateTime>& timeStepDates,
|
|
const std::map<QDateTime, RigAccWellFlowCalculator>& timeStepAndCalculatorPairs )
|
|
: m_timeStepDates( timeStepDates )
|
|
{
|
|
for ( const auto& [date, calculator] : timeStepAndCalculatorPairs )
|
|
{
|
|
std::string err = "Calculator for time step date " + date.toString().toStdString() + " does not exist in time step dates vector ";
|
|
CAF_ASSERT( std::find( m_timeStepDates.begin(), m_timeStepDates.end(), date ) != m_timeStepDates.end() && err.data() );
|
|
}
|
|
|
|
// Time steps not present in input map is considered "excluded" time steps
|
|
// Build new time step and calculator map using calculator for "next" valid time step for
|
|
// "excluded" time steps
|
|
QDateTime prevValidTimeStep;
|
|
for ( auto it = m_timeStepDates.rbegin(); it != m_timeStepDates.rend(); ++it )
|
|
{
|
|
const QDateTime& timeStep = *it;
|
|
auto timeStepCalculatorIt = timeStepAndCalculatorPairs.find( timeStep );
|
|
if ( timeStepCalculatorIt != timeStepAndCalculatorPairs.end() )
|
|
{
|
|
m_timeStepAndCalculatorPairs.emplace( timeStep, timeStepCalculatorIt->second );
|
|
prevValidTimeStep = timeStep;
|
|
}
|
|
else if ( prevValidTimeStep.isValid() )
|
|
{
|
|
// If no calculator for this time step, use the previous valid time step calculator
|
|
m_timeStepAndCalculatorPairs.emplace( timeStep, timeStepAndCalculatorPairs.at( prevValidTimeStep ) );
|
|
}
|
|
}
|
|
|
|
std::sort( m_timeStepDates.begin(), m_timeStepDates.end() );
|
|
|
|
// Retrieve union of well names across all calculators
|
|
std::set<QString> allWellNames;
|
|
for ( const auto& [date, calculator] : m_timeStepAndCalculatorPairs )
|
|
{
|
|
allWellNames.insert( calculator.tracerNames().begin(), calculator.tracerNames().end() );
|
|
}
|
|
|
|
// Fill default well values into map
|
|
const double defaultValue = 0.0;
|
|
for ( const auto& well : allWellNames )
|
|
{
|
|
for ( const auto& date : m_timeStepDates )
|
|
{
|
|
std::pair<QDateTime, double> defaultPair( date, defaultValue );
|
|
m_defaultWellValuesMap[well].insert( defaultPair );
|
|
}
|
|
}
|
|
m_wellValuesMap = m_defaultWellValuesMap;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigWellAllocationOverTime::fillWithFlowRateFractionValues()
|
|
{
|
|
m_wellValuesMap = m_defaultWellValuesMap;
|
|
for ( auto& [timeStep, calculator] : m_timeStepAndCalculatorPairs )
|
|
{
|
|
const auto totalTracerFractions = calculator.totalTracerFractions();
|
|
for ( const auto& [wellName, value] : totalTracerFractions )
|
|
{
|
|
m_wellValuesMap[wellName][timeStep] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigWellAllocationOverTime::fillWithFlowRatePercentageValues()
|
|
{
|
|
m_wellValuesMap = m_defaultWellValuesMap;
|
|
for ( auto& [timeStep, calculator] : m_timeStepAndCalculatorPairs )
|
|
{
|
|
const auto totalTracerFractions = calculator.totalTracerFractions();
|
|
for ( const auto& [wellName, value] : totalTracerFractions )
|
|
{
|
|
double valuePercent = 100.0 * value;
|
|
m_wellValuesMap[wellName][timeStep] = valuePercent;
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigWellAllocationOverTime::fillWithFlowRateValues()
|
|
{
|
|
m_wellValuesMap = m_defaultWellValuesMap;
|
|
const size_t branchIdx = 0;
|
|
for ( auto& [timeStep, calculator] : m_timeStepAndCalculatorPairs )
|
|
{
|
|
for ( const auto& wellName : calculator.tracerNames() )
|
|
{
|
|
const auto& accumulatedConnectionFlows = calculator.accumulatedTracerFlowPrConnection( wellName, branchIdx );
|
|
const double topConnectionFlow = accumulatedConnectionFlows.empty() ? 0.0 : accumulatedConnectionFlows.back();
|
|
m_wellValuesMap[wellName][timeStep] = topConnectionFlow;
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Fill with flow volume at time step.
|
|
///
|
|
/// Create volume by multiplying with number of days since last time step.
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigWellAllocationOverTime::fillWithFlowVolumeValues()
|
|
{
|
|
fillWithFlowRateValues();
|
|
|
|
for ( auto& [well, timeStepsAndValues] : m_wellValuesMap )
|
|
{
|
|
QDateTime prevTimeStep;
|
|
for ( auto& [timeStep, value] : timeStepsAndValues )
|
|
{
|
|
if ( !prevTimeStep.isValid() )
|
|
{
|
|
prevTimeStep = timeStep;
|
|
continue;
|
|
}
|
|
|
|
const auto numDays = static_cast<double>( prevTimeStep.daysTo( timeStep ) );
|
|
value = value * numDays;
|
|
prevTimeStep = timeStep;
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Fill with accumulated flow volume over a range of time steps. Create volume by multiplying with
|
|
/// number of days since last time step.
|
|
///
|
|
/// Group small contributors in "Others" if accumulated volume value at last time step is below
|
|
/// threshold value.
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigWellAllocationOverTime::fillWithAccumulatedFlowVolumeValues( double smallContributionsThreshold )
|
|
{
|
|
fillWithFlowRateValues();
|
|
|
|
for ( auto& [well, timeStepsAndValues] : m_wellValuesMap )
|
|
{
|
|
QDateTime prevTimeStep;
|
|
double accumulatedVolume = 0.0;
|
|
for ( auto& [timeStep, value] : timeStepsAndValues )
|
|
{
|
|
if ( !prevTimeStep.isValid() )
|
|
{
|
|
prevTimeStep = timeStep;
|
|
continue;
|
|
}
|
|
|
|
const auto numDays = static_cast<double>( prevTimeStep.daysTo( timeStep ) );
|
|
const double volume = value * numDays;
|
|
accumulatedVolume += volume;
|
|
value = accumulatedVolume;
|
|
prevTimeStep = timeStep;
|
|
}
|
|
}
|
|
|
|
if ( smallContributionsThreshold > 0.0 )
|
|
{
|
|
groupAccumulatedFlowVolumes( m_wellValuesMap, smallContributionsThreshold );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigWellAllocationOverTime::fillWithAccumulatedFlowVolumeFractionValues( double smallContributionsThreshold )
|
|
{
|
|
fillWithAccumulatedFlowVolumeFractionOrPercentageValues( FractionOrPercentage::FRACTION, smallContributionsThreshold );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigWellAllocationOverTime::fillWithAccumulatedFlowVolumePercentageValues( double smallContributionsThreshold )
|
|
{
|
|
fillWithAccumulatedFlowVolumeFractionOrPercentageValues( FractionOrPercentage::PERCENTAGE, smallContributionsThreshold );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Fill with accumulated well flow volumes in fraction/percent of total accumulated flow volume
|
|
/// at each time step.
|
|
///
|
|
///
|
|
/// Group small contributors in "Others" if volume value for well is below threshold at every
|
|
/// time step.
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigWellAllocationOverTime::fillWithAccumulatedFlowVolumeFractionOrPercentageValues( FractionOrPercentage selection,
|
|
double smallContributionsThreshold )
|
|
{
|
|
const double scaling = selection == FractionOrPercentage::FRACTION ? 1.0 : 100.0;
|
|
|
|
// Handle threshold filtering afterwards
|
|
const double nonFilteringThreshold = 0.0;
|
|
fillWithAccumulatedFlowVolumeValues( nonFilteringThreshold );
|
|
|
|
for ( const auto& timeStep : m_timeStepDates )
|
|
{
|
|
double totalAccumulatedVolume = 0.0;
|
|
std::map<QString, double> timeStepWellValues;
|
|
|
|
// Sum accumulated volumes at time step
|
|
for ( auto& [well, values] : m_wellValuesMap )
|
|
{
|
|
const auto accumulatedVolume = values[timeStep];
|
|
totalAccumulatedVolume += accumulatedVolume;
|
|
timeStepWellValues[well] = accumulatedVolume;
|
|
}
|
|
|
|
// If no accumulated volume exist at time step
|
|
if ( totalAccumulatedVolume == 0.0 ) continue;
|
|
|
|
// Create percentage value
|
|
for ( auto& [well, value] : timeStepWellValues )
|
|
{
|
|
m_wellValuesMap[well][timeStep] = scaling * value / totalAccumulatedVolume;
|
|
}
|
|
}
|
|
|
|
if ( smallContributionsThreshold > 0.0 )
|
|
{
|
|
const auto threshold = scaling * smallContributionsThreshold;
|
|
groupAccumulatedFlowVolumeFractionsOrPercentages( m_wellValuesMap, threshold );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Handle grouping of small contributors in accumulated volume data based on threshold.
|
|
/// Group small contributors in "Others" if accumulated volume value at last time step is below
|
|
/// threshold value.
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigWellAllocationOverTime::groupAccumulatedFlowVolumes( std::map<QString, std::map<QDateTime, double>>& rWellValuesMap, double threshold )
|
|
{
|
|
if ( m_timeStepDates.empty() ) return;
|
|
|
|
std::map<QString, std::map<QDateTime, double>> groupedWellValuesMap;
|
|
std::map<QString, double> lastAccumulatedWellValues;
|
|
double sumLastAccumulatedWellValues = 0.0;
|
|
const QDateTime lastTimeStep = m_timeStepDates.back();
|
|
for ( auto& [well, values] : rWellValuesMap )
|
|
{
|
|
const double lastWellValue = values[lastTimeStep];
|
|
lastAccumulatedWellValues[well] = lastWellValue;
|
|
sumLastAccumulatedWellValues += lastWellValue;
|
|
}
|
|
|
|
// Filter out wells with accumulated flow less than threshold and place among "others"
|
|
std::vector<QString> contributingWells;
|
|
std::vector<QString> groupedWells;
|
|
for ( const auto& [well, value] : lastAccumulatedWellValues )
|
|
{
|
|
if ( sumLastAccumulatedWellValues > 0.0 && ( value / sumLastAccumulatedWellValues ) < threshold )
|
|
{
|
|
groupedWells.push_back( well );
|
|
}
|
|
else
|
|
{
|
|
contributingWells.push_back( well );
|
|
}
|
|
}
|
|
|
|
for ( const auto& well : contributingWells )
|
|
{
|
|
groupedWellValuesMap[well] = rWellValuesMap[well];
|
|
}
|
|
for ( const auto& well : groupedWells )
|
|
{
|
|
if ( groupedWellValuesMap.count( RIG_TINY_TRACER_GROUP_NAME ) == 0 )
|
|
{
|
|
groupedWellValuesMap[RIG_TINY_TRACER_GROUP_NAME] = rWellValuesMap[well];
|
|
}
|
|
else
|
|
{
|
|
for ( const auto& [date, value] : rWellValuesMap[well] )
|
|
{
|
|
groupedWellValuesMap[RIG_TINY_TRACER_GROUP_NAME][date] += value;
|
|
}
|
|
}
|
|
}
|
|
|
|
rWellValuesMap = groupedWellValuesMap;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Handle grouping of small contributors in accumulated volume fraction/percentage based on threshold.
|
|
/// Group small contributors in "Others" if fraction/percentage value for well is below threshold at every
|
|
/// time step. If fraction/percentage value is above threshold for one time step or more, show data for well
|
|
/// at every time step.
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigWellAllocationOverTime::groupAccumulatedFlowVolumeFractionsOrPercentages( std::map<QString, std::map<QDateTime, double>>& rWellValuesMap,
|
|
double threshold )
|
|
{
|
|
auto getMaxValue = []( const std::map<QDateTime, double>& valuesMap ) -> double
|
|
{
|
|
double maxValue = 0.0;
|
|
for ( const auto& [timeStep, value] : valuesMap )
|
|
{
|
|
maxValue = value > maxValue ? value : maxValue;
|
|
}
|
|
return maxValue;
|
|
};
|
|
|
|
std::vector<QString> contributingWells;
|
|
std::vector<QString> groupedWells;
|
|
for ( const auto& [well, values] : rWellValuesMap )
|
|
{
|
|
const double maxValue = getMaxValue( values );
|
|
if ( maxValue > threshold )
|
|
{
|
|
contributingWells.push_back( well );
|
|
}
|
|
else
|
|
{
|
|
groupedWells.push_back( well );
|
|
}
|
|
}
|
|
|
|
std::map<QString, std::map<QDateTime, double>> groupedWellValuesMap;
|
|
for ( const auto& well : contributingWells )
|
|
{
|
|
groupedWellValuesMap[well] = rWellValuesMap[well];
|
|
}
|
|
for ( const auto& well : groupedWells )
|
|
{
|
|
if ( groupedWellValuesMap.count( RIG_TINY_TRACER_GROUP_NAME ) == 0 )
|
|
{
|
|
groupedWellValuesMap[RIG_TINY_TRACER_GROUP_NAME] = rWellValuesMap[well];
|
|
}
|
|
else
|
|
{
|
|
for ( const auto& [date, value] : rWellValuesMap[well] )
|
|
{
|
|
groupedWellValuesMap[RIG_TINY_TRACER_GROUP_NAME][date] += value;
|
|
}
|
|
}
|
|
}
|
|
|
|
rWellValuesMap = groupedWellValuesMap;
|
|
}
|