///////////////////////////////////////////////////////////////////////////////// // // 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 // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RimWellFlowRateCurve.h" #include "WellLogCommands/RicWellLogPlotCurveFeatureImpl.h" #include "RigWellLogCurveData.h" #include "RimWellAllocationPlot.h" #include "RimWellLogPlot.h" #include "RimWellLogTrack.h" #include "RiuLineSegmentQwtPlotCurve.h" #include "qwt_plot.h" #include "cvfMath.h" #include //================================================================================================== /// /// //================================================================================================== CAF_PDM_SOURCE_INIT(RimWellFlowRateCurve, "WellFlowRateCurve"); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimWellFlowRateCurve::RimWellFlowRateCurve() { CAF_PDM_InitObject("Flow Rate Curve", "", "", ""); m_groupId = 0; m_doFillCurve = true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimWellFlowRateCurve::~RimWellFlowRateCurve() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimWellFlowRateCurve::wellName() const { QString name; RimWellAllocationPlot* wap = wellAllocationPlot(); if (wap) { name = wap->wellName(); } else { name = "Undefined"; } return name; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimWellFlowRateCurve::wellLogChannelName() const { return "AccumulatedFlowRate"; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellFlowRateCurve::setGroupId(int groupId) { m_groupId = groupId; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int RimWellFlowRateCurve::groupId() const { return m_groupId; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellFlowRateCurve::setDoFillCurve(bool doFill) { m_doFillCurve = doFill; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimWellFlowRateCurve::doFillCurve() const { return m_doFillCurve; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimWellFlowRateCurve::createCurveAutoName() { return m_curveAutoName; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellFlowRateCurve::onLoadDataAndUpdate(bool updateParentPlot) { this->RimPlotCurve::updateCurvePresentation(updateParentPlot); if (isCurveVisible()) { m_qwtPlotCurve->setTitle(createCurveAutoName()); updateStackedPlotData(); updateZoomInParentPlot(); if (m_parentQwtPlot) m_parentQwtPlot->replot(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellFlowRateCurve::updateCurveAppearance() { RimWellLogCurve::updateCurveAppearance(); bool isLastCurveInGroup = false; { RimWellLogTrack* wellLogTrack; firstAncestorOrThisOfTypeAsserted(wellLogTrack); std::map> stackedCurveGroups = wellLogTrack->visibleStackedCurves(); const std::vector& curveGroup = stackedCurveGroups[this->m_groupId]; isLastCurveInGroup = (curveGroup.back() == this); } if ( isUsingConnectionNumberDepthType() ) { m_qwtPlotCurve->setStyle(QwtPlotCurve::Steps); } if (m_doFillCurve || isLastCurveInGroup) // Fill the last curve in group with a transparent color to "tie" the group together { QColor curveQColor = QColor (m_curveColor.value().rByte(), m_curveColor.value().gByte(), m_curveColor.value().bByte()); QColor fillColor = curveQColor; QColor lineColor = curveQColor.darker(); if (!m_doFillCurve && isLastCurveInGroup) { fillColor = QColor(24, 16, 10, 50); lineColor = curveQColor; } QLinearGradient gradient; gradient.setCoordinateMode(QGradient::StretchToDeviceMode); gradient.setColorAt(0, fillColor.darker(110)); gradient.setColorAt(0.15, fillColor); gradient.setColorAt(0.25, fillColor); gradient.setColorAt(0.4, fillColor.darker(110)); gradient.setColorAt(0.6, fillColor); gradient.setColorAt(0.8, fillColor.darker(110)); gradient.setColorAt(1, fillColor); m_qwtPlotCurve->setBrush(gradient); QPen curvePen = m_qwtPlotCurve->pen(); curvePen.setColor(lineColor); m_qwtPlotCurve->setPen(curvePen); m_qwtPlotCurve->setOrientation(Qt::Horizontal); m_qwtPlotCurve->setBaseline(0.0); m_qwtPlotCurve->setCurveAttribute(QwtPlotCurve::Inverted, true); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellFlowRateCurve::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { uiOrdering.add(&m_curveName); m_curveName.uiCapability()->setUiReadOnly(true); uiOrdering.add(&m_curveColor); m_curveColor.uiCapability()->setUiReadOnly(true); uiOrdering.skipRemainingFields(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellFlowRateCurve::updateStackedPlotData() { RimWellLogPlot* wellLogPlot; firstAncestorOrThisOfTypeAsserted(wellLogPlot); RimWellLogTrack* wellLogTrack; firstAncestorOrThisOfTypeAsserted(wellLogTrack); bool isFirstTrack = (wellLogTrack == wellLogPlot->trackByIndex(0)); RiaDefines::DepthUnitType displayUnit = RiaDefines::UNIT_NONE; std::vector depthValues; std::vector stackedValues; std::vector< std::pair > polyLineStartStopIndices; double zPos = -10000.0 + 100*groupId(); // Z-position of curve, to draw them in correct order hiding the things behind // Starting way behind the grid (z == 0) at -10000 giving room for 100 groups with 100 curves each before getting above the grid { std::map> stackedCurveGroups = wellLogTrack->visibleStackedCurves(); std::vector stackedCurves; if (stackedCurveGroups.count(groupId()) > 0) { stackedCurves = stackedCurveGroups[groupId()]; } std::vector allDepthValues = m_curveData->measuredDepths(); std::vector allStackedValues(allDepthValues.size()); for (RimWellFlowRateCurve * stCurve : stackedCurves) { std::vector allValues = stCurve->curveData()->xValues(); for (size_t i = 0; i < allValues.size(); ++i) { if (allValues[i] != HUGE_VAL) { allStackedValues[i] += allValues[i]; } } if (stCurve == this) break; zPos -= 1.0; } RigWellLogCurveData tempCurveData; tempCurveData.setValuesAndMD(allStackedValues, allDepthValues, RiaDefines::UNIT_NONE, false); depthValues = tempCurveData.measuredDepthPlotValues(displayUnit); stackedValues = tempCurveData.xPlotValues(); polyLineStartStopIndices = tempCurveData.polylineStartStopIndices(); } // Insert the first depth position again, to add a value pair if ( depthValues.size() ) // Should we really do this for all curve variants ? { depthValues.insert(depthValues.begin(), depthValues[0]); stackedValues.insert(stackedValues.begin(), 0.0); polyLineStartStopIndices.front().second += 1; if (wellLogPlot->trackCount() > 1 && isFirstTrack) { // Add a dummy negative depth value to make the contribution // from other branches connected to well head visible double availableMinDepth; double availableMaxDepth; wellLogPlot->availableDepthRange(&availableMinDepth, &availableMaxDepth); double depthSpan = 0.1 * cvf::Math::abs(availableMinDepth - availableMaxDepth); // Round off value to floored decade double logDecValue = log10(depthSpan); logDecValue = cvf::Math::floor(logDecValue); depthSpan = pow(10.0, logDecValue); double dummyNegativeDepthValue = depthValues.back() - depthSpan; depthValues.push_back(dummyNegativeDepthValue); stackedValues.push_back(stackedValues.back()); polyLineStartStopIndices.front().second += 1; } } // Add a dummy point for the zeroth connection to make the "end" distribution show better. if ( isFirstTrack && isUsingConnectionNumberDepthType() ) { stackedValues.push_back(stackedValues.back()); depthValues.push_back(0.0); polyLineStartStopIndices.front().second += 1; } m_qwtPlotCurve->setSamples(stackedValues.data(), depthValues.data(), static_cast(depthValues.size())); m_qwtPlotCurve->setLineSegmentStartStopIndices(polyLineStartStopIndices); m_qwtPlotCurve->setZ(zPos); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimWellFlowRateCurve::isUsingConnectionNumberDepthType() const { RimWellLogPlot* wellLogPlot; firstAncestorOrThisOfType(wellLogPlot); if ( wellLogPlot && wellLogPlot->depthType() == RimWellLogPlot::CONNECTION_NUMBER ) { return true; } return false; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimWellAllocationPlot* RimWellFlowRateCurve::wellAllocationPlot() const { RimWellAllocationPlot* wap = nullptr; this->firstAncestorOrThisOfType(wap); return wap; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellFlowRateCurve::setFlowValuesPrDepthValue(const QString& curveName, const std::vector& depthValues, const std::vector& flowRates) { m_curveData = new RigWellLogCurveData; m_curveData->setValuesAndMD(flowRates, depthValues, RiaDefines::UNIT_NONE, false); m_curveAutoName = curveName; }