mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-26 15:10:22 -05:00
* Add Add Well Picks button to well log formation settings * Expose formation zone colors and shading alpha from RFT track * Average observed pressures per formation with full min/max range * Show formation-colored observed pressure and depth filter in RFT correlation plots * Default new RFT correlation plots to formation filter and ensemble parameter coloring * Move Qwt code out of RFT correlation Rim classes * Align RFT correlation depth filter bars and click zones with displayed track formations
165 lines
9.6 KiB
C++
165 lines
9.6 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2026 Equinor ASA
|
|
//
|
|
// ResInsight is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
|
// for more details.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
#pragma once
|
|
|
|
#include "RiaDefines.h"
|
|
|
|
#include "cafAppEnum.h"
|
|
|
|
#include <QDateTime>
|
|
#include <QString>
|
|
#include <QStringList>
|
|
|
|
#include <optional>
|
|
#include <vector>
|
|
|
|
class RifReaderRftInterface;
|
|
class RigEclipseWellLogExtractor;
|
|
class RimEclipseResultCase;
|
|
class RimSummaryEnsemble;
|
|
class RimWellFormationsFile;
|
|
|
|
//==================================================================================================
|
|
///
|
|
/// Helpers for filtering and reducing RFT pressure data by depth range, shared by the RFT
|
|
/// correlation parameter cross plot (RimParameterRftCrossPlot) and tornado plot (RimRftTornadoPlot).
|
|
///
|
|
//==================================================================================================
|
|
namespace RimRftCrossPlotTools
|
|
{
|
|
// How the active depth filter selects samples: a single depth range, or a set of named zones
|
|
// looked up in a well formations file.
|
|
enum class DepthFilterMode
|
|
{
|
|
NONE,
|
|
DEPTH_RANGE,
|
|
ZONES
|
|
};
|
|
using DepthFilterModeEnum = caf::AppEnum<DepthFilterMode>;
|
|
|
|
// A single inclusive depth interval, in the unit/datum of whichever depth type it was built for.
|
|
struct DepthInterval
|
|
{
|
|
double top = 0.0;
|
|
double base = 0.0;
|
|
QString zoneName; // set when the interval comes from a formation zone
|
|
};
|
|
|
|
// Short abbreviation used in axis titles and plot titles for the active depth type.
|
|
QString depthTypeAbbreviation( RiaDefines::DepthType depthType );
|
|
|
|
// Returns the depth values for the given well/time step, strictly matching depthType: MD
|
|
// (native RFT MD channel, falling back to extractor-derived MD, then to MD interpolated from
|
|
// observed FMU RFT data for the well) or TVD (native RFT TVD channel). Returns an empty vector if
|
|
// the requested depth type is not available, rather than silently substituting the other depth
|
|
// type — callers that filter by depth range rely on this to exclude/blank out data instead of
|
|
// comparing a range against the wrong unit.
|
|
std::vector<double> rftCurveDepthValues( RifReaderRftInterface* reader,
|
|
const QString& wellName,
|
|
const QDateTime& timeStep,
|
|
RigEclipseWellLogExtractor* extractor,
|
|
RiaDefines::DepthType depthType = RiaDefines::DepthType::MEASURED_DEPTH );
|
|
|
|
// MD for the reader's TVD samples, interpolated from the MD/TVD pairs of observed FMU RFT data for
|
|
// the well at the time step. Empty if no such data is available.
|
|
std::vector<double> measuredDepthFromObservedData( RifReaderRftInterface* reader, const QString& wellName, const QDateTime& timeStep );
|
|
|
|
// Returns the subset of pressures whose corresponding depth is within [depthRangeMin, depthRangeMax].
|
|
// If useDepthRange is false, all pressures are returned unfiltered. If useDepthRange is true and
|
|
// depths/pressures are not the same size, an empty vector is returned (no aligned depth data).
|
|
std::vector<double> filterPressuresByDepthRange( const std::vector<double>& depths,
|
|
const std::vector<double>& pressures,
|
|
bool useDepthRange,
|
|
double depthRangeMin,
|
|
double depthRangeMax );
|
|
|
|
// Builds the active depth filter intervals from either a depth range or a set of selected zones.
|
|
// Returns an empty vector (meaning "no filter") when the mode is NONE, or when ZONES mode is
|
|
// selected but no well formations file, well name, or matching zones are available.
|
|
std::vector<DepthInterval> buildDepthIntervals( DepthFilterMode mode,
|
|
double depthRangeMin,
|
|
double depthRangeMax,
|
|
RimWellFormationsFile* wellFormationsFile,
|
|
const QString& wellName,
|
|
const std::vector<QString>& selectedZones,
|
|
RiaDefines::DepthType depthType );
|
|
|
|
// Returns one interval per formation zone of the well (named by zone), used to look up which zone a
|
|
// depth belongs to. Empty if no well formations file or no formations for the well.
|
|
std::vector<DepthInterval>
|
|
buildAllZoneIntervals( RimWellFormationsFile* wellFormationsFile, const QString& wellName, RiaDefines::DepthType depthType );
|
|
|
|
// Returns the subset of pressures whose corresponding depth lies within any of depthIntervals
|
|
// (inclusive). An empty depthIntervals list means "no filter", returning pressures unchanged; a
|
|
// size mismatch between depths/pressures returns an empty vector (no aligned depth data).
|
|
std::vector<double> filterPressuresByDepthIntervals( const std::vector<double>& depths,
|
|
const std::vector<double>& pressures,
|
|
const std::vector<DepthInterval>& depthIntervals );
|
|
|
|
// Short description of the active depth filter for titles/axis labels/group text, e.g.
|
|
// "MD 1000 - 2000 m" or "Zones: Valysar, Therys". Empty when filtering is disabled.
|
|
QString depthFilterDescription( DepthFilterMode mode,
|
|
RiaDefines::DepthType depthType,
|
|
double depthRangeMin,
|
|
double depthRangeMax,
|
|
const std::vector<QString>& selectedZones );
|
|
|
|
// A single observed (e.g. FMU) RFT pressure sample with its uncertainty.
|
|
struct ObservedPressure
|
|
{
|
|
double pressure = 0.0;
|
|
double error = 0.0; // observed pressure error; 0 if not available
|
|
QString zoneName; // formation zone containing the sample; empty if not filtered by zones
|
|
double rangeMin = 0.0; // lowest pressure - error among the observations
|
|
double rangeMax = 0.0; // highest pressure + error among the observations
|
|
int count = 1; // number of observations combined into this entry
|
|
};
|
|
|
|
// Observed pressure samples within depthIntervals for the well/time step, across all observed data
|
|
// sets. Samples in the same zone are combined into one entry: mean pressure, with rangeMin/rangeMax
|
|
// covering all of them. An empty depthIntervals list means no filtering. Samples are named by the
|
|
// selected zones when depthIntervals come from a zone filter, otherwise by zoneIntervals.
|
|
std::vector<ObservedPressure> computeObservedPressures( const QString& wellName,
|
|
const QDateTime& timeStep,
|
|
const std::vector<DepthInterval>& depthIntervals,
|
|
RiaDefines::DepthType depthType = RiaDefines::DepthType::MEASURED_DEPTH,
|
|
const std::vector<DepthInterval>& zoneIntervals = {} );
|
|
|
|
// Arithmetic mean of the given samples, or infinity if samples is empty.
|
|
double computeMean( const std::vector<double>& samples );
|
|
|
|
// Computes the individual RFT pressure samples within depthIntervals per ensemble case.
|
|
// Indices match ensemble->allSummaryCases(). A case with no data gets an empty vector. An empty
|
|
// depthIntervals list means no filtering.
|
|
std::vector<std::vector<double>> computePressureSamplesPerCase( RimSummaryEnsemble* ensemble,
|
|
const QString& wellName,
|
|
const QDateTime& timeStep,
|
|
RimEclipseResultCase* eclipseCase,
|
|
const std::vector<DepthInterval>& depthIntervals,
|
|
RiaDefines::DepthType depthType = RiaDefines::DepthType::MEASURED_DEPTH );
|
|
|
|
// Computes mean RFT pressure per ensemble case (one entry per case, infinity = no data).
|
|
// Indices match ensemble->allSummaryCases().
|
|
std::vector<double> computeMeanPressurePerCase( RimSummaryEnsemble* ensemble,
|
|
const QString& wellName,
|
|
const QDateTime& timeStep,
|
|
RimEclipseResultCase* eclipseCase,
|
|
const std::vector<DepthInterval>& depthIntervals,
|
|
RiaDefines::DepthType depthType = RiaDefines::DepthType::MEASURED_DEPTH );
|
|
} // namespace RimRftCrossPlotTools
|