mirror of
https://github.com/OPM/ResInsight.git
synced 2026-09-03 20:53:13 -05:00
Rename ApplicationCode to ApplicationLibCode
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
|
||||
set (SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaArgumentParser.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaDateStringParser.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaColorTables.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaColorTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaEclipseUnitTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaImageCompareReporter.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaImageFileCompare.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaImageTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaLogging.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaProjectModifier.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaRegressionTest.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaImportEclipseCaseTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaQDateTimeTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaSummaryTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWellNameComparer.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaStdStringTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaInterpolationTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaSummaryCurveAnalyzer.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaSimWellBranchTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaProjectFileVersionTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaStringEncodingTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaTextStringTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaTextFileCompare.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaRegressionTestRunner.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaExtractionTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaFilePathTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaCurveMerger.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaCurveMerger.inl
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaCurveDataTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaTimeHistoryCurveResampler.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaStatisticsTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaOffshoreSphericalCoords.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWeightedMeanCalculator.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaMedianCalculator.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWeightedMeanCalculator.inl
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWeightedGeometricMeanCalculator.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWeightedHarmonicMeanCalculator.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaOptionItemFactory.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaGitDiff.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaCellDividingTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaFieldHandleTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaBoundingBoxTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWellLogUnitTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWellLogUnitTools.inl
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaTimeTTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaValidRegExpValidator.h
|
||||
)
|
||||
|
||||
set (SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaArgumentParser.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaDateStringParser.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaColorTables.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaColorTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaEclipseUnitTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaImageCompareReporter.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaImageFileCompare.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaImageTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaLogging.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaProjectModifier.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaRegressionTest.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaImportEclipseCaseTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaQDateTimeTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaSummaryTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWellNameComparer.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaStdStringTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaInterpolationTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaSummaryCurveAnalyzer.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaSimWellBranchTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaProjectFileVersionTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaStringEncodingTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaTextStringTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaTextFileCompare.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaRegressionTestRunner.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaExtractionTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaFilePathTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaCurveMerger.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaCurveDataTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaTimeHistoryCurveResampler.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaStatisticsTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWeightedGeometricMeanCalculator.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWeightedHarmonicMeanCalculator.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaOptionItemFactory.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaGitDiff.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaCellDividingTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaFieldHandleTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaBoundingBoxTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaTimeTTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaValidRegExpValidator.cpp
|
||||
)
|
||||
|
||||
list(APPEND CODE_HEADER_FILES
|
||||
${SOURCE_GROUP_HEADER_FILES}
|
||||
)
|
||||
|
||||
list(APPEND CODE_SOURCE_FILES
|
||||
${SOURCE_GROUP_SOURCE_FILES}
|
||||
)
|
||||
|
||||
set (QT_MOC_HEADERS
|
||||
${QT_MOC_HEADERS}
|
||||
)
|
||||
|
||||
|
||||
source_group( "Application\\Tools" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake )
|
||||
@@ -0,0 +1,160 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaArgumentParser.h"
|
||||
|
||||
#include "RiaBaseDefs.h"
|
||||
#include "RiaImportEclipseCaseTools.h"
|
||||
#include "RiaLogging.h"
|
||||
#include "RiaPreferences.h"
|
||||
#include "RiaProjectModifier.h"
|
||||
#include "RiaRegressionTestRunner.h"
|
||||
|
||||
#include "RimProject.h"
|
||||
|
||||
#include "RiuMainWindow.h"
|
||||
#include "RiuPlotMainWindow.h"
|
||||
|
||||
#include "RicfCommandFileExecutor.h"
|
||||
|
||||
#include "ExportCommands/RicSnapshotAllPlotsToFileFeature.h"
|
||||
#include "ExportCommands/RicSnapshotAllViewsToFileFeature.h"
|
||||
#include "ExportCommands/RicSnapshotViewToFileFeature.h"
|
||||
#include "RicImportSummaryCasesFeature.h"
|
||||
|
||||
#include "cafPdmScriptIOMessages.h"
|
||||
#include "cvfProgramOptions.h"
|
||||
#include "cvfqtUtils.h"
|
||||
|
||||
#include "cafUtils.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFile>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaArgumentParser::parseArguments( cvf::ProgramOptions* progOpt )
|
||||
{
|
||||
CVF_ASSERT( progOpt );
|
||||
progOpt->registerOption( "help", "", "Displays help text and exits." );
|
||||
progOpt->registerOption( "?", "", "Displays help text and exits." );
|
||||
|
||||
progOpt->registerOption( "project", "<filename>", "Open project file <filename>.", cvf::ProgramOptions::SINGLE_VALUE );
|
||||
progOpt->registerOption( "last", "", "Open last used project." );
|
||||
progOpt->registerOption( "case",
|
||||
"<casename|filename> [<casename|filename> ...]",
|
||||
"Imports the Eclipse cases specified by case name with or without extension."
|
||||
"If <casename>, import the corresponding grid file and summary file"
|
||||
"If <filename> has extension .GRRID/.EGRID, import the grid file and corresponding "
|
||||
"summary file"
|
||||
"If <filename> has extension .SMSPEC, import the summary file (does not open the "
|
||||
"corresponding grid file)",
|
||||
cvf::ProgramOptions::MULTI_VALUE );
|
||||
progOpt->registerOption( "size",
|
||||
"<width> <height>",
|
||||
"Set size of the main application window.",
|
||||
cvf::ProgramOptions::MULTI_VALUE );
|
||||
progOpt->registerOption( "console", "", "Launch as a console application without graphics" );
|
||||
progOpt->registerOption( "server",
|
||||
"[<portnumber>]",
|
||||
"Launch as a GRPC server. Default port is 50051",
|
||||
cvf::ProgramOptions::SINGLE_VALUE );
|
||||
progOpt->registerOption( "startdir", "<folder>", "Set startup directory.\n", cvf::ProgramOptions::SINGLE_VALUE );
|
||||
|
||||
progOpt->registerOption( "summaryplot",
|
||||
"[<plotOptions>] <eclipsesummaryvectors> <eclipsedatafiles>",
|
||||
"Creates a summary plot using all the <eclipsedatafiles>,"
|
||||
"and all the summary vectors defined in <eclipsesummaryvectors>."
|
||||
"Use --summaryplot -help to show a more detailed help text.\n",
|
||||
cvf::ProgramOptions::OPTIONAL_MULTI_VALUE );
|
||||
|
||||
progOpt->registerOption( "commandFile", "<commandfile>", "Execute the command file.", cvf::ProgramOptions::SINGLE_VALUE );
|
||||
progOpt->registerOption( "commandFileReplaceCases",
|
||||
"[<caseId>] <caseListFile>",
|
||||
"Supply list of cases to replace in project, performing command file for each case.",
|
||||
cvf::ProgramOptions::SINGLE_VALUE );
|
||||
progOpt->registerOption( "commandFileProject",
|
||||
"<filename>",
|
||||
"Project to use if performing case looping for command file. Used in conjunction with "
|
||||
"'commandFileReplaceCases'.\n",
|
||||
cvf::ProgramOptions::SINGLE_VALUE );
|
||||
|
||||
progOpt->registerOption( "snapshotsize",
|
||||
"<width> <height>",
|
||||
"Set size of exported snapshot images.",
|
||||
cvf::ProgramOptions::MULTI_VALUE );
|
||||
progOpt->registerOption( "snapshotfolder",
|
||||
"<folder>",
|
||||
"Set the destination folder for exported snapshot images.\n",
|
||||
cvf::ProgramOptions::SINGLE_VALUE );
|
||||
progOpt->registerOption( "savesnapshots",
|
||||
"all|views|plots",
|
||||
"Save snapshot of all views or plots to project file location sub folder 'snapshots'. "
|
||||
"Option 'all' "
|
||||
"will include both views and plots. Application closes after snapshots have been written.",
|
||||
cvf::ProgramOptions::OPTIONAL_MULTI_VALUE );
|
||||
progOpt->registerOption( "multiCaseSnapshots",
|
||||
"<gridListFile>",
|
||||
"For each grid file listed in the <gridListFile> file, replace the first case in the "
|
||||
"project and save "
|
||||
"snapshots of all views.\n",
|
||||
cvf::ProgramOptions::SINGLE_VALUE );
|
||||
|
||||
progOpt->registerOption( "replaceCase",
|
||||
"[<caseId>] <newGridFile>",
|
||||
"Replace grid in <caseId> or first case with <newgridFile>. Repeat parameter for multiple "
|
||||
"replace operations.",
|
||||
cvf::ProgramOptions::MULTI_VALUE,
|
||||
cvf::ProgramOptions::COMBINE_REPEATED );
|
||||
progOpt->registerOption( "replaceSourceCases",
|
||||
"[<caseGroupId>] <gridListFile>",
|
||||
"Replace source cases in <caseGroupId> or first grid case group with the grid files "
|
||||
"listed in the "
|
||||
"<gridListFile> file. Repeat parameter for multiple replace operations.",
|
||||
cvf::ProgramOptions::MULTI_VALUE,
|
||||
cvf::ProgramOptions::COMBINE_REPEATED );
|
||||
progOpt->registerOption( "replacePropertiesFolder",
|
||||
"[<caseId>] <newPropertiesFolder>",
|
||||
"Replace the folder containing property files for an eclipse input case.\n",
|
||||
cvf::ProgramOptions::MULTI_VALUE );
|
||||
|
||||
progOpt->registerOption( "updateregressiontestbase", "<folder>", "System command", cvf::ProgramOptions::SINGLE_VALUE );
|
||||
progOpt->registerOption( "regressiontest", "<folder>", "System command", cvf::ProgramOptions::SINGLE_VALUE );
|
||||
#ifdef USE_UNIT_TESTS
|
||||
progOpt->registerOption( "unittest", "", "System command" );
|
||||
#endif
|
||||
progOpt->registerOption( "generate", "[<outputFile>]", "Generate code or documentation", cvf::ProgramOptions::SINGLE_VALUE );
|
||||
progOpt->registerOption( "ignoreArgs", "", "System command. Ignore all arguments. Mostly for testing purposes" );
|
||||
|
||||
progOpt->setOptionPrefix( cvf::ProgramOptions::DOUBLE_DASH );
|
||||
|
||||
QStringList arguments = QCoreApplication::arguments();
|
||||
|
||||
bool parseOk = progOpt->parse( cvfqt::Utils::toStringVector( arguments ) );
|
||||
|
||||
// If positional parameter functionality is to be supported, the test for existence of positionalParameters must be
|
||||
// removed This is based on a pull request by @andlaus https://github.com/OPM/ResInsight/pull/162
|
||||
if ( !parseOk || !progOpt->positionalParameters().empty() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 <QString>
|
||||
|
||||
namespace cvf
|
||||
{
|
||||
class ProgramOptions;
|
||||
}
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaArgumentParser
|
||||
{
|
||||
public:
|
||||
static bool parseArguments( cvf::ProgramOptions* progOpt );
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011- Statoil ASA
|
||||
// Copyright (C) 2013- Ceetron Solutions AS
|
||||
// Copyright (C) 2011-2012 Ceetron AS
|
||||
//
|
||||
// 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 "RiaBoundingBoxTools.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::BoundingBox RiaBoundingBoxTools::inflate( const cvf::BoundingBox& boundingBox, double factor )
|
||||
{
|
||||
cvf::Vec3d center = boundingBox.center();
|
||||
cvf::Vec3d sizes = boundingBox.extent() * factor;
|
||||
|
||||
cvf::Vec3d newMin( center.x() - sizes.x() / 2.0, center.y() - sizes.y() / 2.0, center.z() - sizes.z() / 2.0 );
|
||||
cvf::Vec3d newMax( center.x() + sizes.x() / 2.0, center.y() + sizes.y() / 2.0, center.z() + sizes.z() / 2.0 );
|
||||
return cvf::BoundingBox( newMin, newMax );
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011- Statoil ASA
|
||||
// Copyright (C) 2013- Ceetron Solutions AS
|
||||
// Copyright (C) 2011-2012 Ceetron AS
|
||||
//
|
||||
// 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 <cvfBoundingBox.h>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaBoundingBoxTools
|
||||
{
|
||||
public:
|
||||
static cvf::BoundingBox inflate( const cvf::BoundingBox& boundingBox, double factor );
|
||||
};
|
||||
@@ -0,0 +1,210 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaCellDividingTools.h"
|
||||
|
||||
#include "cvfAssert.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Internal functions
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Splits a line in a number of equal parts
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<cvf::Vec3d> splitLine( cvf::Vec3d ptStart, cvf::Vec3d ptEnd, size_t partCount );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Calculates all points on a face described by edge points from all four edges.
|
||||
/// The result is a grid of points including the given edge points
|
||||
///
|
||||
/// edgeXPtsHigh
|
||||
/// |-------------|
|
||||
/// | |
|
||||
/// edgeYPtsLow | | edgeYPtsHigh
|
||||
/// | |
|
||||
/// |-------------|
|
||||
/// edgeXPtsLow
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<std::vector<cvf::Vec3d>> calcFacePoints( const std::vector<cvf::Vec3d> edgeXPtsLow,
|
||||
const std::vector<cvf::Vec3d> edgeXPtsHigh,
|
||||
const std::vector<cvf::Vec3d> edgeYPtsLow,
|
||||
const std::vector<cvf::Vec3d> edgeYPtsHigh );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<cvf::Vec3d>
|
||||
RiaCellDividingTools::createHexCornerCoords( std::array<cvf::Vec3d, 8> mainCellCorners, size_t nx, size_t ny, size_t nz )
|
||||
{
|
||||
std::array<std::pair<size_t, size_t>, 12> edgeCorners = {
|
||||
std::make_pair( 0, 1 ),
|
||||
std::make_pair( 3, 2 ),
|
||||
std::make_pair( 4, 5 ),
|
||||
std::make_pair( 7, 6 ), // X
|
||||
std::make_pair( 0, 3 ),
|
||||
std::make_pair( 4, 7 ),
|
||||
std::make_pair( 1, 2 ),
|
||||
std::make_pair( 5, 6 ), // Y
|
||||
std::make_pair( 0, 4 ),
|
||||
std::make_pair( 1, 5 ),
|
||||
std::make_pair( 3, 7 ),
|
||||
std::make_pair( 2, 6 ), // Z
|
||||
};
|
||||
|
||||
std::array<size_t, 3> nxyz = { nx, ny, nz };
|
||||
std::array<std::vector<cvf::Vec3d>, 12> edgePoints;
|
||||
|
||||
for ( int i = 0; i < 12; i++ )
|
||||
{
|
||||
int partCountsIndex = i / 4;
|
||||
edgePoints[i] = splitLine( mainCellCorners[edgeCorners[i].first],
|
||||
mainCellCorners[edgeCorners[i].second],
|
||||
nxyz[partCountsIndex] );
|
||||
}
|
||||
|
||||
// lowIJ, highIJ, lowJK, highKJ,
|
||||
std::vector<std::vector<std::vector<cvf::Vec3d>>> nodes;
|
||||
nodes.reserve( ( nx + 1 ) * ( ny + 1 ) * ( nz + 1 ) );
|
||||
|
||||
auto xyFacePtsLow = calcFacePoints( edgePoints[0], edgePoints[1], edgePoints[4], edgePoints[6] );
|
||||
auto xyFacePtsHigh = calcFacePoints( edgePoints[2], edgePoints[3], edgePoints[5], edgePoints[7] );
|
||||
auto yzFacePtsLow = calcFacePoints( edgePoints[4], edgePoints[5], edgePoints[8], edgePoints[10] );
|
||||
auto yzFacePtsHigh = calcFacePoints( edgePoints[6], edgePoints[7], edgePoints[9], edgePoints[11] );
|
||||
auto xzFacePtsLow = calcFacePoints( edgePoints[0], edgePoints[2], edgePoints[8], edgePoints[9] );
|
||||
auto xzFacePtsHigh = calcFacePoints( edgePoints[1], edgePoints[3], edgePoints[10], edgePoints[11] );
|
||||
|
||||
nodes.push_back( xyFacePtsLow );
|
||||
|
||||
for ( size_t z = 1; z < nz; z++ )
|
||||
{
|
||||
auto xyFacePoints = calcFacePoints( xzFacePtsLow[z], xzFacePtsHigh[z], yzFacePtsLow[z], yzFacePtsHigh[z] );
|
||||
nodes.push_back( xyFacePoints );
|
||||
}
|
||||
|
||||
nodes.push_back( xyFacePtsHigh );
|
||||
|
||||
std::vector<cvf::Vec3d> coords;
|
||||
coords.reserve( nx * ny * nz * 8 );
|
||||
|
||||
for ( size_t z = 1; z < nz + 1; z++ )
|
||||
{
|
||||
for ( size_t y = 1; y < ny + 1; y++ )
|
||||
{
|
||||
for ( size_t x = 1; x < nx + 1; x++ )
|
||||
{
|
||||
std::array<cvf::Vec3d, 8> cs;
|
||||
|
||||
cs[0] = nodes[z - 1][y - 1][x - 1];
|
||||
cs[1] = nodes[z - 1][y - 1][x];
|
||||
cs[2] = nodes[z - 1][y][x];
|
||||
cs[3] = nodes[z - 1][y][x - 1];
|
||||
|
||||
cs[4] = nodes[z][y - 1][x - 1];
|
||||
cs[5] = nodes[z][y - 1][x];
|
||||
cs[6] = nodes[z][y][x];
|
||||
cs[7] = nodes[z][y][x - 1];
|
||||
|
||||
coords.insert( coords.end(), cs.begin(), cs.end() );
|
||||
}
|
||||
}
|
||||
}
|
||||
return coords;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaCellDividingTools::computeFlowDistance( const std::array<cvf::Vec3d, 8>& cellVertices,
|
||||
const cvf::Vec3d& areaCenter )
|
||||
{
|
||||
auto subCellCorners = createHexCornerCoords( cellVertices, 2, 2, 2 );
|
||||
|
||||
double weightedDistanceTotal = 0.0;
|
||||
double weightTotal = 0.0;
|
||||
|
||||
for ( size_t c = 0; c < 8; c++ )
|
||||
{
|
||||
double weight = 1.0;
|
||||
weightTotal += weight;
|
||||
|
||||
cvf::Vec3d centerOfSubCell = cvf::Vec3d::ZERO;
|
||||
{
|
||||
cvf::Vec3d vertexSum = cvf::Vec3d::ZERO;
|
||||
for ( size_t v = 0; v < 8; v++ )
|
||||
vertexSum += subCellCorners[c * 8 + v];
|
||||
centerOfSubCell = vertexSum / 8;
|
||||
}
|
||||
|
||||
auto dist = ( centerOfSubCell - areaCenter ).length();
|
||||
weightedDistanceTotal += ( dist * weight );
|
||||
}
|
||||
|
||||
return weightedDistanceTotal / weightTotal;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<cvf::Vec3d> splitLine( cvf::Vec3d ptStart, cvf::Vec3d ptEnd, size_t partCount )
|
||||
{
|
||||
std::vector<cvf::Vec3d> pts = { ptStart };
|
||||
|
||||
for ( size_t i = 1; i < partCount; i++ )
|
||||
{
|
||||
pts.push_back( cvf::Vec3d( ptStart.x() + ( ptEnd.x() - ptStart.x() ) * i / partCount,
|
||||
ptStart.y() + ( ptEnd.y() - ptStart.y() ) * i / partCount,
|
||||
ptStart.z() + ( ptEnd.z() - ptStart.z() ) * i / partCount ) );
|
||||
}
|
||||
pts.push_back( ptEnd );
|
||||
return pts;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<std::vector<cvf::Vec3d>> calcFacePoints( const std::vector<cvf::Vec3d> edgeXPtsLow,
|
||||
const std::vector<cvf::Vec3d> edgeXPtsHigh,
|
||||
const std::vector<cvf::Vec3d> edgeYPtsLow,
|
||||
const std::vector<cvf::Vec3d> edgeYPtsHigh )
|
||||
{
|
||||
CVF_ASSERT( edgeXPtsLow.size() == edgeXPtsHigh.size() && edgeYPtsLow.size() == edgeYPtsHigh.size() );
|
||||
|
||||
size_t xSize = edgeXPtsLow.size();
|
||||
size_t ySize = edgeYPtsLow.size();
|
||||
|
||||
std::vector<std::vector<cvf::Vec3d>> pts;
|
||||
|
||||
// Add low edge points
|
||||
pts.push_back( edgeXPtsLow );
|
||||
|
||||
// Interior points
|
||||
for ( size_t y = 1; y < ySize - 1; y++ )
|
||||
{
|
||||
auto interiorPts = splitLine( edgeYPtsLow[y], edgeYPtsHigh[y], xSize - 1 );
|
||||
pts.push_back( interiorPts );
|
||||
}
|
||||
|
||||
// Add low edge points
|
||||
pts.push_back( edgeXPtsHigh );
|
||||
return pts;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 <cvfVector3.h>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
class RiaCellDividingTools
|
||||
{
|
||||
public:
|
||||
static std::vector<cvf::Vec3d>
|
||||
createHexCornerCoords( std::array<cvf::Vec3d, 8> mainCellCorners, size_t nx, size_t ny, size_t nz );
|
||||
|
||||
static double computeFlowDistance( const std::array<cvf::Vec3d, 8>& cellVertices, const cvf::Vec3d& areaCenter );
|
||||
};
|
||||
@@ -0,0 +1,733 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaColorTables.h"
|
||||
#include "RiaColorTools.h"
|
||||
|
||||
#include "cvfAssert.h"
|
||||
|
||||
#include <QColor>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::normalPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{ cvf::Color3ub( 0, 0, 255 ),
|
||||
cvf::Color3ub( 0, 127, 255 ),
|
||||
cvf::Color3ub( 0, 255, 255 ),
|
||||
cvf::Color3ub( 0, 255, 0 ),
|
||||
cvf::Color3ub( 255, 255, 0 ),
|
||||
cvf::Color3ub( 255, 127, 0 ),
|
||||
cvf::Color3ub( 255, 0, 0 ) };
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::normalPaletteOppositeOrderingColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{ cvf::Color3ub( 255, 0, 0 ),
|
||||
cvf::Color3ub( 255, 127, 0 ),
|
||||
cvf::Color3ub( 255, 255, 0 ),
|
||||
cvf::Color3ub( 0, 255, 0 ),
|
||||
cvf::Color3ub( 0, 255, 255 ),
|
||||
cvf::Color3ub( 0, 127, 255 ),
|
||||
cvf::Color3ub( 0, 0, 255 ) };
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::blackWhitePaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{ cvf::Color3ub::BLACK, cvf::Color3ub::WHITE };
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::whiteBlackPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{ cvf::Color3ub::WHITE, cvf::Color3ub::BLACK };
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::pinkWhitePaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{ cvf::Color3ub::DEEP_PINK, cvf::Color3ub::WHITE };
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::whitePinkPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{ cvf::Color3ub::WHITE, cvf::Color3ub::DEEP_PINK };
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::blueWhiteRedPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{ cvf::Color3ub::BLUE, cvf::Color3ub::WHITE, cvf::Color3ub::RED };
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::redWhiteBluePaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{ cvf::Color3ub::RED, cvf::Color3ub::WHITE, cvf::Color3ub::BLUE };
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::categoryPaletteColors()
|
||||
{
|
||||
static caf::ColorTable colorTable = caf::ColorTable( categoryColors() );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::contrastCategoryPaletteColors()
|
||||
{
|
||||
static caf::ColorTable colorTable = caf::ColorTable( contrastCategoryColors() );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::tensorWhiteGrayBlackPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub::WHITE,
|
||||
cvf::Color3ub::LIGHT_GRAY,
|
||||
cvf::Color3ub::BLACK,
|
||||
};
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::tensorOrangeBlueWhitePaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 236, 118, 0 ), // Orange
|
||||
cvf::Color3ub( 56, 56, 255 ), // Vivid Blue
|
||||
cvf::Color3ub( 210, 248, 250 ), // White Turquoiseish
|
||||
};
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::tensorsMagentaBrownGrayPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 248, 0, 170 ), // Magenta
|
||||
cvf::Color3ub::BROWN,
|
||||
cvf::Color3ub::LIGHT_GRAY,
|
||||
};
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::angularPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{ cvf::Color3ub( 255, 0, 255 ),
|
||||
cvf::Color3ub( 0, 0, 255 ),
|
||||
cvf::Color3ub( 0, 127, 255 ),
|
||||
cvf::Color3ub( 0, 255, 255 ),
|
||||
cvf::Color3ub( 0, 255, 0 ),
|
||||
cvf::Color3ub( 255, 255, 0 ),
|
||||
cvf::Color3ub( 255, 127, 0 ),
|
||||
cvf::Color3ub( 255, 0, 0 ),
|
||||
cvf::Color3ub( 255, 0, 255 ) };
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::rainbowPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{ cvf::Color3ub::BLACK,
|
||||
cvf::Color3ub::MAGENTA,
|
||||
cvf::Color3ub::BLUE,
|
||||
cvf::Color3ub::CYAN,
|
||||
cvf::Color3ub::GREEN,
|
||||
cvf::Color3ub::RED,
|
||||
cvf::Color3ub::YELLOW,
|
||||
cvf::Color3ub::WHITE };
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::stimPlanPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 220, 220, 220 ), // Grey
|
||||
cvf::Color3ub( 0, 0, 255 ), // Blue
|
||||
cvf::Color3ub( 0, 128, 255 ), // Lighter blue
|
||||
cvf::Color3ub( 80, 240, 60 ), // Darker green
|
||||
cvf::Color3ub( 0, 255, 0 ), // Green
|
||||
cvf::Color3ub( 255, 255, 0 ), // Yellow
|
||||
cvf::Color3ub( 255, 192, 0 ), // Light orange
|
||||
cvf::Color3ub( 255, 128, 0 ), // Orange
|
||||
cvf::Color3ub( 255, 64, 0 ), // Red-orange
|
||||
cvf::Color3ub( 255, 0, 255 ) // Magenta
|
||||
};
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::faultsPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 101, 132, 96 ), // Dark green
|
||||
cvf::Color3ub( 255, 131, 140 ), // Old pink
|
||||
cvf::Color3ub( 210, 176, 112 ), // Light Brown
|
||||
cvf::Color3ub( 140, 171, 238 ), // Light gray blue
|
||||
cvf::Color3ub( 255, 205, 131 ), // Peach
|
||||
cvf::Color3ub( 220, 212, 166 ), // Dark off white
|
||||
cvf::Color3ub( 130, 255, 120 ), // Light green
|
||||
cvf::Color3ub( 166, 220, 215 ), // Light gray torquise
|
||||
cvf::Color3ub( 168, 220, 166 ), // Light gray green
|
||||
cvf::Color3ub( 255, 64, 236 ) // Magneta
|
||||
};
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::wellsPaletteColors()
|
||||
{
|
||||
return categoryPaletteColors();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::summaryCurveDefaultPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 0, 112, 136 ), // Dark Green-Blue
|
||||
cvf::Color3ub( 202, 0, 0 ), // Red
|
||||
cvf::Color3ub( 78, 204, 0 ), // Clear Green
|
||||
cvf::Color3ub( 236, 118, 0 ), // Orange
|
||||
cvf::Color3ub( 130, 130, 130 ), // Grey
|
||||
cvf::Color3ub( 56, 56, 255 ), // Vivid Blue
|
||||
cvf::Color3ub( 248, 0, 170 ), // Magenta
|
||||
cvf::Color3ub( 169, 2, 240 ), // Purple
|
||||
cvf::Color3ub( 0, 221, 221 ), // Turquoise
|
||||
cvf::Color3ub( 201, 168, 206 ), // Light Violet
|
||||
cvf::Color3ub( 0, 205, 68 ), // Bluish Green
|
||||
cvf::Color3ub( 236, 188, 0 ), // Mid Yellow
|
||||
cvf::Color3ub( 51, 204, 255 ), // Bluer Turquoise
|
||||
cvf::Color3ub( 164, 193, 0 ), // Mid Yellowish Green
|
||||
cvf::Color3ub( 0, 143, 239 ) // Dark Light Blue
|
||||
};
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::summaryCurveRedPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 202, 0, 0 ), // Off Red
|
||||
cvf::Color3ub( 255, 51, 51 ), // Bright Red
|
||||
cvf::Color3ub( 255, 102, 102 ) // Light Red
|
||||
};
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::summaryCurveGreenPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 78, 204, 0 ), // Clear Green
|
||||
cvf::Color3ub( 164, 193, 0 ), // Mid Yellowish Green
|
||||
cvf::Color3ub( 0, 205, 68 ) // Bluish Green
|
||||
};
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::summaryCurveBluePaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 56, 56, 255 ), // Vivid Blue
|
||||
cvf::Color3ub( 0, 143, 239 ), // Dark Light Blue
|
||||
cvf::Color3ub( 153, 153, 255 ) // Off Light Blue
|
||||
};
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::summaryCurveBrownPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 186, 101, 44 ),
|
||||
cvf::Color3ub( 99, 53, 23 ), // Highway Brown
|
||||
cvf::Color3ub( 103, 56, 24 ), // Dark Brown
|
||||
};
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::summaryCurveNoneRedGreenBlueBrownPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 236, 118, 0 ), // Orange
|
||||
cvf::Color3ub( 0, 0, 0 ), // Black
|
||||
cvf::Color3ub( 248, 0, 170 ), // Magenta
|
||||
cvf::Color3ub( 236, 188, 0 ), // Mid Yellow
|
||||
cvf::Color3ub( 169, 2, 240 ), // Purple
|
||||
cvf::Color3ub( 0, 221, 221 ), // Turquoise
|
||||
cvf::Color3ub( 201, 168, 206 ) // Light Violet
|
||||
};
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::wellLogPlotPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{ caf::ColorTable::fromQColor( QColor( "peru" ) ),
|
||||
caf::ColorTable::fromQColor( QColor( "blueviolet" ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::darkYellow ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::darkCyan ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::darkMagenta ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::darkGray ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::yellow ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::magenta ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::cyan ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::gray ) ),
|
||||
caf::ColorTable::fromQColor( QColor( "yellowgreen" ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::black ) ) };
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::selectionPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{ caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::magenta ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::cyan ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::blue ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::red ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::green ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::yellow ) ),
|
||||
caf::ColorTable::fromQColor( Qt::GlobalColor( Qt::gray ) ) };
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::timestepsPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 56, 56, 255 ), // Vivid Blue
|
||||
cvf::Color3ub( 0, 143, 239 ), // Dark Light Blue
|
||||
cvf::Color3ub( 0, 112, 136 ), // Dark Green-Blue
|
||||
cvf::Color3ub( 51, 204, 255 ), // Bluer Turquoise
|
||||
cvf::Color3ub( 0, 221, 221 ), // Turquoise
|
||||
cvf::Color3ub( 0, 205, 68 ), // Bluish Green
|
||||
cvf::Color3ub( 78, 204, 0 ), // Clear Green
|
||||
cvf::Color3ub( 164, 193, 0 ), // Mid Yellowish Green
|
||||
cvf::Color3ub( 236, 188, 0 ), // Mid Yellow
|
||||
cvf::Color3ub( 236, 118, 0 ), // Orange
|
||||
cvf::Color3ub( 202, 0, 0 ), // Red
|
||||
cvf::Color3ub( 248, 0, 170 ), // Magenta
|
||||
cvf::Color3ub( 201, 168, 206 ), // Light Violet
|
||||
cvf::Color3ub( 169, 2, 240 ), // Purple
|
||||
};
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::editableWellPathsPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 201, 145, 201 ), // Gray pink
|
||||
cvf::Color3ub( 173, 23, 212 ), // Strong Purple
|
||||
cvf::Color3ub( 143, 46, 219 ), // Purple
|
||||
cvf::Color3ub( 102, 76, 230 ), // Gray Blue
|
||||
cvf::Color3ub( 71, 99, 237 ), // Lighter Gray Blue
|
||||
cvf::Color3ub( 31, 130, 247 ), // Strong Blue
|
||||
cvf::Color3ub( 0, 153, 255 ), // Dark Turquise
|
||||
};
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::wellPathsPaletteColors()
|
||||
{
|
||||
// Use inverted category colors to avoid identical colors if we have few sim wells and few well paths
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( invertedCategoryColors() );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::waterAndRockPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 127, 205, 255 ), // Sea Blue
|
||||
cvf::Color3ub( 100, 100, 100 ) // Gray
|
||||
};
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::correlationPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 255, 25, 50 ), // Bluish red
|
||||
cvf::Color3ub( 240, 240, 240 ), // Light Gray
|
||||
cvf::Color3ub( 255, 100, 50 ), // Dark red Orange
|
||||
};
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RiaColorTables::undefinedCellColor()
|
||||
{
|
||||
return cvf::Color3::GRAY;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaColorTables::WellPathComponentColors RiaColorTables::wellPathComponentColors()
|
||||
{
|
||||
return { { RiaDefines::WellPathComponentType::WELL_PATH, cvf::Color3::CEETRON },
|
||||
{ RiaDefines::WellPathComponentType::PERFORATION_INTERVAL, cvf::Color3::DARK_MAGENTA },
|
||||
{ RiaDefines::WellPathComponentType::FISHBONES, cvf::Color3::DARK_GREEN },
|
||||
{ RiaDefines::WellPathComponentType::FRACTURE, cvf::Color3::CRIMSON },
|
||||
{ RiaDefines::WellPathComponentType::ICD, cvf::Color3::DARK_ORANGE },
|
||||
{ RiaDefines::WellPathComponentType::AICD, cvf::Color3::INDIGO },
|
||||
{ RiaDefines::WellPathComponentType::ICV, cvf::Color3::ORCHID },
|
||||
{ RiaDefines::WellPathComponentType::CASING, cvf::Color3::SEA_GREEN },
|
||||
{ RiaDefines::WellPathComponentType::LINER, cvf::Color3::OLIVE },
|
||||
{ RiaDefines::WellPathComponentType::PACKER, cvf::Color3::GRAY },
|
||||
{ RiaDefines::WellPathComponentType::UNDEFINED_COMPONENT, cvf::Color3::MAGENTA } };
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RiaColorTables::defaultGridLineColor()
|
||||
{
|
||||
return cvf::Color3f( 0.92f, 0.92f, 0.92f );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RiaColorTables::defaultFaultLineColor()
|
||||
{
|
||||
return cvf::Color3f( 0.08f, 0.08f, 0.08f );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RiaColorTables::defaultWellLabelColor()
|
||||
{
|
||||
return cvf::Color3f( 0.92f, 0.92f, 0.92f );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RiaColorTables::defaultViewerBackgroundColor()
|
||||
{
|
||||
return cvf::Color3f( 0.69f, 0.77f, 0.87f );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
caf::ColorTable RiaColorTables::createBrightnessBasedColorTable( cvf::Color3ub baseColor, int brightnessLevelCount )
|
||||
{
|
||||
CVF_ASSERT( brightnessLevelCount >= 1 );
|
||||
QColor baseRGB( baseColor.r(), baseColor.g(), baseColor.b() );
|
||||
float hueF = baseRGB.hslHueF();
|
||||
float satF = baseRGB.hslSaturationF();
|
||||
|
||||
std::vector<cvf::Color3ub> colors;
|
||||
if ( brightnessLevelCount == 1 )
|
||||
{
|
||||
colors.push_back( cvf::Color3ub( RiaColorTools::fromQColorTo3f( QColor::fromHslF( hueF, satF, 0.5 ) ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( int i = 0; i < brightnessLevelCount; ++i )
|
||||
{
|
||||
float brightness = static_cast<float>( i ) / static_cast<float>( brightnessLevelCount - 1 );
|
||||
colors.push_back( cvf::Color3ub( RiaColorTools::fromQColorTo3f( QColor::fromHslF( hueF, satF, brightness ) ) ) );
|
||||
}
|
||||
}
|
||||
return caf::ColorTable( colors );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::map<RiaDefines::PhaseType, caf::ColorTable> RiaColorTables::phaseColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> waterColors{ cvf::Color3ub( cvf::Color3::DARK_BLUE ),
|
||||
cvf::Color3ub( cvf::Color3::SKY_BLUE ) };
|
||||
static std::vector<cvf::Color3ub> gasColors{ cvf::Color3ub( cvf::Color3::DARK_RED ),
|
||||
cvf::Color3ub( cvf::Color3::PINK ) };
|
||||
static std::vector<cvf::Color3ub> oilColors{ cvf::Color3ub( cvf::Color3::DARK_GREEN ),
|
||||
cvf::Color3ub( cvf::Color3::YELLOW_GREEN ) };
|
||||
|
||||
return { { RiaDefines::PhaseType::WATER_PHASE, caf::ColorTable( waterColors ) },
|
||||
{ RiaDefines::PhaseType::GAS_PHASE, caf::ColorTable( gasColors ) },
|
||||
{ RiaDefines::PhaseType::OIL_PHASE, caf::ColorTable( oilColors ) } };
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<cvf::Color3ub> RiaColorTables::categoryColors()
|
||||
{
|
||||
// Based on http://stackoverflow.com/questions/470690/how-to-automatically-generate-n-distinct-colors
|
||||
// and Kelly Colors and sorted by hue
|
||||
// See also http://www.w3schools.com/colors/ for palettes etc.
|
||||
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 128, 62, 117 ), // hwb(310, 24%, 50%) strong_purple
|
||||
cvf::Color3ub( 212, 28, 132 ), // hwb(326, 11%, 17%) strong_purplish_red
|
||||
cvf::Color3ub( 246, 118, 142 ), // hwb(349, 46%, 4%) strong_purplish_pink
|
||||
cvf::Color3ub( 193, 0, 32 ), // hwb(350, 0%, 24%) vivid_red
|
||||
cvf::Color3ub( 127, 24, 13 ), // hwb( 6, 5%, 50%) strong_reddish_brown
|
||||
cvf::Color3ub( 241, 58, 19 ), // hwb( 11, 7%, 5%) vivid_reddish_orange
|
||||
cvf::Color3ub( 255, 122, 92 ), // hwb( 11, 36%, 0%) strong_yellowish_pink
|
||||
cvf::Color3ub( 129, 112, 102 ), // hwb( 22, 40%, 49%) medium_gray
|
||||
cvf::Color3ub( 255, 104, 0 ), // hwb( 24, 0%, 0%) vivid_orange
|
||||
cvf::Color3ub( 89, 51, 21 ), // hwb( 26, 8%, 65%) deep_yellowish_brown
|
||||
cvf::Color3ub( 255, 142, 0 ), // hwb( 33, 0%, 0%) vivid_orange_yellow
|
||||
cvf::Color3ub( 206, 162, 98 ), // hwb( 36, 38%, 19%) grayish_yellow
|
||||
cvf::Color3ub( 244, 200, 0 ), // hwb( 49, 0%, 4%) vivid_greenish_yellow
|
||||
cvf::Color3ub( 147, 170, 0 ), // hwb( 68, 0%, 33%) vivid_yellowish_green
|
||||
cvf::Color3ub( 59, 84, 23 ), // hwb( 85, 9%, 67%) dark_olive_green
|
||||
cvf::Color3ub( 0, 125, 52 ), // hwb(145, 0%, 51%) vivid_green
|
||||
cvf::Color3ub( 54, 125, 123 ), // hwb(178, 21%, 51%) vivid_blueish_green
|
||||
cvf::Color3ub( 0, 83, 138 ), // hwb(204, 0%, 46%) strong_blue
|
||||
cvf::Color3ub( 166, 189, 215 ), // hwb(212, 65%, 16%) very_light_blue
|
||||
cvf::Color3ub( 46, 76, 224 ) // hwb(230, 18%, 12%) medium_blue
|
||||
};
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<cvf::Color3ub> RiaColorTables::contrastCategoryColors()
|
||||
{
|
||||
// Based on http://stackoverflow.com/questions/470690/how-to-automatically-generate-n-distinct-colors
|
||||
// and Kelly Colors and sorted by hue
|
||||
// See also http://www.w3schools.com/colors/ for palettes etc.
|
||||
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 244, 200, 0 ), // hwb( 49, 0%, 4%) vivid_greenish_yellow
|
||||
cvf::Color3ub( 128, 62, 117 ), // hwb(310, 24%, 50%) strong_purple
|
||||
cvf::Color3ub( 255, 104, 0 ), // hwb( 24, 0%, 0%) vivid_orange
|
||||
cvf::Color3ub( 166, 189, 215 ), // hwb(212, 65%, 16%) very_light_blue
|
||||
cvf::Color3ub( 193, 0, 32 ), // hwb(350, 0%, 24%) vivid_red
|
||||
cvf::Color3ub( 206, 162, 98 ), // hwb( 36, 38%, 19%) grayish_yellow
|
||||
cvf::Color3ub( 129, 112, 102 ), // hwb( 22, 40%, 49%) medium_gray
|
||||
cvf::Color3ub( 0, 125, 52 ), // hwb(145, 0%, 51%) vivid_green
|
||||
cvf::Color3ub( 246, 118, 142 ), // hwb(349, 46%, 4%) strong_purplish_pink
|
||||
cvf::Color3ub( 0, 83, 138 ), // hwb(204, 0%, 46%) strong_blue
|
||||
cvf::Color3ub( 255, 122, 92 ), // hwb( 11, 36%, 0%) strong_yellowish_pink
|
||||
cvf::Color3ub( 212, 28, 132 ), // hwb(326, 11%, 17%) strong_purplish_red
|
||||
cvf::Color3ub( 255, 142, 0 ), // hwb( 33, 0%, 0%) vivid_orange_yellow
|
||||
cvf::Color3ub( 59, 84, 23 ), // hwb( 85, 9%, 67%) dark_olive_green
|
||||
cvf::Color3ub( 127, 24, 13 ), // hwb( 6, 5%, 50%) strong_reddish_brown
|
||||
cvf::Color3ub( 54, 125, 123 ), // hwb(178, 21%, 51%) vivid_blueish_green
|
||||
cvf::Color3ub( 241, 58, 19 ), // hwb( 11, 7%, 5%) vivid_reddish_orange
|
||||
cvf::Color3ub( 147, 170, 0 ), // hwb( 68, 0%, 33%) vivid_yellowish_green
|
||||
cvf::Color3ub( 46, 76, 224 ), // hwb(230, 18%, 12%) medium_blue
|
||||
cvf::Color3ub( 89, 51, 21 ), // hwb( 26, 8%, 65%) deep_yellowish_brown
|
||||
cvf::Color3ub( 0, 0, 0 ) // hwb(0, 0%, 100%) black
|
||||
};
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<cvf::Color3ub> RiaColorTables::invertedCategoryColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{
|
||||
cvf::Color3ub( 46, 76, 224 ), // hwb(230, 18%, 12%) medium_blue
|
||||
cvf::Color3ub( 166, 189, 215 ), // hwb(212, 65%, 16%) very_light_blue
|
||||
cvf::Color3ub( 0, 83, 138 ), // hwb(204, 0%, 46%) strong_blue
|
||||
cvf::Color3ub( 54, 125, 123 ), // hwb(178, 21%, 51%) vivid_blueish_green
|
||||
cvf::Color3ub( 0, 125, 52 ), // hwb(145, 0%, 51%) vivid_green
|
||||
cvf::Color3ub( 59, 84, 23 ), // hwb( 85, 9%, 67%) dark_olive_green
|
||||
cvf::Color3ub( 147, 170, 0 ), // hwb( 68, 0%, 33%) vivid_yellowish_green
|
||||
cvf::Color3ub( 244, 200, 0 ), // hwb( 49, 0%, 4%) vivid_greenish_yellow
|
||||
cvf::Color3ub( 206, 162, 98 ), // hwb( 36, 38%, 19%) grayish_yellow
|
||||
cvf::Color3ub( 255, 142, 0 ), // hwb( 33, 0%, 0%) vivid_orange_yellow
|
||||
cvf::Color3ub( 89, 51, 21 ), // hwb( 26, 8%, 65%) deep_yellowish_brown
|
||||
cvf::Color3ub( 255, 104, 0 ), // hwb( 24, 0%, 0%) vivid_orange
|
||||
cvf::Color3ub( 129, 112, 102 ), // hwb( 22, 40%, 49%) medium_gray
|
||||
cvf::Color3ub( 255, 122, 92 ), // hwb( 11, 36%, 0%) strong_yellowish_pink
|
||||
cvf::Color3ub( 241, 58, 19 ), // hwb( 11, 7%, 5%) vivid_reddish_orange
|
||||
cvf::Color3ub( 127, 24, 13 ), // hwb( 6, 5%, 50%) strong_reddish_brown
|
||||
cvf::Color3ub( 193, 0, 32 ), // hwb(350, 0%, 24%) vivid_red
|
||||
cvf::Color3ub( 246, 118, 142 ), // hwb(349, 46%, 4%) strong_purplish_pink
|
||||
cvf::Color3ub( 212, 28, 132 ), // hwb(326, 11%, 17%) strong_purplish_red
|
||||
cvf::Color3ub( 128, 62, 117 ) // hwb(310, 24%, 50%) strong_purple
|
||||
};
|
||||
|
||||
return colors;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaDefines.h"
|
||||
#include "cafColorTable.h"
|
||||
#include <map>
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
///
|
||||
//==================================================================================================
|
||||
class RiaColorTables
|
||||
{
|
||||
public:
|
||||
typedef std::map<RiaDefines::WellPathComponentType, cvf::Color3::ColorIdent> WellPathComponentColors;
|
||||
|
||||
static const caf::ColorTable& normalPaletteColors();
|
||||
static const caf::ColorTable& normalPaletteOppositeOrderingColors();
|
||||
static const caf::ColorTable& blackWhitePaletteColors();
|
||||
static const caf::ColorTable& whiteBlackPaletteColors();
|
||||
static const caf::ColorTable& pinkWhitePaletteColors();
|
||||
static const caf::ColorTable& whitePinkPaletteColors();
|
||||
static const caf::ColorTable& blueWhiteRedPaletteColors();
|
||||
static const caf::ColorTable& redWhiteBluePaletteColors();
|
||||
static const caf::ColorTable& categoryPaletteColors();
|
||||
static const caf::ColorTable& contrastCategoryPaletteColors();
|
||||
static const caf::ColorTable& tensorWhiteGrayBlackPaletteColors();
|
||||
static const caf::ColorTable& tensorOrangeBlueWhitePaletteColors();
|
||||
static const caf::ColorTable& tensorsMagentaBrownGrayPaletteColors();
|
||||
static const caf::ColorTable& angularPaletteColors();
|
||||
static const caf::ColorTable& rainbowPaletteColors();
|
||||
static const caf::ColorTable& stimPlanPaletteColors();
|
||||
static const caf::ColorTable& faultsPaletteColors();
|
||||
static const caf::ColorTable& wellsPaletteColors();
|
||||
static const caf::ColorTable& summaryCurveDefaultPaletteColors();
|
||||
static const caf::ColorTable& summaryCurveRedPaletteColors();
|
||||
static const caf::ColorTable& summaryCurveGreenPaletteColors();
|
||||
static const caf::ColorTable& summaryCurveBluePaletteColors();
|
||||
static const caf::ColorTable& summaryCurveBrownPaletteColors();
|
||||
static const caf::ColorTable& summaryCurveNoneRedGreenBlueBrownPaletteColors();
|
||||
static const caf::ColorTable& wellLogPlotPaletteColors();
|
||||
static const caf::ColorTable& selectionPaletteColors();
|
||||
static const caf::ColorTable& timestepsPaletteColors();
|
||||
static const caf::ColorTable& editableWellPathsPaletteColors();
|
||||
static const caf::ColorTable& wellPathsPaletteColors();
|
||||
static const caf::ColorTable& waterAndRockPaletteColors();
|
||||
static const caf::ColorTable& correlationPaletteColors();
|
||||
|
||||
static cvf::Color3f undefinedCellColor();
|
||||
|
||||
static WellPathComponentColors wellPathComponentColors();
|
||||
|
||||
// Default 3d View colors
|
||||
static cvf::Color3f defaultGridLineColor();
|
||||
static cvf::Color3f defaultFaultLineColor();
|
||||
static cvf::Color3f defaultWellLabelColor();
|
||||
static cvf::Color3f defaultViewerBackgroundColor();
|
||||
|
||||
static caf::ColorTable createBrightnessBasedColorTable( cvf::Color3ub baseColor, int brightnessLevelCount );
|
||||
|
||||
static std::map<RiaDefines::PhaseType, caf::ColorTable> phaseColors();
|
||||
|
||||
private:
|
||||
static std::vector<cvf::Color3ub> categoryColors();
|
||||
static std::vector<cvf::Color3ub> contrastCategoryColors();
|
||||
static std::vector<cvf::Color3ub> invertedCategoryColors();
|
||||
};
|
||||
@@ -0,0 +1,209 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- Equinor ASA
|
||||
// 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 "RiaColorTools.h"
|
||||
#include "RiuGuiTheme.h"
|
||||
|
||||
#include "cvfAssert.h"
|
||||
#include "cvfMath.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include <QPalette>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Uses W3.org relative luminance calculation taking into account the different luminance of the different colors
|
||||
/// https://www.w3.org/TR/WCAG20-TECHS/G18.html
|
||||
/// Luminance is between [0, 1] so anything above 0.5 is considered in the bright half of the spectrum.
|
||||
/// However, subjectively the contrast looks better if the threshold is to 0.4 so black contrast is used a bit more
|
||||
/// often.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaColorTools::isBrightnessAboveThreshold( cvf::Color3f backgroundColor )
|
||||
{
|
||||
if ( relativeLuminance( backgroundColor ) > 0.4 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RiaColorTools::computeOffsetColor( cvf::Color3f color, float offsetFactor )
|
||||
{
|
||||
float gridR = 0.0;
|
||||
float gridG = 0.0;
|
||||
float gridB = 0.0;
|
||||
|
||||
if ( isBrightnessAboveThreshold( color ) )
|
||||
{
|
||||
gridR = color.r() - ( color.r() * offsetFactor );
|
||||
gridG = color.g() - ( color.g() * offsetFactor );
|
||||
gridB = color.b() - ( color.b() * offsetFactor );
|
||||
}
|
||||
else
|
||||
{
|
||||
gridR = color.r() + ( 1.0f - color.r() ) * offsetFactor;
|
||||
gridG = color.g() + ( 1.0f - color.g() ) * offsetFactor;
|
||||
gridB = color.b() + ( 1.0f - color.b() ) * offsetFactor;
|
||||
}
|
||||
|
||||
return cvf::Color3f( cvf::Math::clamp( gridR, 0.0f, 1.0f ),
|
||||
cvf::Math::clamp( gridG, 0.0f, 1.0f ),
|
||||
cvf::Math::clamp( gridB, 0.0f, 1.0f ) );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RiaColorTools::darkContrastColor()
|
||||
{
|
||||
return cvf::Color3f::fromByteColor( 10, 10, 10 );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RiaColorTools::brightContrastColor()
|
||||
{
|
||||
return cvf::Color3f::WHITE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RiaColorTools::darkContrastColorSofter()
|
||||
{
|
||||
return cvf::Color3f::fromByteColor( 30, 30, 30 );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RiaColorTools::brightContrastColorSofter()
|
||||
{
|
||||
return cvf::Color3f::fromByteColor( 200, 200, 200 );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RiaColorTools::contrastColor( cvf::Color3f backgroundColor, bool softerContrast )
|
||||
{
|
||||
if ( isBrightnessAboveThreshold( backgroundColor ) )
|
||||
{
|
||||
if ( softerContrast ) return darkContrastColorSofter();
|
||||
return darkContrastColor();
|
||||
}
|
||||
if ( softerContrast ) return brightContrastColorSofter();
|
||||
return brightContrastColor();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QColor RiaColorTools::toQColor( cvf::Color3f color, float alpha )
|
||||
{
|
||||
QColor qcolor( color.rByte(), color.gByte(), color.bByte() );
|
||||
qcolor.setAlphaF( alpha );
|
||||
return qcolor;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QColor RiaColorTools::toQColor( cvf::Color4f color )
|
||||
{
|
||||
return toQColor( color.toColor3f(), color.a() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RiaColorTools::fromQColorTo3f( QColor color )
|
||||
{
|
||||
return cvf::Color3f( color.redF(), color.greenF(), color.blueF() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QColor RiaColorTools::textColor()
|
||||
{
|
||||
return RiuGuiTheme::getColorByVariableName( "textColor" );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RiaColorTools::textColor3f()
|
||||
{
|
||||
return fromQColorTo3f( textColor() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::Color3f RiaColorTools::blendCvfColors( const cvf::Color3f& color1,
|
||||
const cvf::Color3f& color2,
|
||||
int weight1 /*= 1*/,
|
||||
int weight2 /*= 1*/ )
|
||||
{
|
||||
CVF_ASSERT( weight1 > 0 && weight2 > 0 );
|
||||
int weightsum = weight1 + weight2;
|
||||
return cvf::Color3f( ( color1.r() * weight1 + color2.r() * weight2 ) / weightsum,
|
||||
( color1.g() * weight1 + color2.g() * weight2 ) / weightsum,
|
||||
( color1.b() * weight1 + color2.b() * weight2 ) / weightsum );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QColor RiaColorTools::blendQColors( const QColor& color1, const QColor& color2, int weight1 /*= 1*/, int weight2 /*= 1*/ )
|
||||
{
|
||||
CVF_ASSERT( weight1 > 0 && weight2 > 0 );
|
||||
int weightsum = weight1 + weight2;
|
||||
return QColor( ( color1.red() * weight1 + color2.red() * weight2 ) / weightsum,
|
||||
( color1.green() * weight1 + color2.green() * weight2 ) / weightsum,
|
||||
( color1.blue() * weight1 + color2.blue() * weight2 ) / weightsum );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
float RiaColorTools::relativeLuminance( cvf::Color3f backgroundColor )
|
||||
{
|
||||
float R = calculateNonLinearColorValue( backgroundColor.r() );
|
||||
float G = calculateNonLinearColorValue( backgroundColor.g() );
|
||||
float B = calculateNonLinearColorValue( backgroundColor.b() );
|
||||
|
||||
double luminance = 0.2126 * R + 0.7152 * G + 0.0722 * B;
|
||||
return luminance;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
float RiaColorTools::calculateNonLinearColorValue( float colorFraction )
|
||||
{
|
||||
return colorFraction <= 0.03928 ? colorFraction / 12.92 : std::pow( ( colorFraction + 0.055 ) / 1.055, 2.4 );
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- Equinor ASA
|
||||
// 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 "cvfArray.h"
|
||||
|
||||
#include <QColor>
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
///
|
||||
//==================================================================================================
|
||||
class RiaColorTools
|
||||
{
|
||||
public:
|
||||
static bool isBrightnessAboveThreshold( cvf::Color3f backgroundColor );
|
||||
|
||||
static cvf::Color3f computeOffsetColor( cvf::Color3f color, float offsetFactor );
|
||||
static cvf::Color3f darkContrastColor();
|
||||
static cvf::Color3f brightContrastColor();
|
||||
static cvf::Color3f darkContrastColorSofter();
|
||||
static cvf::Color3f brightContrastColorSofter();
|
||||
static cvf::Color3f contrastColor( cvf::Color3f backgroundColor, bool softerContrast = false );
|
||||
static QColor toQColor( cvf::Color3f color, float alpha = 1.0f );
|
||||
static QColor toQColor( cvf::Color4f color );
|
||||
static cvf::Color3f fromQColorTo3f( QColor );
|
||||
|
||||
static QColor textColor();
|
||||
static cvf::Color3f textColor3f();
|
||||
|
||||
static cvf::Color3f
|
||||
blendCvfColors( const cvf::Color3f& color1, const cvf::Color3f& color2, int weight1 = 1, int weight2 = 1 );
|
||||
static QColor blendQColors( const QColor& color1, const QColor& color2, int weight1 = 1, int weight2 = 1 );
|
||||
|
||||
private:
|
||||
static float relativeLuminance( cvf::Color3f backgroundColor );
|
||||
static float calculateNonLinearColorValue( float colorFraction );
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2015- Statoil ASA
|
||||
// Copyright (C) 2015- Ceetron Solutions AS
|
||||
//
|
||||
// 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 "RiaCurveDataTools.h"
|
||||
|
||||
#include <cmath> // Needed for HUGE_VAL on Linux
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaCurveDataTools::CurveIntervals RiaCurveDataTools::calculateIntervalsOfValidValues( const std::vector<double>& values,
|
||||
bool includePositiveValuesOnly )
|
||||
{
|
||||
CurveIntervals intervals;
|
||||
|
||||
int startIdx = -1;
|
||||
size_t vIdx = 0;
|
||||
|
||||
size_t valueCount = values.size();
|
||||
while ( vIdx < valueCount )
|
||||
{
|
||||
bool isValid = RiaCurveDataTools::isValidValue( values[vIdx], includePositiveValuesOnly );
|
||||
|
||||
if ( !isValid )
|
||||
{
|
||||
if ( startIdx >= 0 )
|
||||
{
|
||||
size_t endIdx = vIdx - 1;
|
||||
intervals.push_back( std::make_pair( startIdx, endIdx ) );
|
||||
startIdx = -1;
|
||||
}
|
||||
}
|
||||
else if ( startIdx < 0 )
|
||||
{
|
||||
startIdx = (int)vIdx;
|
||||
}
|
||||
|
||||
vIdx++;
|
||||
}
|
||||
|
||||
if ( startIdx >= 0 && startIdx < ( (int)valueCount ) )
|
||||
{
|
||||
intervals.push_back( std::make_pair( startIdx, valueCount - 1 ) );
|
||||
}
|
||||
|
||||
return intervals;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<std::pair<size_t, size_t>> RiaCurveDataTools::computePolyLineStartStopIndices( const CurveIntervals& intervals )
|
||||
{
|
||||
std::vector<std::pair<size_t, size_t>> lineStartAndStopIndices;
|
||||
|
||||
const size_t intervalCount = intervals.size();
|
||||
if ( intervalCount < 1 ) return lineStartAndStopIndices;
|
||||
|
||||
size_t index = 0;
|
||||
for ( size_t intIdx = 0; intIdx < intervalCount; intIdx++ )
|
||||
{
|
||||
size_t intervalSize = intervals[intIdx].second - intervals[intIdx].first + 1;
|
||||
lineStartAndStopIndices.push_back( std::make_pair( index, index + intervalSize - 1 ) );
|
||||
|
||||
index += intervalSize;
|
||||
}
|
||||
|
||||
return lineStartAndStopIndices;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaCurveDataTools::isValidValue( double value, bool allowPositiveValuesOnly )
|
||||
{
|
||||
if ( value == HUGE_VAL || value == -HUGE_VAL || value != value )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( allowPositiveValuesOnly && value <= 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2015- Statoil ASA
|
||||
// Copyright (C) 2015- Ceetron Solutions AS
|
||||
//
|
||||
// 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 "cvfAssert.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class QDateTime;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RiaCurveDataTools
|
||||
{
|
||||
public:
|
||||
typedef std::vector<std::pair<size_t, size_t>> CurveIntervals;
|
||||
|
||||
enum class ErrorAxis
|
||||
{
|
||||
ERROR_ALONG_X_AXIS,
|
||||
ERROR_ALONG_Y_AXIS
|
||||
};
|
||||
|
||||
public:
|
||||
static CurveIntervals calculateIntervalsOfValidValues( const std::vector<double>& values,
|
||||
bool includePositiveValuesOnly );
|
||||
|
||||
template <typename T>
|
||||
static void
|
||||
getValuesByIntervals( const std::vector<T>& values, const CurveIntervals& intervals, std::vector<T>* filteredValues )
|
||||
{
|
||||
CVF_ASSERT( filteredValues );
|
||||
|
||||
for ( size_t intIdx = 0; intIdx < intervals.size(); intIdx++ )
|
||||
{
|
||||
for ( size_t vIdx = intervals[intIdx].first; vIdx <= intervals[intIdx].second; vIdx++ )
|
||||
{
|
||||
filteredValues->push_back( values[vIdx] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<std::pair<size_t, size_t>> computePolyLineStartStopIndices( const CurveIntervals& intervals );
|
||||
|
||||
public:
|
||||
static bool isValidValue( double value, bool allowPositiveValuesOnly );
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "RiaCurveMerger.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <time.h>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <>
|
||||
bool XValueComparator<double>::equals( const double& lhs, const double& rhs )
|
||||
{
|
||||
double eps = 1.0e-12 * std::max( std::fabs( lhs ), std::fabs( rhs ) );
|
||||
return std::fabs( lhs - rhs ) < eps;
|
||||
}
|
||||
|
||||
template <>
|
||||
double XValueComparator<time_t>::diff( const time_t& lhs, const time_t& rhs )
|
||||
{
|
||||
return difftime( lhs, rhs );
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaCurveDataTools.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
template <typename XValueType>
|
||||
class XValueComparator
|
||||
{
|
||||
public:
|
||||
bool operator()( const XValueType& lhs, const XValueType& rhs ) const;
|
||||
static bool equals( const XValueType& lhs, const XValueType& rhs );
|
||||
static double diff( const XValueType& lhs, const XValueType& rhs );
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
template <typename XValueType>
|
||||
class RiaCurveMerger
|
||||
{
|
||||
public:
|
||||
typedef XValueComparator<XValueType> XComparator;
|
||||
RiaCurveMerger();
|
||||
|
||||
void addCurveData( const std::vector<XValueType>& xValues, const std::vector<double>& yValues );
|
||||
size_t curveCount() const;
|
||||
|
||||
void computeInterpolatedValues( bool includeValuesFromPartialCurves = true );
|
||||
|
||||
RiaCurveDataTools::CurveIntervals validIntervalsForAllXValues() const;
|
||||
const std::vector<XValueType>& allXValues() const;
|
||||
const std::vector<double>& interpolatedYValuesForAllXValues( size_t curveIdx ) const;
|
||||
|
||||
// Non-const access is not required by any clients, but the expression parser has no available const interface
|
||||
// for specifying a data source for an expression variable. Allow non-const access to avoid copy of the contained
|
||||
// values, interpolated for all time steps
|
||||
//
|
||||
// See ExpressionParserImpl::assignVector()
|
||||
std::vector<double>& interpolatedYValuesForAllXValues( size_t curveIdx );
|
||||
|
||||
public:
|
||||
// Helper methods, available as public to be able to access from unit tests
|
||||
|
||||
static double interpolatedYValue( const XValueType& xValue,
|
||||
const std::vector<XValueType>& curveXValues,
|
||||
const std::vector<double>& curveYValues );
|
||||
|
||||
private:
|
||||
void computeUnionOfXValues( bool includeValuesFromPartialCurves );
|
||||
|
||||
private:
|
||||
std::vector<std::pair<std::vector<XValueType>, std::vector<double>>> m_originalValues;
|
||||
|
||||
RiaCurveDataTools::CurveIntervals m_validIntervalsForAllXValues;
|
||||
|
||||
std::vector<XValueType> m_allXValues;
|
||||
std::vector<std::vector<double>> m_interpolatedValuesForAllCurves;
|
||||
};
|
||||
|
||||
typedef RiaCurveMerger<time_t> RiaTimeHistoryCurveMerger;
|
||||
|
||||
template <>
|
||||
bool XValueComparator<double>::equals( const double& lhs, const double& rhs );
|
||||
template <>
|
||||
double XValueComparator<time_t>::diff( const time_t& lhs, const time_t& rhs );
|
||||
|
||||
#include "RiaCurveMerger.inl"
|
||||
@@ -0,0 +1,291 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 <algorithm>
|
||||
#include <cmath> // Needed for HUGE_VAL on Linux
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
bool XValueComparator<XValueType>::operator()( const XValueType& lhs, const XValueType& rhs ) const
|
||||
{
|
||||
if ( XValueComparator<XValueType>::equals( lhs, rhs ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return lhs < rhs;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
double XValueComparator<XValueType>::diff( const XValueType& lhs, const XValueType& rhs )
|
||||
{
|
||||
return lhs - rhs;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
bool XValueComparator<XValueType>::equals( const XValueType& lhs, const XValueType& rhs )
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
RiaCurveMerger<XValueType>::RiaCurveMerger()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
void RiaCurveMerger<XValueType>::addCurveData( const std::vector<XValueType>& xValues, const std::vector<double>& yValues )
|
||||
{
|
||||
CVF_ASSERT( xValues.size() == yValues.size() );
|
||||
|
||||
if ( !xValues.empty() )
|
||||
{
|
||||
m_originalValues.push_back( std::make_pair( xValues, yValues ) );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
size_t RiaCurveMerger<XValueType>::curveCount() const
|
||||
{
|
||||
return m_interpolatedValuesForAllCurves.size();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
RiaCurveDataTools::CurveIntervals RiaCurveMerger<XValueType>::validIntervalsForAllXValues() const
|
||||
{
|
||||
return m_validIntervalsForAllXValues;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
const std::vector<XValueType>& RiaCurveMerger<XValueType>::allXValues() const
|
||||
{
|
||||
return m_allXValues;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
const std::vector<double>& RiaCurveMerger<XValueType>::interpolatedYValuesForAllXValues( size_t curveIdx ) const
|
||||
{
|
||||
CVF_ASSERT( curveIdx < m_interpolatedValuesForAllCurves.size() );
|
||||
|
||||
return m_interpolatedValuesForAllCurves[curveIdx];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
std::vector<double>& RiaCurveMerger<XValueType>::interpolatedYValuesForAllXValues( size_t curveIdx )
|
||||
{
|
||||
CVF_ASSERT( curveIdx < m_interpolatedValuesForAllCurves.size() );
|
||||
|
||||
return m_interpolatedValuesForAllCurves[curveIdx];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
void RiaCurveMerger<XValueType>::computeInterpolatedValues( bool includeValuesFromPartialCurves )
|
||||
{
|
||||
m_validIntervalsForAllXValues.clear();
|
||||
m_allXValues.clear();
|
||||
m_interpolatedValuesForAllCurves.clear();
|
||||
|
||||
computeUnionOfXValues( includeValuesFromPartialCurves );
|
||||
|
||||
const size_t curveCount = m_originalValues.size();
|
||||
if ( curveCount == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t dataValueCount = m_allXValues.size();
|
||||
if ( dataValueCount == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_interpolatedValuesForAllCurves.resize( curveCount );
|
||||
|
||||
std::vector<double> accumulatedValidValues( dataValueCount, 1.0 );
|
||||
|
||||
for ( size_t curveIdx = 0; curveIdx < curveCount; curveIdx++ )
|
||||
{
|
||||
std::vector<double>& curveValues = m_interpolatedValuesForAllCurves[curveIdx];
|
||||
curveValues.resize( dataValueCount );
|
||||
|
||||
for ( size_t valueIndex = 0; valueIndex < dataValueCount; valueIndex++ )
|
||||
{
|
||||
double interpolValue = interpolatedYValue( m_allXValues[valueIndex],
|
||||
m_originalValues[curveIdx].first,
|
||||
m_originalValues[curveIdx].second );
|
||||
if ( !RiaCurveDataTools::isValidValue( interpolValue, false ) )
|
||||
{
|
||||
accumulatedValidValues[valueIndex] = HUGE_VAL;
|
||||
}
|
||||
|
||||
curveValues[valueIndex] = interpolValue;
|
||||
}
|
||||
}
|
||||
|
||||
m_validIntervalsForAllXValues = RiaCurveDataTools::calculateIntervalsOfValidValues( accumulatedValidValues, false );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
void RiaCurveMerger<XValueType>::computeUnionOfXValues( bool includeValuesForPartialCurves )
|
||||
{
|
||||
m_allXValues.clear();
|
||||
|
||||
std::set<XValueType, XComparator> unionOfXValues;
|
||||
|
||||
std::vector<std::pair<XValueType, XValueType>> originalXBounds;
|
||||
for ( const auto& curveData : m_originalValues )
|
||||
{
|
||||
if ( curveData.first.empty() ) continue;
|
||||
|
||||
for ( const auto& x : curveData.first )
|
||||
{
|
||||
unionOfXValues.insert( x );
|
||||
}
|
||||
auto minmax_it = std::minmax_element( curveData.first.begin(), curveData.first.end() );
|
||||
originalXBounds.push_back( std::make_pair( *( minmax_it.first ), *( minmax_it.second ) ) );
|
||||
}
|
||||
|
||||
if ( !includeValuesForPartialCurves )
|
||||
{
|
||||
for ( auto it = unionOfXValues.begin(); it != unionOfXValues.end(); )
|
||||
{
|
||||
bool outsideBounds = false;
|
||||
for ( const auto& curveXBounds : originalXBounds )
|
||||
{
|
||||
if ( *it < curveXBounds.first || *it > curveXBounds.second )
|
||||
{
|
||||
outsideBounds = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( outsideBounds )
|
||||
{
|
||||
it = unionOfXValues.erase( it );
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_allXValues = std::vector<XValueType>( unionOfXValues.begin(), unionOfXValues.end() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
double RiaCurveMerger<XValueType>::interpolatedYValue( const XValueType& interpolationXValue,
|
||||
const std::vector<XValueType>& xValues,
|
||||
const std::vector<double>& yValues )
|
||||
{
|
||||
if ( yValues.size() != xValues.size() ) return HUGE_VAL;
|
||||
|
||||
const bool removeInterpolatedValues = false;
|
||||
|
||||
for ( size_t firstI = 0; firstI < xValues.size(); firstI++ )
|
||||
{
|
||||
if ( XComparator::equals( xValues.at( firstI ), interpolationXValue ) )
|
||||
{
|
||||
const double& firstValue = yValues.at( firstI );
|
||||
if ( !RiaCurveDataTools::isValidValue( firstValue, removeInterpolatedValues ) )
|
||||
{
|
||||
return HUGE_VAL;
|
||||
}
|
||||
|
||||
return firstValue;
|
||||
}
|
||||
|
||||
size_t secondI = firstI + 1;
|
||||
|
||||
if ( secondI < xValues.size() )
|
||||
{
|
||||
if ( XComparator::equals( xValues.at( secondI ), interpolationXValue ) )
|
||||
{
|
||||
const double& secondValue = yValues.at( secondI );
|
||||
if ( !RiaCurveDataTools::isValidValue( secondValue, removeInterpolatedValues ) )
|
||||
{
|
||||
return HUGE_VAL;
|
||||
}
|
||||
|
||||
return secondValue;
|
||||
}
|
||||
|
||||
if ( xValues.at( firstI ) < interpolationXValue && xValues.at( secondI ) > interpolationXValue )
|
||||
{
|
||||
const double& firstValue = yValues.at( firstI );
|
||||
const double& secondValue = yValues.at( secondI );
|
||||
|
||||
bool isFirstValid = RiaCurveDataTools::isValidValue( firstValue, removeInterpolatedValues );
|
||||
if ( !isFirstValid ) return HUGE_VAL;
|
||||
|
||||
bool isSecondValid = RiaCurveDataTools::isValidValue( secondValue, removeInterpolatedValues );
|
||||
if ( !isSecondValid ) return HUGE_VAL;
|
||||
|
||||
double firstDiff = fabs( XComparator::diff( interpolationXValue, xValues.at( firstI ) ) );
|
||||
double secondDiff = fabs( XComparator::diff( xValues.at( secondI ), interpolationXValue ) );
|
||||
|
||||
double firstWeight = secondDiff / ( firstDiff + secondDiff );
|
||||
double secondWeight = firstDiff / ( firstDiff + secondDiff );
|
||||
|
||||
double val = ( firstValue * firstWeight ) + ( secondValue * secondWeight );
|
||||
|
||||
CVF_ASSERT( RiaCurveDataTools::isValidValue( val, removeInterpolatedValues ) );
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return HUGE_VAL;
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaDateStringParser.h"
|
||||
|
||||
#include "RiaQDateTimeTools.h"
|
||||
#include "RiaStdStringTools.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
const std::string MONTH_NAMES[] =
|
||||
{ "january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december" };
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaDateStringParser::parseDateString( const QString& dateString )
|
||||
{
|
||||
return RiaDateStringParser::parseDateString( dateString.toStdString() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaDateStringParser::parseDateString( const std::string& dateString )
|
||||
{
|
||||
int year = -1, month = -1, day = -1;
|
||||
bool parsedOk = false;
|
||||
if ( hasSeparators( dateString ) )
|
||||
{
|
||||
parsedOk = tryParseYearFirst( dateString, year, month, day ) ||
|
||||
tryParseDayFirst( dateString, year, month, day ) || tryParseMonthFirst( dateString, year, month, day );
|
||||
}
|
||||
if ( !parsedOk )
|
||||
{
|
||||
auto firstNumerical = dateString.find_first_of( "0123456789" );
|
||||
if ( firstNumerical != std::string::npos )
|
||||
{
|
||||
std::string subString = dateString.substr( firstNumerical );
|
||||
|
||||
parsedOk = tryParseYearFirstNoSeparators( subString, year, month, day ) ||
|
||||
tryParseDayFirstNoSeparators( subString, year, month, day ) ||
|
||||
tryParseMonthFirstNoSeparators( subString, year, month, day );
|
||||
}
|
||||
}
|
||||
|
||||
QDateTime dt;
|
||||
dt.setTimeSpec( RiaQDateTimeTools::currentTimeSpec() );
|
||||
if ( parsedOk ) dt.setDate( QDate( year, month, day ) );
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Try parse formats
|
||||
/// 'yyyy mm dd'
|
||||
/// 'yyyy MMM dd'
|
||||
/// 'yyyy_mm_dd'
|
||||
/// 'yyyy_MMM_dd'
|
||||
/// 'yyyy-mm-dd'
|
||||
/// 'yyyy-MMM-dd'
|
||||
/// 'yyyy.MMM.dd'
|
||||
/// MMM is month name (shortened)
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaDateStringParser::tryParseYearFirst( const std::string& s, int& year, int& month, int& day )
|
||||
{
|
||||
auto firstSep = s.find_first_of( separators() );
|
||||
auto lastSep = s.find_first_of( separators(), firstSep + 1 );
|
||||
|
||||
if ( firstSep == std::string::npos || lastSep == std::string::npos ) return false;
|
||||
|
||||
auto sYear = s.substr( 0, firstSep );
|
||||
auto sMonth = s.substr( firstSep + 1, lastSep - firstSep - 1 );
|
||||
auto sDay = s.substr( lastSep + 1 );
|
||||
|
||||
return tryParseYear( sYear, year ) && tryParseMonth( sMonth, month ) && tryParseDay( sDay, day );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Try parse formats
|
||||
/// 'dd mm yyyy'
|
||||
/// 'dd MMM yyyy'
|
||||
/// 'dd_mm_yyyy'
|
||||
/// 'dd_MMM_yyyy'
|
||||
/// 'dd-mm-yyyy'
|
||||
/// 'dd-MMM-yyyy'
|
||||
/// 'dd.mm.yyyy'
|
||||
/// 'dd.MMM.yyyy'
|
||||
/// MMM is month name (shortened)
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaDateStringParser::tryParseDayFirst( const std::string& s, int& year, int& month, int& day )
|
||||
{
|
||||
auto firstSep = s.find_first_of( separators() );
|
||||
auto lastSep = s.find_first_of( separators(), firstSep + 1 );
|
||||
|
||||
if ( firstSep == std::string::npos || lastSep == std::string::npos ) return false;
|
||||
|
||||
auto sDay = s.substr( 0, firstSep );
|
||||
auto sMonth = s.substr( firstSep + 1, lastSep - firstSep - 1 );
|
||||
auto sYear = s.substr( lastSep + 1 );
|
||||
|
||||
return tryParseYear( sYear, year ) && tryParseMonth( sMonth, month ) && tryParseDay( sDay, day );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaDateStringParser::tryParseMonthFirst( const std::string& s, int& year, int& month, int& day )
|
||||
{
|
||||
auto firstSep = s.find_first_of( separators() );
|
||||
auto lastSep = s.find_first_of( separators(), firstSep + 1 );
|
||||
|
||||
if ( firstSep == std::string::npos || lastSep == std::string::npos ) return false;
|
||||
|
||||
auto sMonth = s.substr( 0, firstSep );
|
||||
auto sDay = s.substr( firstSep + 1, lastSep - firstSep - 1 );
|
||||
auto sYear = s.substr( lastSep + 1 );
|
||||
|
||||
return tryParseYear( sYear, year ) && tryParseMonth( sMonth, month ) && tryParseDay( sDay, day );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaDateStringParser::tryParseYearFirstNoSeparators( const std::string& s, int& year, int& month, int& day )
|
||||
{
|
||||
if ( s.length() == 8 )
|
||||
{
|
||||
// Four digit year
|
||||
auto sYear = s.substr( 0, 4 );
|
||||
auto sMonth = s.substr( 4, 2 );
|
||||
auto sDay = s.substr( 6, 2 );
|
||||
return tryParseYear( sYear, year ) && tryParseMonth( sMonth, month ) && tryParseDay( sDay, day );
|
||||
}
|
||||
else if ( s.length() == 6 )
|
||||
{
|
||||
// Two digit year
|
||||
auto sYear = s.substr( 0, 2 );
|
||||
auto sMonth = s.substr( 2, 2 );
|
||||
auto sDay = s.substr( 4, 2 );
|
||||
|
||||
return tryParseYear( sYear, year ) && tryParseMonth( sMonth, month ) && tryParseDay( sDay, day );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaDateStringParser::tryParseDayFirstNoSeparators( const std::string& s, int& year, int& month, int& day )
|
||||
{
|
||||
if ( s.length() == 8 )
|
||||
{
|
||||
// Four digit year
|
||||
auto sDay = s.substr( 0, 2 );
|
||||
auto sMonth = s.substr( 2, 2 );
|
||||
auto sYear = s.substr( 4, 4 );
|
||||
|
||||
return tryParseYear( sYear, year ) && tryParseMonth( sMonth, month ) && tryParseDay( sDay, day );
|
||||
}
|
||||
else if ( s.length() == 6 )
|
||||
{
|
||||
// Two digit year
|
||||
auto sDay = s.substr( 0, 2 );
|
||||
auto sMonth = s.substr( 2, 2 );
|
||||
auto sYear = s.substr( 4, 2 );
|
||||
|
||||
return tryParseYear( sYear, year ) && tryParseMonth( sMonth, month ) && tryParseDay( sDay, day );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaDateStringParser::tryParseMonthFirstNoSeparators( const std::string& s, int& year, int& month, int& day )
|
||||
{
|
||||
if ( s.length() == 8 )
|
||||
{
|
||||
// Four digit year
|
||||
auto sMonth = s.substr( 0, 2 );
|
||||
auto sDay = s.substr( 2, 2 );
|
||||
auto sYear = s.substr( 4, 4 );
|
||||
|
||||
return tryParseYear( sYear, year ) && tryParseMonth( sMonth, month ) && tryParseDay( sDay, day );
|
||||
}
|
||||
else if ( s.length() == 6 )
|
||||
{
|
||||
// Two digit year
|
||||
auto sMonth = s.substr( 0, 2 );
|
||||
auto sDay = s.substr( 2, 2 );
|
||||
auto sYear = s.substr( 4, 2 );
|
||||
|
||||
return tryParseYear( sYear, year ) && tryParseMonth( sMonth, month ) && tryParseDay( sDay, day );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaDateStringParser::tryParseYear( const std::string& s, int& year )
|
||||
{
|
||||
if ( RiaStdStringTools::containsAlphabetic( s ) ) return false;
|
||||
|
||||
auto today = QDate::currentDate();
|
||||
int y = RiaStdStringTools::toInt( s );
|
||||
if ( y < 100 )
|
||||
{
|
||||
if ( y > 70 )
|
||||
y += 1900;
|
||||
else
|
||||
y += 2000;
|
||||
}
|
||||
|
||||
if ( y > 1970 && y <= today.year() + 100 ) // Support dates 100 years into the future.
|
||||
{
|
||||
year = y;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaDateStringParser::tryParseMonth( const std::string& s, int& month )
|
||||
{
|
||||
if ( RiaStdStringTools::containsAlphabetic( s ) )
|
||||
{
|
||||
auto sMonth = s;
|
||||
sMonth = trimString( sMonth );
|
||||
std::transform( sMonth.begin(), sMonth.end(), sMonth.begin(), []( const char c ) -> char {
|
||||
return (char)::tolower( c );
|
||||
} );
|
||||
|
||||
for ( int i = 0; i < 12; i++ )
|
||||
{
|
||||
if ( MONTH_NAMES[i].compare( 0, sMonth.size(), sMonth ) == 0 )
|
||||
{
|
||||
month = i + 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int m = RiaStdStringTools::toInt( s );
|
||||
if ( m >= 1 && m <= 12 )
|
||||
{
|
||||
month = m;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaDateStringParser::tryParseDay( const std::string& s, int& day )
|
||||
{
|
||||
if ( RiaStdStringTools::containsAlphabetic( s ) ) return false;
|
||||
|
||||
int d = RiaStdStringTools::toInt( s );
|
||||
if ( d >= 1 && d <= 31 )
|
||||
{
|
||||
day = d;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::string RiaDateStringParser::separators()
|
||||
{
|
||||
return " -_.";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaDateStringParser::hasSeparators( const std::string& s )
|
||||
{
|
||||
auto firstSep = s.find_first_of( separators() );
|
||||
return firstSep != std::string::npos;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::string RiaDateStringParser::trimString( const std::string& s )
|
||||
{
|
||||
auto sCopy = s.substr( 0, s.find_last_not_of( ' ' ) + 1 );
|
||||
sCopy = sCopy.substr( sCopy.find_first_not_of( ' ' ) );
|
||||
return sCopy;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 <QDateTime>
|
||||
#include <QString>
|
||||
#include <string>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaDateStringParser
|
||||
{
|
||||
public:
|
||||
static QDateTime parseDateString( const QString& dateString );
|
||||
static QDateTime parseDateString( const std::string& dateString );
|
||||
|
||||
private:
|
||||
static bool tryParseYearFirst( const std::string& s, int& year, int& month, int& day );
|
||||
static bool tryParseDayFirst( const std::string& s, int& year, int& month, int& day );
|
||||
static bool tryParseMonthFirst( const std::string& s, int& year, int& month, int& day );
|
||||
|
||||
static bool tryParseYearFirstNoSeparators( const std::string& s, int& year, int& month, int& day );
|
||||
static bool tryParseDayFirstNoSeparators( const std::string& s, int& year, int& month, int& day );
|
||||
static bool tryParseMonthFirstNoSeparators( const std::string& s, int& year, int& month, int& day );
|
||||
|
||||
static bool tryParseYear( const std::string& s, int& year );
|
||||
static bool tryParseMonth( const std::string& s, int& month );
|
||||
static bool tryParseDay( const std::string& s, int& day );
|
||||
|
||||
static std::string separators();
|
||||
static bool hasSeparators( const std::string& s );
|
||||
static std::string trimString( const std::string& s );
|
||||
};
|
||||
@@ -0,0 +1,195 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaEclipseUnitTools.h"
|
||||
|
||||
#include "cafAppEnum.h"
|
||||
|
||||
#include "cvfAssert.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace caf
|
||||
{
|
||||
template <>
|
||||
void RiaEclipseUnitTools::UnitSystemType::setUp()
|
||||
{
|
||||
addItem( RiaEclipseUnitTools::UnitSystem::UNITS_METRIC, "UNITS_METRIC", "Metric" );
|
||||
addItem( RiaEclipseUnitTools::UnitSystem::UNITS_FIELD, "UNITS_FIELD", "Field" );
|
||||
addItem( RiaEclipseUnitTools::UnitSystem::UNITS_UNKNOWN, "UNITS_UNKNOWN", "Unknown" );
|
||||
|
||||
setDefault( RiaEclipseUnitTools::UnitSystem::UNITS_METRIC );
|
||||
}
|
||||
} // namespace caf
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaEclipseUnitTools::darcysConstant( UnitSystem unitSystem )
|
||||
{
|
||||
// See "Cartesian transmissibility calculations" in the "Eclipse Technical Description"
|
||||
// CDARCY Darcys constant
|
||||
// = 0.00852702 (E300); 0.008527 (ECLIPSE 100) (METRIC)
|
||||
// = 0.00112712 (E300); 0.001127 (ECLIPSE 100) (FIELD)
|
||||
// = 3.6 (LAB)
|
||||
// = 0.00864 (PVT - M)
|
||||
switch ( unitSystem )
|
||||
{
|
||||
case UnitSystem::UNITS_FIELD:
|
||||
return 0.001127;
|
||||
case UnitSystem::UNITS_METRIC:
|
||||
return 0.008527;
|
||||
default:
|
||||
CVF_ASSERT( false );
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaDefines::DepthUnitType RiaEclipseUnitTools::depthUnit( UnitSystem unit )
|
||||
{
|
||||
switch ( unit )
|
||||
{
|
||||
case RiaEclipseUnitTools::UnitSystem::UNITS_METRIC:
|
||||
return RiaDefines::DepthUnitType::UNIT_METER;
|
||||
break;
|
||||
case RiaEclipseUnitTools::UnitSystem::UNITS_FIELD:
|
||||
return RiaDefines::DepthUnitType::UNIT_FEET;
|
||||
break;
|
||||
case RiaEclipseUnitTools::UnitSystem::UNITS_LAB:
|
||||
return RiaDefines::DepthUnitType::UNIT_NONE;
|
||||
break;
|
||||
case RiaEclipseUnitTools::UnitSystem::UNITS_UNKNOWN:
|
||||
return RiaDefines::DepthUnitType::UNIT_NONE;
|
||||
break;
|
||||
default:
|
||||
return RiaDefines::DepthUnitType::UNIT_NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Convert Gas to oil equivalents
|
||||
/// If field unit, the Gas is in Mega ft^3 while the others are in [stb] (barrel)
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaEclipseUnitTools::convertSurfaceGasFlowRateToOilEquivalents( UnitSystem caseUnitSystem, double eclGasFlowRate )
|
||||
{
|
||||
/// Unused Gas to Barrel conversion :
|
||||
/// we convert gas to stb as well. Based on
|
||||
/// 1 [stb] = 0.15898729492800007 [m^3]
|
||||
/// 1 [ft] = 0.3048 [m]
|
||||
/// megaFt3ToStbFactor = 1.0 / (1.0e-6 * 0.15898729492800007 * ( 1.0 / 0.3048 )^3 )
|
||||
/// double megaFt3ToStbFactor = 178107.60668;
|
||||
|
||||
double fieldGasToOilEquivalent = 1.0e6 / 5800; // Mega ft^3 to BOE
|
||||
double metricGasToOilEquivalent = 1.0 / 1.0e3; // Sm^3 Gas to Sm^3 oe
|
||||
|
||||
double oilEquivalentGasRate = HUGE_VAL;
|
||||
|
||||
if ( caseUnitSystem == RiaEclipseUnitTools::UnitSystem::UNITS_FIELD )
|
||||
oilEquivalentGasRate = fieldGasToOilEquivalent * eclGasFlowRate;
|
||||
if ( caseUnitSystem == RiaEclipseUnitTools::UnitSystem::UNITS_METRIC )
|
||||
oilEquivalentGasRate = metricGasToOilEquivalent * eclGasFlowRate;
|
||||
|
||||
return oilEquivalentGasRate;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaEclipseUnitTools::unitStringPressure( UnitSystem unitSystem )
|
||||
{
|
||||
switch ( unitSystem )
|
||||
{
|
||||
case RiaEclipseUnitTools::UnitSystem::UNITS_METRIC:
|
||||
return "barsa";
|
||||
case RiaEclipseUnitTools::UnitSystem::UNITS_FIELD:
|
||||
return "psia";
|
||||
case RiaEclipseUnitTools::UnitSystem::UNITS_LAB:
|
||||
return "atma";
|
||||
case RiaEclipseUnitTools::UnitSystem::UNITS_UNKNOWN:
|
||||
return "";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaEclipseUnitTools::convertToMeter( double sourceValue, const QString& sourceValueUnitText )
|
||||
{
|
||||
QString timmed = sourceValueUnitText.trimmed();
|
||||
|
||||
if ( timmed.compare( "m", Qt::CaseInsensitive ) == 0 || timmed.compare( "md-m", Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
return sourceValue;
|
||||
}
|
||||
else if ( timmed.compare( "cm", Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
return sourceValue / 100.0;
|
||||
}
|
||||
else if ( timmed.compare( "mm", Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
return sourceValue / 1000.0;
|
||||
}
|
||||
else if ( timmed.compare( "in", Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
return RiaEclipseUnitTools::inchToMeter( sourceValue );
|
||||
}
|
||||
else if ( timmed.compare( "ft", Qt::CaseInsensitive ) == 0 || timmed.compare( "md-ft", Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
return RiaEclipseUnitTools::feetToMeter( sourceValue );
|
||||
}
|
||||
|
||||
return HUGE_VAL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaEclipseUnitTools::convertToFeet( double sourceValue, const QString& sourceValueUnitText )
|
||||
{
|
||||
QString timmed = sourceValueUnitText.trimmed();
|
||||
|
||||
if ( timmed.compare( "ft", Qt::CaseInsensitive ) == 0 || timmed.compare( "md-ft", Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
return sourceValue;
|
||||
}
|
||||
else if ( timmed.compare( "in", Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
return RiaEclipseUnitTools::inchToFeet( sourceValue );
|
||||
}
|
||||
else if ( timmed.compare( "cm", Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
double meter = sourceValue / 100.0;
|
||||
return RiaEclipseUnitTools::meterToFeet( meter );
|
||||
}
|
||||
else if ( timmed.compare( "mm", Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
double meter = sourceValue / 1000.0;
|
||||
return RiaEclipseUnitTools::meterToFeet( meter );
|
||||
}
|
||||
else if ( timmed.compare( "m", Qt::CaseInsensitive ) == 0 || timmed.compare( "md-m", Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
return RiaEclipseUnitTools::meterToFeet( sourceValue );
|
||||
}
|
||||
|
||||
return HUGE_VAL;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaDefines.h"
|
||||
#include "cafAppEnum.h"
|
||||
|
||||
class RiaEclipseUnitTools
|
||||
{
|
||||
public:
|
||||
enum class UnitSystem
|
||||
{
|
||||
UNITS_METRIC,
|
||||
UNITS_FIELD,
|
||||
UNITS_LAB,
|
||||
UNITS_UNKNOWN,
|
||||
};
|
||||
|
||||
typedef caf::AppEnum<RiaEclipseUnitTools::UnitSystem> UnitSystemType;
|
||||
|
||||
static double feetPerMeter() { return 3.2808399; }
|
||||
static double meterPerFeet() { return 0.3048000; }
|
||||
|
||||
static double meterToFeet( double meter ) { return meter * feetPerMeter(); }
|
||||
static double feetToMeter( double feet ) { return feet * meterPerFeet(); }
|
||||
static double meterToInch( double meter ) { return meter * feetPerMeter() * 12.0; }
|
||||
static double inchToMeter( double inch ) { return ( inch / 12.0 ) * meterPerFeet(); }
|
||||
static double inchToFeet( double inch ) { return ( inch / 12.0 ); }
|
||||
static double mmToMeter( double mm ) { return mm / 1000.0; }
|
||||
static double meterToMm( double meter ) { return 1000.0 * meter; }
|
||||
|
||||
static double barToPascal( double bar ) { return bar * 100000.0; }
|
||||
static double pascalToBar( double pas ) { return pas / 100000.0; }
|
||||
|
||||
static double barToPsi( double bar ) { return bar * 14.5038; }
|
||||
static double barPerMeterToPsiPerFeet( double barPerMeter ) { return barPerMeter * 4.42075; }
|
||||
static double gigaPascalToPascal( double gigaPascal ) { return gigaPascal * 1.0e9; }
|
||||
|
||||
static double darcysConstant( UnitSystem unitSystem );
|
||||
|
||||
static RiaDefines::DepthUnitType depthUnit( UnitSystem unit );
|
||||
|
||||
static double convertSurfaceGasFlowRateToOilEquivalents( UnitSystem, double eclGasFlowRate );
|
||||
|
||||
static QString unitStringPressure( UnitSystem unitSystem );
|
||||
|
||||
static double convertToMeter( double sourceValue, const QString& unitText );
|
||||
static double convertToFeet( double sourceValue, const QString& unitText );
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaExtractionTools.h"
|
||||
|
||||
#include "RigWellPath.h"
|
||||
#include "RimEclipseCase.h"
|
||||
#include "RimMainPlotCollection.h"
|
||||
#include "RimProject.h"
|
||||
#include "RimSimWellInView.h"
|
||||
#include "RimWellLogPlotCollection.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigEclipseWellLogExtractor* RiaExtractionTools::findOrCreateWellLogExtractor( RimWellPath* wellPath,
|
||||
RimEclipseCase* eclipseCase )
|
||||
{
|
||||
if ( !( wellPath && eclipseCase ) ) return nullptr;
|
||||
|
||||
auto wlPlotCollection = wellLogPlotCollection();
|
||||
if ( !wlPlotCollection ) return nullptr;
|
||||
|
||||
return wlPlotCollection->findOrCreateExtractor( wellPath, eclipseCase );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigGeoMechWellLogExtractor* RiaExtractionTools::findOrCreateWellLogExtractor( RimWellPath* wellPath,
|
||||
RimGeoMechCase* geomCase )
|
||||
{
|
||||
if ( !( wellPath && geomCase ) ) return nullptr;
|
||||
|
||||
auto wlPlotCollection = wellLogPlotCollection();
|
||||
if ( !wlPlotCollection ) return nullptr;
|
||||
|
||||
return wlPlotCollection->findOrCreateExtractor( wellPath, geomCase );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigEclipseWellLogExtractor* RiaExtractionTools::findOrCreateSimWellExtractor( const RimSimWellInView* simWell,
|
||||
const RigWellPath* wellPathGeom )
|
||||
{
|
||||
if ( !( simWell && wellPathGeom ) ) return nullptr;
|
||||
|
||||
auto wlPlotCollection = wellLogPlotCollection();
|
||||
if ( !wlPlotCollection ) return nullptr;
|
||||
|
||||
RimEclipseCase* eclipseCase = nullptr;
|
||||
simWell->firstAncestorOrThisOfType( eclipseCase );
|
||||
if ( !( eclipseCase && eclipseCase->eclipseCaseData() ) )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString caseUserDescription = eclipseCase->caseUserDescription();
|
||||
|
||||
return wlPlotCollection->findOrCreateSimWellExtractor( simWell->name,
|
||||
caseUserDescription,
|
||||
wellPathGeom,
|
||||
eclipseCase->eclipseCaseData() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimWellLogPlotCollection* RiaExtractionTools::wellLogPlotCollection()
|
||||
{
|
||||
auto proj = RimProject::current();
|
||||
if ( !proj ) return nullptr;
|
||||
|
||||
auto plotCollection = proj->mainPlotCollection();
|
||||
if ( !plotCollection ) return nullptr;
|
||||
|
||||
auto wellLogPlotCollection = plotCollection->wellLogPlotCollection();
|
||||
return wellLogPlotCollection;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 <gsl/gsl>
|
||||
|
||||
class RigEclipseWellLogExtractor;
|
||||
class RigGeoMechWellLogExtractor;
|
||||
class RigWellPath;
|
||||
class RimEclipseCase;
|
||||
class RimGeoMechCase;
|
||||
class RimSimWellInView;
|
||||
class RimWellLogPlotCollection;
|
||||
class RimWellPath;
|
||||
|
||||
class QString;
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
namespace RiaExtractionTools
|
||||
{
|
||||
RigEclipseWellLogExtractor* findOrCreateWellLogExtractor( RimWellPath* wellPath, RimEclipseCase* eclipseCase );
|
||||
RigGeoMechWellLogExtractor* findOrCreateWellLogExtractor( RimWellPath* wellPath, RimGeoMechCase* geomCase );
|
||||
|
||||
RigEclipseWellLogExtractor* findOrCreateSimWellExtractor( const RimSimWellInView* simWell, const RigWellPath* wellPathGeom );
|
||||
|
||||
RimWellLogPlotCollection* wellLogPlotCollection();
|
||||
|
||||
}; // namespace RiaExtractionTools
|
||||
@@ -0,0 +1,44 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- Equinor ASA
|
||||
// Copyright (C) 2018- Ceetron Solutions AS
|
||||
//
|
||||
// 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 "RiaFieldHandleTools.h"
|
||||
|
||||
#include "cafPdmFieldHandle.h"
|
||||
#include "cafPdmUiFieldHandle.h"
|
||||
#include "cafPdmXmlFieldHandle.h"
|
||||
|
||||
#include "cvfAssert.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaFieldhandleTools::disableWriteAndSetFieldHidden( caf::PdmFieldHandle* fieldHandle )
|
||||
{
|
||||
CVF_ASSERT( fieldHandle );
|
||||
|
||||
if ( fieldHandle->uiCapability() )
|
||||
{
|
||||
fieldHandle->uiCapability()->setUiHidden( true );
|
||||
}
|
||||
|
||||
if ( fieldHandle->xmlCapability() )
|
||||
{
|
||||
fieldHandle->xmlCapability()->setIOWritable( false );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- Equinor ASA
|
||||
// Copyright (C) 2018- Ceetron Solutions AS
|
||||
//
|
||||
// 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
|
||||
|
||||
namespace caf
|
||||
{
|
||||
class PdmFieldHandle;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaFieldhandleTools
|
||||
{
|
||||
public:
|
||||
static void disableWriteAndSetFieldHidden( caf::PdmFieldHandle* fieldHandle );
|
||||
};
|
||||
@@ -0,0 +1,364 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011- Statoil ASA
|
||||
// Copyright (C) 2013- Ceetron Solutions AS
|
||||
// Copyright (C) 2011-2012 Ceetron AS
|
||||
//
|
||||
// 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 "RiaFilePathTools.h"
|
||||
#include "RiaTextStringTools.h"
|
||||
|
||||
#include "cafAssert.h"
|
||||
|
||||
#include <QDir>
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const QChar RiaFilePathTools::separator()
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaFilePathTools::toInternalSeparator( const QString& path )
|
||||
{
|
||||
QString currNativeSep = QDir::separator();
|
||||
|
||||
if ( currNativeSep == "/" )
|
||||
{
|
||||
// On Linux like system -> Do not convert separators
|
||||
return path;
|
||||
}
|
||||
|
||||
// On other systems (i.e. Windows) -> Convert to internal separator (/)
|
||||
QString output = path;
|
||||
return output.replace( QString( "\\" ), separator() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString& RiaFilePathTools::appendSeparatorIfNo( QString& path )
|
||||
{
|
||||
if ( !path.endsWith( separator() ) )
|
||||
{
|
||||
path.append( separator() );
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaFilePathTools::relativePath( const QString& rootDir, const QString& dir )
|
||||
{
|
||||
if ( dir.startsWith( rootDir ) )
|
||||
{
|
||||
QString relPath = dir;
|
||||
relPath.remove( 0, rootDir.size() );
|
||||
|
||||
if ( relPath.startsWith( separator() ) ) relPath.remove( 0, 1 );
|
||||
return appendSeparatorIfNo( relPath );
|
||||
}
|
||||
else
|
||||
{
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaFilePathTools::equalPaths( const QString& path1, const QString& path2 )
|
||||
{
|
||||
QString p1 = path1;
|
||||
QString p2 = path2;
|
||||
appendSeparatorIfNo( p1 );
|
||||
appendSeparatorIfNo( p2 );
|
||||
return p1 == p2;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Own canonicalPath method since the QDir::canonicalPath seems to not work
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaFilePathTools::canonicalPath( const QString& path )
|
||||
{
|
||||
return QDir( path ).absolutePath();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::pair<QString, QString> RiaFilePathTools::toFolderAndFileName( const QString& absFileName )
|
||||
{
|
||||
auto absFN = toInternalSeparator( absFileName );
|
||||
int lastSep = absFN.lastIndexOf( separator() );
|
||||
if ( lastSep > 0 )
|
||||
{
|
||||
return std::make_pair( absFN.left( lastSep ), absFN.mid( lastSep + 1 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::make_pair( "", absFN );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaFilePathTools::removeDuplicatePathSeparators( const QString& path )
|
||||
{
|
||||
QString correctedPath = path;
|
||||
QString prefix;
|
||||
|
||||
QString doubleBackslash = R"(\\)";
|
||||
if ( correctedPath.size() > 2 )
|
||||
{
|
||||
QString prefixCandidate = correctedPath.left( 2 );
|
||||
if ( prefixCandidate == doubleBackslash || prefixCandidate == "//" )
|
||||
{
|
||||
prefix = prefixCandidate;
|
||||
|
||||
correctedPath = correctedPath.right( correctedPath.size() - 2 );
|
||||
}
|
||||
}
|
||||
|
||||
correctedPath.replace( QString( "%1%1" ).arg( separator() ), separator() );
|
||||
correctedPath.replace( doubleBackslash, R"(\)" );
|
||||
|
||||
correctedPath = prefix + correctedPath;
|
||||
|
||||
return correctedPath;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaFilePathTools::rootSearchPathFromSearchFilter( const QString& searchFilter )
|
||||
{
|
||||
QStringList pathPartList = searchFilter.split( separator() );
|
||||
|
||||
QStringList::iterator pathPartIt = pathPartList.begin();
|
||||
|
||||
for ( ; pathPartIt != pathPartList.end(); ++pathPartIt )
|
||||
{
|
||||
QString pathPart = *pathPartIt;
|
||||
|
||||
// Remove allowed escaping of wildcards
|
||||
|
||||
pathPart.replace( "[[]", "" );
|
||||
pathPart.replace( "[]]", "" );
|
||||
pathPart.replace( "[?]", "" );
|
||||
pathPart.replace( "[*]", "" );
|
||||
|
||||
if ( pathPart.contains( "*" ) ) break;
|
||||
if ( pathPart.contains( "?" ) ) break;
|
||||
if ( pathPart.contains( "[" ) ) break;
|
||||
}
|
||||
|
||||
pathPartList.erase( pathPartIt, pathPartList.end() );
|
||||
|
||||
return pathPartList.join( separator() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaFilePathTools::commonRootOfFileNames( const QStringList& fileList )
|
||||
{
|
||||
QStringList fileNameList;
|
||||
for ( auto filePath : fileList )
|
||||
{
|
||||
QFileInfo fileInfo( filePath );
|
||||
QString fileNameWithoutExt = fileInfo.baseName();
|
||||
fileNameList.push_back( fileNameWithoutExt );
|
||||
}
|
||||
QString root = RiaTextStringTools::commonRoot( fileNameList );
|
||||
return root;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QStringList RiaFilePathTools::splitPathIntoComponents( const QString& inputPath, bool splitExtensionIntoSeparateEntry )
|
||||
{
|
||||
auto path = QDir::cleanPath( inputPath );
|
||||
|
||||
QStringList components;
|
||||
|
||||
QDir dir( path );
|
||||
|
||||
QFileInfo fileInfo( path );
|
||||
|
||||
if ( splitExtensionIntoSeparateEntry )
|
||||
{
|
||||
QString extension = fileInfo.completeSuffix();
|
||||
path = path.replace( QString( ".%1" ).arg( extension ), "" );
|
||||
components.push_front( extension );
|
||||
components.push_front( fileInfo.baseName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
components.push_back( fileInfo.fileName() );
|
||||
}
|
||||
|
||||
while ( dir.cdUp() )
|
||||
{
|
||||
components.push_front( dir.dirName() );
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
struct PathNode
|
||||
{
|
||||
QString name;
|
||||
PathNode* parent;
|
||||
std::list<std::unique_ptr<PathNode>> children;
|
||||
QString fileName;
|
||||
|
||||
PathNode( const QString& name, PathNode* parent )
|
||||
: name( name )
|
||||
, parent( parent )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void addToPathTree( PathNode* node, QStringList pathComponents, const QString& fileName )
|
||||
{
|
||||
CAF_ASSERT( node );
|
||||
if ( !pathComponents.empty() )
|
||||
{
|
||||
QString pathComponent = pathComponents.front();
|
||||
pathComponents.pop_front();
|
||||
|
||||
for ( auto it = node->children.begin(); it != node->children.end(); ++it )
|
||||
{
|
||||
if ( it->get()->name == pathComponent )
|
||||
{
|
||||
addToPathTree( it->get(), pathComponents, fileName );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
node->children.push_back( std::unique_ptr<PathNode>( new PathNode( pathComponent, node ) ) );
|
||||
addToPathTree( node->children.back().get(), pathComponents, fileName );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reached leaf, just set file name
|
||||
node->fileName = fileName;
|
||||
}
|
||||
}
|
||||
|
||||
void trimTree( PathNode* node )
|
||||
{
|
||||
if ( node->children.size() == 1u )
|
||||
{
|
||||
// Unnecessary level. Remove it.
|
||||
std::unique_ptr<PathNode> singleChildNode = std::move( node->children.front() );
|
||||
node->children.clear();
|
||||
node->children.swap( singleChildNode->children );
|
||||
node->fileName = singleChildNode->fileName;
|
||||
|
||||
// Re-parent children
|
||||
for ( auto it = node->children.begin(); it != node->children.end(); ++it )
|
||||
{
|
||||
it->get()->parent = node;
|
||||
}
|
||||
trimTree( node );
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( auto it = node->children.begin(); it != node->children.end(); ++it )
|
||||
{
|
||||
trimTree( it->get() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void extractLeafNodes( PathNode* node, std::list<PathNode*>* leafNodes )
|
||||
{
|
||||
if ( node->children.empty() )
|
||||
{
|
||||
leafNodes->push_back( node );
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( auto it = node->children.begin(); it != node->children.end(); ++it )
|
||||
{
|
||||
extractLeafNodes( it->get(), leafNodes );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pathToNode( PathNode* node, QStringList* path )
|
||||
{
|
||||
CAF_ASSERT( path );
|
||||
|
||||
if ( node != nullptr )
|
||||
{
|
||||
if ( !node->name.isEmpty() ) path->push_front( node->name );
|
||||
pathToNode( node->parent, path );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Takes a list of file paths and returns a map with the key components that separate the path
|
||||
/// from the others.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::map<QString, QStringList> RiaFilePathTools::keyPathComponentsForEachFilePath( const QStringList& filePaths )
|
||||
{
|
||||
std::map<QString, QStringList> allComponents;
|
||||
|
||||
std::multiset<QString> allPathComponents;
|
||||
for ( auto fileName : filePaths )
|
||||
{
|
||||
QStringList pathComponentsForFile = splitPathIntoComponents( fileName, true );
|
||||
allComponents[fileName] = pathComponentsForFile;
|
||||
|
||||
for ( auto pathComponent : pathComponentsForFile )
|
||||
{
|
||||
allPathComponents.insert( pathComponent );
|
||||
}
|
||||
}
|
||||
|
||||
auto topNode = std::unique_ptr<PathNode>( new PathNode( "", nullptr ) );
|
||||
|
||||
for ( auto keyComponentsPair : allComponents )
|
||||
{
|
||||
addToPathTree( topNode.get(), keyComponentsPair.second, keyComponentsPair.first );
|
||||
}
|
||||
|
||||
trimTree( topNode.get() );
|
||||
std::list<PathNode*> leafNodes;
|
||||
extractLeafNodes( topNode.get(), &leafNodes );
|
||||
|
||||
std::map<QString, QStringList> keyComponents;
|
||||
for ( PathNode* node : leafNodes )
|
||||
{
|
||||
QStringList path;
|
||||
pathToNode( node, &path );
|
||||
keyComponents[node->fileName] = path;
|
||||
}
|
||||
|
||||
return keyComponents;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011- Statoil ASA
|
||||
// Copyright (C) 2013- Ceetron Solutions AS
|
||||
// Copyright (C) 2011-2012 Ceetron AS
|
||||
//
|
||||
// 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 <QByteArray>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaFilePathTools
|
||||
{
|
||||
public:
|
||||
static const QChar separator();
|
||||
static QString toInternalSeparator( const QString& path );
|
||||
static QString& appendSeparatorIfNo( QString& path );
|
||||
static QString relativePath( const QString& rootDir, const QString& dir );
|
||||
static bool equalPaths( const QString& path1, const QString& path2 );
|
||||
static QString canonicalPath( const QString& path );
|
||||
static std::pair<QString, QString> toFolderAndFileName( const QString& absFileName );
|
||||
static QString removeDuplicatePathSeparators( const QString& path );
|
||||
static QString rootSearchPathFromSearchFilter( const QString& searchFilter );
|
||||
static QString commonRootOfFileNames( const QStringList& filePaths );
|
||||
|
||||
static QStringList splitPathIntoComponents( const QString& path, bool splitExtensionIntoSeparateEntry = false );
|
||||
|
||||
static std::map<QString, QStringList> keyPathComponentsForEachFilePath( const QStringList& filePaths );
|
||||
};
|
||||
@@ -0,0 +1,125 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaGitDiff.h"
|
||||
|
||||
#include "cafUtils.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QProcess>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaGitDiff::RiaGitDiff( const QString& pathToDiffTool )
|
||||
: m_pathToGitTool( pathToDiffTool )
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaGitDiff::~RiaGitDiff()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaGitDiff::reset()
|
||||
{
|
||||
m_lastError = ErrorType::IC_NO_ERROR;
|
||||
m_errorMsg.clear();
|
||||
m_errorDetails.clear();
|
||||
m_diffOutput.clear();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaGitDiff::executeDiff( const QString& baseFolder )
|
||||
{
|
||||
reset();
|
||||
|
||||
QString fullFilePath = "git";
|
||||
if ( !m_pathToGitTool.isEmpty() )
|
||||
{
|
||||
fullFilePath = m_pathToGitTool + "/" + fullFilePath;
|
||||
}
|
||||
|
||||
QString incomingCurrentPath = QDir::currentPath();
|
||||
QDir::setCurrent( baseFolder );
|
||||
|
||||
QString args = "diff";
|
||||
|
||||
QString completeCommand = QString( "\"%1\" %2" ).arg( fullFilePath ).arg( args );
|
||||
|
||||
// Launch process and wait
|
||||
QProcess proc;
|
||||
proc.start( completeCommand );
|
||||
proc.waitForFinished( 30000 );
|
||||
|
||||
QDir::setCurrent( incomingCurrentPath );
|
||||
|
||||
QProcess::ProcessError procError = proc.error();
|
||||
if ( procError != QProcess::UnknownError )
|
||||
{
|
||||
m_lastError = ErrorType::SEVERE_ERROR;
|
||||
m_errorMsg = "Error running 'git' tool process";
|
||||
m_errorDetails = completeCommand;
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray stdOut = proc.readAllStandardOutput();
|
||||
m_diffOutput = stdOut;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaGitDiff::ErrorType RiaGitDiff::error() const
|
||||
{
|
||||
return m_lastError;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaGitDiff::errorMessage() const
|
||||
{
|
||||
return m_errorMsg;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaGitDiff::errorDetails() const
|
||||
{
|
||||
return m_errorDetails;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaGitDiff::diffOutput() const
|
||||
{
|
||||
return m_diffOutput;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 <QString>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
// Use external tool 'git' to produce a text string representing the diff
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaGitDiff
|
||||
{
|
||||
public:
|
||||
enum class ErrorType
|
||||
{
|
||||
IC_NO_ERROR, // No error occurred
|
||||
IC_ERROR, // An error occurred
|
||||
SEVERE_ERROR // Severe error occurred, it is likely that another call to compare() will also fail
|
||||
};
|
||||
|
||||
public:
|
||||
explicit RiaGitDiff( const QString& pathToGitTool );
|
||||
~RiaGitDiff();
|
||||
|
||||
bool executeDiff( const QString& baseFolder );
|
||||
ErrorType error() const;
|
||||
QString errorMessage() const;
|
||||
QString errorDetails() const;
|
||||
QString diffOutput() const;
|
||||
|
||||
private:
|
||||
void reset();
|
||||
|
||||
private:
|
||||
const QString m_pathToGitTool;
|
||||
ErrorType m_lastError;
|
||||
QString m_errorMsg;
|
||||
QString m_errorDetails;
|
||||
QString m_diffOutput;
|
||||
};
|
||||
@@ -0,0 +1,225 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS
|
||||
//
|
||||
// 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 "RiaImageCompareReporter.h"
|
||||
#include <QDir>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
RiaImageCompareReporter::RiaImageCompareReporter( void )
|
||||
{
|
||||
m_showOriginal = true;
|
||||
m_showGenerated = true;
|
||||
m_showInteractiveDiff = false;
|
||||
}
|
||||
|
||||
RiaImageCompareReporter::~RiaImageCompareReporter( void )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaImageCompareReporter::addImageDirectoryComparisonSet( const std::string& title,
|
||||
const std::string& baseImageDir,
|
||||
const std::string& newImagesDir,
|
||||
const std::string& diffImagesDir )
|
||||
{
|
||||
m_directorySets.push_back( DirSet( title, baseImageDir, newImagesDir, diffImagesDir ) );
|
||||
}
|
||||
|
||||
std::string removeCommonStart( const std::string& mask, const std::string& filename )
|
||||
{
|
||||
size_t i;
|
||||
for ( i = 0; i < mask.size() && i < filename.size(); ++i )
|
||||
{
|
||||
if ( mask[i] != filename[i] ) break;
|
||||
}
|
||||
|
||||
return filename.substr( i );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaImageCompareReporter::generateHTMLReport( const std::string& fileName, const std::string& diff2htmlHeaderText )
|
||||
{
|
||||
if ( m_directorySets.size() == 0 ) return;
|
||||
|
||||
std::ofstream output( fileName.c_str() );
|
||||
if ( !output )
|
||||
{
|
||||
std::cout << "Trouble opening test report file: " << fileName;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string html;
|
||||
|
||||
html += "<html>\n";
|
||||
html += "<head>\n";
|
||||
|
||||
if ( m_showInteractiveDiff )
|
||||
{
|
||||
html += cssString();
|
||||
}
|
||||
|
||||
html += diff2htmlHeaderText;
|
||||
|
||||
html += "</head>\n";
|
||||
html += "\n";
|
||||
html += "<body>\n";
|
||||
html += "<title>Regression-Test Report</title>\n";
|
||||
html += "\n";
|
||||
|
||||
for ( size_t dsIdx = 0; dsIdx < m_directorySets.size(); ++dsIdx )
|
||||
{
|
||||
std::vector<std::string> baseImageNames = getPngFilesInDirectory( m_directorySets[dsIdx].m_baseImageDir );
|
||||
|
||||
html += "<table>\n";
|
||||
html += " <tr>\n";
|
||||
html += " <td colspan=\"3\" bgcolor=\"darkblue\" height=\"40\"> <b><font color=\"white\" size=\"3\"> " +
|
||||
m_directorySets[dsIdx].m_title + " </font></b> </td>\n";
|
||||
html += " </tr>\n";
|
||||
|
||||
std::string baseImageFolder = removeCommonStart( fileName, m_directorySets[dsIdx].m_baseImageDir );
|
||||
std::string genImageFolder = removeCommonStart( fileName, m_directorySets[dsIdx].m_newImagesDir );
|
||||
std::string diffImageFolder = removeCommonStart( fileName, m_directorySets[dsIdx].m_diffImagesDir );
|
||||
|
||||
for ( size_t fIdx = 0; fIdx < baseImageNames.size(); ++fIdx )
|
||||
{
|
||||
html += " <tr>\n";
|
||||
html += " <td colspan=\"3\" bgcolor=\"lightgray\"> " + baseImageNames[fIdx] + "</td>\n";
|
||||
html += " </tr>\n";
|
||||
|
||||
html += " <tr>\n";
|
||||
if ( m_showOriginal )
|
||||
{
|
||||
html += " <td> <img src=\"" + baseImageFolder + "/" + baseImageNames[fIdx] +
|
||||
"\" width=\"100%\" alt=\"" + baseImageFolder + "/" + baseImageNames[fIdx] + "\" > </td>\n";
|
||||
}
|
||||
|
||||
if ( m_showGenerated )
|
||||
{
|
||||
html += " <td> <img src=\"" + genImageFolder + "/" + baseImageNames[fIdx] +
|
||||
"\" width=\"100%\" alt=\"" + genImageFolder + "/" + baseImageNames[fIdx] + "\" > </td>\n";
|
||||
}
|
||||
|
||||
if ( m_showInteractiveDiff )
|
||||
{
|
||||
html += " <td> <div class = \"image-slider\"> <div> <img src=\"" + baseImageFolder + "/" +
|
||||
baseImageNames[fIdx] + "\" > </div> <img src = \"" + genImageFolder + "/" +
|
||||
baseImageNames[fIdx] + "\" > </div> </td>\n";
|
||||
}
|
||||
|
||||
html += " <td> <img src=\"" + diffImageFolder + "/" + baseImageNames[fIdx] +
|
||||
"\" width=\"100%\" alt=\"" + diffImageFolder + "/" + baseImageNames[fIdx] + "\" > </td>\n";
|
||||
html += " </tr>\n";
|
||||
|
||||
// A little air between images
|
||||
html += " <tr> <td height=\"10\"> </td> </tr>\n";
|
||||
}
|
||||
|
||||
html += "</table>\n";
|
||||
|
||||
html += "\n";
|
||||
}
|
||||
|
||||
output << html;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaImageCompareReporter::showInteractiveOnly()
|
||||
{
|
||||
m_showOriginal = false;
|
||||
m_showGenerated = false;
|
||||
m_showInteractiveDiff = true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Retuns the names of the *.png files in a directory. The names are without path, but with extension
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
std::vector<std::string> RiaImageCompareReporter::getPngFilesInDirectory( const std::string& searchPath )
|
||||
{
|
||||
QDir searchDir( QString::fromStdString( searchPath ) );
|
||||
|
||||
searchDir.setFilter( QDir::Files );
|
||||
// QStringList filter;
|
||||
// filter.append("*.png");
|
||||
// searchDir.setNameFilters(filter);
|
||||
|
||||
QStringList imageFiles = searchDir.entryList();
|
||||
|
||||
std::vector<std::string> fileNames;
|
||||
for ( int i = 0; i < imageFiles.size(); ++i )
|
||||
{
|
||||
fileNames.push_back( imageFiles[i].toStdString() );
|
||||
}
|
||||
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::string RiaImageCompareReporter::cssString() const
|
||||
{
|
||||
std::string html;
|
||||
|
||||
html += "<style media=\"screen\" type=\"text/css\">";
|
||||
|
||||
html += "";
|
||||
html += ".image-slider {";
|
||||
html += "position:relative;";
|
||||
html += "display: inline-block;";
|
||||
html += "line-height: 0;";
|
||||
html += "}";
|
||||
|
||||
html += ".image-slider > div {";
|
||||
html += "position: absolute;";
|
||||
html += "top: 0; bottom: 0; left: 0;";
|
||||
html += "width: 25px;";
|
||||
html += "max-width: 100%;";
|
||||
html += "overflow: hidden;";
|
||||
html += "resize: horizontal;";
|
||||
html += "}";
|
||||
|
||||
html += ".image-slider > div:before {";
|
||||
html += "content: '';";
|
||||
html += "position: absolute;";
|
||||
html += "right: 0; bottom: 0;";
|
||||
html += "width: 23px; height: 23px;";
|
||||
html += "padding: 5px;";
|
||||
html += "background: linear-gradient(-45deg, gray 50%, transparent 0);";
|
||||
html += "background-clip: content-box;";
|
||||
html += "cursor: ew-resize;";
|
||||
html += "-webkit-filter: drop-shadow(0 0 6px black);";
|
||||
html += "filter: drop-shadow(0 0 6px black);";
|
||||
html += "}";
|
||||
|
||||
html += ".image-slider img {";
|
||||
html += "user-select: none;";
|
||||
html += "max-width: 1000px;";
|
||||
html += "}";
|
||||
|
||||
html += "</style>";
|
||||
|
||||
return html;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS
|
||||
//
|
||||
// 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 <string>
|
||||
#include <vector>
|
||||
|
||||
class RiaImageCompareReporter
|
||||
{
|
||||
public:
|
||||
RiaImageCompareReporter();
|
||||
virtual ~RiaImageCompareReporter();
|
||||
|
||||
void addImageDirectoryComparisonSet( const std::string& title,
|
||||
const std::string& baseImageDir,
|
||||
const std::string& newImagesDir,
|
||||
const std::string& diffImagesDir );
|
||||
void generateHTMLReport( const std::string& filenName, const std::string& pathToDiff2html );
|
||||
|
||||
void showInteractiveOnly();
|
||||
|
||||
private:
|
||||
static std::vector<std::string> getPngFilesInDirectory( const std::string& searchPath );
|
||||
std::string cssString() const;
|
||||
|
||||
private:
|
||||
struct DirSet
|
||||
{
|
||||
DirSet( const std::string& title,
|
||||
const std::string& baseImageDir,
|
||||
const std::string& newImagesDir,
|
||||
const std::string& diffImagesDir )
|
||||
: m_title( title )
|
||||
, m_baseImageDir( baseImageDir )
|
||||
, m_newImagesDir( newImagesDir )
|
||||
, m_diffImagesDir( diffImagesDir )
|
||||
{
|
||||
}
|
||||
|
||||
std::string m_title;
|
||||
std::string m_baseImageDir;
|
||||
std::string m_newImagesDir;
|
||||
std::string m_diffImagesDir;
|
||||
};
|
||||
|
||||
std::vector<DirSet> m_directorySets;
|
||||
|
||||
bool m_showOriginal;
|
||||
bool m_showGenerated;
|
||||
bool m_showInteractiveDiff;
|
||||
};
|
||||
@@ -0,0 +1,152 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS
|
||||
//
|
||||
// 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 "RiaImageFileCompare.h"
|
||||
#include <QtCore/QProcess>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaImageFileCompare::RiaImageFileCompare( QString compareExecutable )
|
||||
: m_compareExecutable( compareExecutable )
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaImageFileCompare::~RiaImageFileCompare()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaImageFileCompare::reset()
|
||||
{
|
||||
m_imagesEqual = false;
|
||||
m_lastError = ErrorType::IC_NO_ERROR;
|
||||
m_errorMsg = "";
|
||||
m_errorDetails = "";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaImageFileCompare::runComparison( const QString& imgFileName, const QString& refFileName, const QString& diffFileName )
|
||||
{
|
||||
reset();
|
||||
|
||||
if ( m_compareExecutable.isEmpty() )
|
||||
{
|
||||
m_lastError = ErrorType::SEVERE_ERROR;
|
||||
m_errorMsg = "Cannot compare images, no compare executable set";
|
||||
return false;
|
||||
}
|
||||
|
||||
// QString args = QString("-fuzz 2% -lowlight-color white -metric ae \"%1\" \"%2\"
|
||||
// \"%3\"").arg(imgFileName).arg(refFileName).arg((diffFileName));
|
||||
// The ImageMagick compare tool on RedHat 5 does not support the lowlight-color options
|
||||
// Use GCC version as a crude mechanism for disabling use of this option on RedHat5
|
||||
#if ( __GNUC__ == 4 && __GNUC_MINOR__ <= 1 )
|
||||
QString args =
|
||||
QString( "-fuzz 0.4% -metric ae \"%1\" \"%2\" \"%3\"" ).arg( imgFileName ).arg( refFileName ).arg( ( diffFileName ) );
|
||||
#else
|
||||
QString args = QString( "-fuzz 0.4% -lowlight-color white -metric ae \"%1\" \"%2\" \"%3\"" )
|
||||
.arg( imgFileName )
|
||||
.arg( refFileName )
|
||||
.arg( ( diffFileName ) );
|
||||
#endif
|
||||
QString completeCommand = QString( "\"%1\" %2" ).arg( m_compareExecutable ).arg( args );
|
||||
|
||||
// Launch process and wait
|
||||
QProcess proc;
|
||||
proc.start( completeCommand );
|
||||
proc.waitForFinished( 30000 );
|
||||
|
||||
QProcess::ProcessError procError = proc.error();
|
||||
if ( procError != QProcess::UnknownError )
|
||||
{
|
||||
m_lastError = ErrorType::SEVERE_ERROR;
|
||||
m_errorMsg = "Error running compare tool process";
|
||||
m_errorDetails = completeCommand;
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray stdErr = proc.readAllStandardError();
|
||||
int procExitCode = proc.exitCode();
|
||||
if ( procExitCode == 0 )
|
||||
{
|
||||
// Strip out whitespace and look for 0 (as in zero pixel differences)
|
||||
stdErr = stdErr.simplified();
|
||||
if ( !stdErr.isEmpty() && stdErr[0] == '0' )
|
||||
{
|
||||
m_imagesEqual = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Report non-severe error
|
||||
m_lastError = ErrorType::IC_ERROR;
|
||||
m_errorMsg = "Error running compare tool process";
|
||||
m_errorDetails = stdErr;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaImageFileCompare::imagesEqual() const
|
||||
{
|
||||
return m_imagesEqual;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaImageFileCompare::ErrorType RiaImageFileCompare::error() const
|
||||
{
|
||||
return m_lastError;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaImageFileCompare::errorMessage() const
|
||||
{
|
||||
return m_errorMsg;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaImageFileCompare::errorDetails() const
|
||||
{
|
||||
return m_errorDetails;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS
|
||||
//
|
||||
// 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>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
// Compare two images (currently using ImageMagick in an external process)
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaImageFileCompare
|
||||
{
|
||||
public:
|
||||
enum class ErrorType
|
||||
{
|
||||
IC_NO_ERROR, // No error occurred
|
||||
IC_ERROR, // An error occurred
|
||||
SEVERE_ERROR // Severe error occurred, it is likely that another call to compare() will also fail
|
||||
};
|
||||
|
||||
public:
|
||||
explicit RiaImageFileCompare( QString compareExecutable );
|
||||
~RiaImageFileCompare();
|
||||
|
||||
bool runComparison( const QString& imgFileName, const QString& refFileName, const QString& diffFileName );
|
||||
bool imagesEqual() const;
|
||||
ErrorType error() const;
|
||||
QString errorMessage() const;
|
||||
QString errorDetails() const;
|
||||
|
||||
private:
|
||||
void reset();
|
||||
|
||||
private:
|
||||
QString m_compareExecutable; // The executable for the ImageMagick compare tool
|
||||
bool m_imagesEqual; // Result of last comparison
|
||||
ErrorType m_lastError; // Error for last execution
|
||||
QString m_errorMsg;
|
||||
QString m_errorDetails;
|
||||
};
|
||||
@@ -0,0 +1,135 @@
|
||||
#include "RiaImageTools.h"
|
||||
|
||||
#include "cvfAssert.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QImage>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Meijster, Roerdink, Hesselink
|
||||
/// A GENERAL ALGORITHM FOR COMPUTING DISTANCE TRANSFORMS IN LINEAR TIME
|
||||
/// http://fab.cba.mit.edu/classes/S62.12/docs/Meijster_distance.pdf
|
||||
/// Currently Euclidean only, but can be easily extended by replacing the lambda functions.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaImageTools::distanceTransform2d( std::vector<std::vector<unsigned int>>& image )
|
||||
{
|
||||
if ( image.empty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ( image.front().empty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
const int64_t M = (int64_t)image.size();
|
||||
const int64_t N = (int64_t)image.front().size();
|
||||
|
||||
int64_t infVal = M + N;
|
||||
CVF_ASSERT( infVal <= std::numeric_limits<unsigned int>::max() );
|
||||
|
||||
// First phase
|
||||
std::vector<std::vector<int64_t>> g( M );
|
||||
|
||||
#pragma omp parallel for
|
||||
for ( int64_t x = 0; x < M; ++x )
|
||||
{
|
||||
g[x].resize( N, infVal );
|
||||
if ( image[x][0] )
|
||||
{
|
||||
g[x][0] = 0;
|
||||
}
|
||||
for ( int64_t y = 1; y < N - 1; ++y )
|
||||
{
|
||||
if ( image[x][y] )
|
||||
{
|
||||
g[x][y] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
g[x][y] = 1 + g[x][y - 1];
|
||||
}
|
||||
}
|
||||
for ( int64_t y = N - 2; y >= 0; --y )
|
||||
{
|
||||
if ( g[x][y + 1] < g[x][y] )
|
||||
{
|
||||
g[x][y] = 1 + g[x][y + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto f = []( int64_t x, int64_t i, const std::vector<std::vector<int64_t>>& g, int64_t y ) {
|
||||
return ( x - i ) * ( x - i ) + g[i][y] * g[i][y];
|
||||
};
|
||||
|
||||
auto sep = []( int64_t i, int64_t u, const std::vector<std::vector<int64_t>>& g, int64_t y ) {
|
||||
if ( i == u ) return (int64_t)0;
|
||||
|
||||
int64_t numerator = u * u - i * i + g[u][y] * g[u][y] - g[i][y] * g[i][y];
|
||||
int64_t divisor = 2 * ( u - i );
|
||||
return numerator / divisor;
|
||||
};
|
||||
|
||||
// Second phase
|
||||
#pragma omp parallel for
|
||||
for ( int64_t y = 0; y < N; ++y )
|
||||
{
|
||||
int64_t q = 0;
|
||||
std::vector<int64_t> s( std::max( N, M ), (int64_t)0 );
|
||||
std::vector<int64_t> t( std::max( N, M ), (int64_t)0 );
|
||||
|
||||
for ( int64_t u = 1; u < M - 1; ++u )
|
||||
{
|
||||
while ( q >= 0 && f( t[q], s[q], g, y ) > f( t[q], u, g, y ) )
|
||||
{
|
||||
q--;
|
||||
}
|
||||
if ( q < 0 )
|
||||
{
|
||||
q = 0;
|
||||
s[0] = u;
|
||||
}
|
||||
else
|
||||
{
|
||||
int64_t w = 1 + sep( (int64_t)s[q], u, g, y );
|
||||
if ( w < M )
|
||||
{
|
||||
q++;
|
||||
s[q] = u;
|
||||
t[q] = w;
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( int64_t u = M - 1; u >= 0; --u )
|
||||
{
|
||||
int64_t fVal = f( u, s[q], g, y );
|
||||
CVF_ASSERT( fVal <= std::numeric_limits<double>::max() );
|
||||
image[u][y] = static_cast<unsigned int>( fVal );
|
||||
if ( u == t[q] )
|
||||
{
|
||||
q = q - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaImageTools::makeGrayScale( QImage& image )
|
||||
{
|
||||
for ( int i = 0; i < image.height(); i++ )
|
||||
{
|
||||
uchar* scanLine = image.scanLine( i );
|
||||
for ( int j = 0; j < image.width(); j++ )
|
||||
{
|
||||
QRgb* pixel = reinterpret_cast<QRgb*>( scanLine + j * 4 );
|
||||
int gray = qGray( *pixel );
|
||||
int alpha = qAlpha( *pixel );
|
||||
*pixel = QColor( gray, gray, gray, alpha ).rgba();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2019- 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 <vector>
|
||||
|
||||
class QImage;
|
||||
|
||||
class RiaImageTools
|
||||
{
|
||||
public:
|
||||
static void distanceTransform2d( std::vector<std::vector<unsigned int>>& image );
|
||||
static void makeGrayScale( QImage& image );
|
||||
};
|
||||
@@ -0,0 +1,458 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaImportEclipseCaseTools.h"
|
||||
|
||||
#include "ApplicationCommands/RicShowMainWindowFeature.h"
|
||||
|
||||
#include "SummaryPlotCommands/RicNewSummaryCurveFeature.h"
|
||||
#include "SummaryPlotCommands/RicNewSummaryPlotFeature.h"
|
||||
#include "SummaryPlotCommands/RicSummaryPlotFeatureImpl.h"
|
||||
|
||||
#include "RiaApplication.h"
|
||||
#include "RiaGuiApplication.h"
|
||||
#include "RiaLogging.h"
|
||||
#include "RiaPreferences.h"
|
||||
|
||||
#include "RifEclipseSummaryTools.h"
|
||||
#include "RifSummaryCaseRestartSelector.h"
|
||||
|
||||
#include "RigGridManager.h"
|
||||
|
||||
#include "RimCaseCollection.h"
|
||||
#include "RimCompletionTemplateCollection.h"
|
||||
#include "RimEclipseCaseCollection.h"
|
||||
#include "RimEclipseCellColors.h"
|
||||
#include "RimEclipseInputCase.h"
|
||||
#include "RimEclipseResultCase.h"
|
||||
#include "RimEclipseView.h"
|
||||
#include "RimFileSummaryCase.h"
|
||||
#include "RimGridSummaryCase.h"
|
||||
#include "RimIdenticalGridCaseGroup.h"
|
||||
#include "RimMainPlotCollection.h"
|
||||
#include "RimOilField.h"
|
||||
#include "RimProject.h"
|
||||
#include "RimSummaryCase.h"
|
||||
#include "RimSummaryCaseCollection.h"
|
||||
#include "RimSummaryCaseMainCollection.h"
|
||||
#include "RimSummaryCurve.h"
|
||||
#include "RimSummaryCurveCollection.h"
|
||||
#include "RimSummaryCurveFilter.h"
|
||||
#include "RimSummaryPlot.h"
|
||||
#include "RimSummaryPlotCollection.h"
|
||||
#include "RimWellLogRftCurve.h"
|
||||
|
||||
#include "Riu3DMainWindowTools.h"
|
||||
#include "RiuMainWindow.h"
|
||||
#include "RiuPlotMainWindow.h"
|
||||
#include "RiuPlotMainWindowTools.h"
|
||||
|
||||
#include "cafProgressInfo.h"
|
||||
#include "cafUtils.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaImportEclipseCaseTools::openEclipseCasesFromFile( const QStringList& fileNames,
|
||||
FileCaseIdMap* openedFilesOut,
|
||||
bool noDialog )
|
||||
{
|
||||
RiaApplication* app = RiaApplication::instance();
|
||||
RimProject* project = app->project();
|
||||
|
||||
// Get list of files to import
|
||||
RifSummaryCaseRestartSelector selector;
|
||||
if ( noDialog ) selector.showDialog( false );
|
||||
selector.determineFilesToImportFromGridFiles( fileNames );
|
||||
std::vector<RifSummaryCaseFileResultInfo> summaryFileInfos = selector.summaryFileInfos();
|
||||
|
||||
FileCaseIdMap openedFiles;
|
||||
|
||||
// Import eclipse case files
|
||||
for ( const QString& gridCaseFile : selector.gridCaseFiles() )
|
||||
{
|
||||
int caseId = RiaImportEclipseCaseTools::openEclipseCaseFromFile( gridCaseFile );
|
||||
if ( caseId >= 0 )
|
||||
{
|
||||
openedFiles.insert( std::make_pair( gridCaseFile, caseId ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !openedFiles.empty() )
|
||||
{
|
||||
if ( project && project->mainPlotCollection() )
|
||||
{
|
||||
project->mainPlotCollection()->ensureDefaultFlowPlotsAreCreated();
|
||||
}
|
||||
}
|
||||
|
||||
// Import summary cases
|
||||
if ( !summaryFileInfos.empty() )
|
||||
{
|
||||
RimSummaryCaseMainCollection* sumCaseColl =
|
||||
project->activeOilField() ? project->activeOilField()->summaryCaseMainCollection() : nullptr;
|
||||
if ( sumCaseColl )
|
||||
{
|
||||
std::vector<RimSummaryCase*> newSumCases = sumCaseColl->createSummaryCasesFromFileInfos( summaryFileInfos );
|
||||
for ( RimSummaryCase* newSumCase : newSumCases )
|
||||
{
|
||||
RimSummaryCaseCollection* existingCollection = nullptr;
|
||||
QString gridCaseFile =
|
||||
RifEclipseSummaryTools::findGridCaseFileFromSummaryHeaderFile( newSumCase->summaryHeaderFilename() );
|
||||
RimEclipseCase* gridCase = project->eclipseCaseFromGridFileName( gridCaseFile );
|
||||
if ( gridCase )
|
||||
{
|
||||
RimSummaryCase* existingSummaryCase =
|
||||
sumCaseColl->findSummaryCaseFromFileName( newSumCase->summaryHeaderFilename() );
|
||||
RimGridSummaryCase* existingGridSummaryCase = dynamic_cast<RimGridSummaryCase*>( existingSummaryCase );
|
||||
RimFileSummaryCase* existingFileSummaryCase = dynamic_cast<RimFileSummaryCase*>( existingSummaryCase );
|
||||
if ( existingGridSummaryCase )
|
||||
{
|
||||
delete newSumCase; // No need to add anything new. Already have one.
|
||||
continue;
|
||||
}
|
||||
else if ( existingFileSummaryCase )
|
||||
{
|
||||
existingFileSummaryCase->firstAncestorOrThisOfType( existingCollection );
|
||||
|
||||
// Replace file summary case pointers in Rft Curves
|
||||
std::vector<RimWellLogRftCurve*> rftCurves;
|
||||
existingFileSummaryCase->objectsWithReferringPtrFieldsOfType( rftCurves );
|
||||
for ( RimWellLogRftCurve* curve : rftCurves )
|
||||
{
|
||||
if ( curve->summaryCase() == existingSummaryCase )
|
||||
{
|
||||
curve->setSummaryCase( newSumCase );
|
||||
}
|
||||
}
|
||||
|
||||
// Replace all occurrences of file sum with ecl sum
|
||||
|
||||
std::vector<RimSummaryCurve*> objects;
|
||||
existingFileSummaryCase->objectsWithReferringPtrFieldsOfType( objects );
|
||||
|
||||
// UI settings of a curve filter is updated based
|
||||
// on the new case association for the curves in the curve filter
|
||||
// UI is updated by loadDataAndUpdate()
|
||||
|
||||
for ( RimSummaryCurve* summaryCurve : objects )
|
||||
{
|
||||
if ( summaryCurve )
|
||||
{
|
||||
if ( summaryCurve->summaryCaseX() == existingSummaryCase )
|
||||
{
|
||||
summaryCurve->setSummaryCaseX( newSumCase );
|
||||
}
|
||||
if ( summaryCurve->summaryCaseY() == existingSummaryCase )
|
||||
{
|
||||
summaryCurve->setSummaryCaseY( newSumCase );
|
||||
}
|
||||
|
||||
RimSummaryCurveCollection* parentCollection = nullptr;
|
||||
summaryCurve->firstAncestorOrThisOfType( parentCollection );
|
||||
if ( parentCollection )
|
||||
{
|
||||
parentCollection->loadDataAndUpdate( true );
|
||||
parentCollection->updateConnectedEditors();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove existing case
|
||||
sumCaseColl->removeCase( existingFileSummaryCase );
|
||||
delete existingFileSummaryCase;
|
||||
}
|
||||
}
|
||||
if ( existingCollection )
|
||||
{
|
||||
existingCollection->addCase( newSumCase );
|
||||
}
|
||||
else
|
||||
{
|
||||
sumCaseColl->addCase( newSumCase );
|
||||
}
|
||||
sumCaseColl->updateAllRequiredEditors();
|
||||
}
|
||||
|
||||
if ( !newSumCases.empty() )
|
||||
{
|
||||
RimSummaryPlotCollection* summaryPlotColl = project->mainPlotCollection()->summaryPlotCollection();
|
||||
|
||||
RicSummaryPlotFeatureImpl::ensureAtLeastOnePlot( summaryPlotColl, newSumCases.front() );
|
||||
|
||||
RiuPlotMainWindowTools::setExpanded( newSumCases.front() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( selector.foundErrors() )
|
||||
{
|
||||
QString errorMessage = selector.createCombinedErrorMessage();
|
||||
RiaLogging::error( errorMessage );
|
||||
}
|
||||
|
||||
project->activeOilField()->completionTemplateCollection()->setDefaultUnitSystemBasedOnLoadedCases();
|
||||
|
||||
RiuPlotMainWindowTools::refreshToolbars();
|
||||
|
||||
if ( openedFilesOut )
|
||||
{
|
||||
*openedFilesOut = openedFiles;
|
||||
}
|
||||
|
||||
return !openedFiles.empty();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiaImportEclipseCaseTools::openEclipseCaseFromFile( const QString& fileName )
|
||||
{
|
||||
if ( !caf::Utils::fileExists( fileName ) ) return -1;
|
||||
|
||||
return RiaImportEclipseCaseTools::openEclipseCaseShowTimeStepFilterImpl( fileName, false );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaImportEclipseCaseTools::openEclipseCaseShowTimeStepFilter( const QString& fileName )
|
||||
{
|
||||
if ( !caf::Utils::fileExists( fileName ) ) return false;
|
||||
|
||||
return RiaImportEclipseCaseTools::openEclipseCaseShowTimeStepFilterImpl( fileName, true ) >= 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaImportEclipseCaseTools::openEclipseInputCaseFromFileNames( const QStringList& fileNames,
|
||||
QString* fileContainingGrid /*=nullptr*/ )
|
||||
{
|
||||
RimEclipseInputCase* rimInputReservoir = new RimEclipseInputCase();
|
||||
|
||||
RiaApplication* app = RiaApplication::instance();
|
||||
RimProject* project = app->project();
|
||||
|
||||
project->assignCaseIdToCase( rimInputReservoir );
|
||||
|
||||
bool gridImportSuccess = rimInputReservoir->openDataFileSet( fileNames );
|
||||
if ( !gridImportSuccess )
|
||||
{
|
||||
RiaLogging::error( "Failed to import grid" );
|
||||
return false;
|
||||
}
|
||||
|
||||
RimEclipseCaseCollection* analysisModels = project->activeOilField() ? project->activeOilField()->analysisModels()
|
||||
: nullptr;
|
||||
if ( analysisModels == nullptr ) return false;
|
||||
|
||||
analysisModels->cases.push_back( rimInputReservoir );
|
||||
|
||||
RimEclipseView* riv = rimInputReservoir->createAndAddReservoirView();
|
||||
|
||||
riv->cellResult()->setResultType( RiaDefines::ResultCatType::INPUT_PROPERTY );
|
||||
|
||||
riv->loadDataAndUpdate();
|
||||
|
||||
if ( !riv->cellResult()->hasResult() )
|
||||
{
|
||||
riv->cellResult()->setResultVariable( RiaDefines::undefinedResultName() );
|
||||
}
|
||||
|
||||
analysisModels->updateConnectedEditors();
|
||||
|
||||
Riu3DMainWindowTools::selectAsCurrentItem( riv->cellResult() );
|
||||
|
||||
if ( fileContainingGrid )
|
||||
{
|
||||
*fileContainingGrid = rimInputReservoir->gridFileName();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaImportEclipseCaseTools::openMockModel( const QString& name )
|
||||
{
|
||||
return RiaImportEclipseCaseTools::openEclipseCaseShowTimeStepFilterImpl( name, false );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiaImportEclipseCaseTools::openEclipseCaseShowTimeStepFilterImpl( const QString& fileName, bool showTimeStepFilter )
|
||||
{
|
||||
QFileInfo gridFileName( fileName );
|
||||
QString caseName = gridFileName.completeBaseName();
|
||||
|
||||
RimEclipseResultCase* rimResultReservoir = new RimEclipseResultCase();
|
||||
rimResultReservoir->setCaseInfo( caseName, fileName );
|
||||
|
||||
RiaApplication* app = RiaApplication::instance();
|
||||
RimProject* project = app->project();
|
||||
|
||||
RimEclipseCaseCollection* analysisModels = project->activeOilField() ? project->activeOilField()->analysisModels()
|
||||
: nullptr;
|
||||
if ( analysisModels == nullptr )
|
||||
{
|
||||
delete rimResultReservoir;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( RiaGuiApplication::isRunning() )
|
||||
{
|
||||
RicShowMainWindowFeature::showMainWindow();
|
||||
}
|
||||
|
||||
analysisModels->cases.push_back( rimResultReservoir );
|
||||
|
||||
if ( !rimResultReservoir->importGridAndResultMetaData( showTimeStepFilter ) )
|
||||
{
|
||||
analysisModels->removeCaseFromAllGroups( rimResultReservoir );
|
||||
|
||||
delete rimResultReservoir;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
RimEclipseView* riv = rimResultReservoir->createAndAddReservoirView();
|
||||
|
||||
riv->loadDataAndUpdate();
|
||||
|
||||
if ( !riv->cellResult()->hasResult() )
|
||||
{
|
||||
riv->cellResult()->setResultVariable( RiaDefines::undefinedResultName() );
|
||||
}
|
||||
|
||||
analysisModels->updateConnectedEditors();
|
||||
|
||||
if ( RiaGuiApplication::isRunning() )
|
||||
{
|
||||
RiuMainWindow::instance()->selectAsCurrentItem( riv->cellResult() );
|
||||
}
|
||||
return rimResultReservoir->caseId();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaImportEclipseCaseTools::addEclipseCases( const QStringList& fileNames,
|
||||
RimIdenticalGridCaseGroup** resultingCaseGroup /*=nullptr*/ )
|
||||
{
|
||||
if ( fileNames.size() == 0 ) return true;
|
||||
|
||||
// First file is read completely including grid.
|
||||
// The main grid from the first case is reused directly in for the other cases.
|
||||
// When reading active cell info, only the total cell count is tested for consistency
|
||||
RimEclipseResultCase* mainResultCase = nullptr;
|
||||
std::vector<std::vector<int>> mainCaseGridDimensions;
|
||||
RimIdenticalGridCaseGroup* gridCaseGroup = nullptr;
|
||||
|
||||
RiaApplication* app = RiaApplication::instance();
|
||||
RimProject* project = app->project();
|
||||
|
||||
{
|
||||
QString firstFileName = fileNames[0];
|
||||
QFileInfo gridFileName( firstFileName );
|
||||
|
||||
QString caseName = gridFileName.completeBaseName();
|
||||
|
||||
RimEclipseResultCase* rimResultReservoir = new RimEclipseResultCase();
|
||||
rimResultReservoir->setCaseInfo( caseName, firstFileName );
|
||||
if ( !rimResultReservoir->openEclipseGridFile() )
|
||||
{
|
||||
delete rimResultReservoir;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
rimResultReservoir->readGridDimensions( mainCaseGridDimensions );
|
||||
|
||||
mainResultCase = rimResultReservoir;
|
||||
RimOilField* oilField = project->activeOilField();
|
||||
if ( oilField && oilField->analysisModels() )
|
||||
{
|
||||
gridCaseGroup = oilField->analysisModels->createIdenticalCaseGroupFromMainCase( mainResultCase );
|
||||
}
|
||||
}
|
||||
|
||||
caf::ProgressInfo info( fileNames.size(), "Reading Active Cell data" );
|
||||
|
||||
for ( int i = 1; i < fileNames.size(); i++ )
|
||||
{
|
||||
QString caseFileName = fileNames[i];
|
||||
QFileInfo gridFileName( caseFileName );
|
||||
|
||||
QString caseName = gridFileName.completeBaseName();
|
||||
|
||||
RimEclipseResultCase* rimResultReservoir = new RimEclipseResultCase();
|
||||
rimResultReservoir->setCaseInfo( caseName, caseFileName );
|
||||
|
||||
std::vector<std::vector<int>> caseGridDimensions;
|
||||
rimResultReservoir->readGridDimensions( caseGridDimensions );
|
||||
|
||||
bool identicalGrid = RigGridManager::isGridDimensionsEqual( mainCaseGridDimensions, caseGridDimensions );
|
||||
if ( identicalGrid )
|
||||
{
|
||||
if ( rimResultReservoir->openAndReadActiveCellData( mainResultCase->eclipseCaseData() ) )
|
||||
{
|
||||
RimOilField* oilField = project->activeOilField();
|
||||
if ( oilField && oilField->analysisModels() )
|
||||
{
|
||||
oilField->analysisModels()->insertCaseInCaseGroup( gridCaseGroup, rimResultReservoir );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete rimResultReservoir;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete rimResultReservoir;
|
||||
}
|
||||
|
||||
info.setProgress( i );
|
||||
}
|
||||
|
||||
if ( gridCaseGroup )
|
||||
{
|
||||
// Create placeholder results and propagate results info from main case to all other cases
|
||||
gridCaseGroup->loadMainCaseAndActiveCellInfo();
|
||||
|
||||
if ( resultingCaseGroup )
|
||||
{
|
||||
*resultingCaseGroup = gridCaseGroup;
|
||||
}
|
||||
}
|
||||
|
||||
project->activeOilField()->analysisModels()->updateConnectedEditors();
|
||||
|
||||
if ( RiaGuiApplication::isRunning() && gridCaseGroup && gridCaseGroup->statisticsCaseCollection()->reservoirs.size() > 0 )
|
||||
{
|
||||
RiuMainWindow::instance()->selectAsCurrentItem( gridCaseGroup->statisticsCaseCollection()->reservoirs[0] );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 <map>
|
||||
|
||||
class QString;
|
||||
class QStringList;
|
||||
|
||||
class RimIdenticalGridCaseGroup;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RiaImportEclipseCaseTools
|
||||
{
|
||||
public:
|
||||
typedef std::map<QString, int> FileCaseIdMap;
|
||||
|
||||
static bool openEclipseCasesFromFile( const QStringList& fileNames,
|
||||
FileCaseIdMap* openedFilesOut = nullptr,
|
||||
bool noDialog = false );
|
||||
static bool openEclipseCaseShowTimeStepFilter( const QString& fileName );
|
||||
|
||||
static bool openEclipseInputCaseFromFileNames( const QStringList& fileNames, QString* fileContainingGrid = nullptr );
|
||||
static bool openMockModel( const QString& name );
|
||||
|
||||
static bool addEclipseCases( const QStringList& fileNames, RimIdenticalGridCaseGroup** resultingCaseGroup = nullptr );
|
||||
|
||||
private:
|
||||
static int openEclipseCaseFromFile( const QString& fileName );
|
||||
static int openEclipseCaseShowTimeStepFilterImpl( const QString& fileName, bool showTimeStepFilter );
|
||||
};
|
||||
@@ -0,0 +1,212 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020 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 "RiaInterpolationTools.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool almostEqual( double a, double b, double maxRelDiff = std::numeric_limits<double>::epsilon() * 128 )
|
||||
{
|
||||
// Calculate the difference.
|
||||
double diff = std::fabs( a - b );
|
||||
double fabsa = std::fabs( a );
|
||||
double fabsb = std::fabs( b );
|
||||
// Find the largest
|
||||
double largest = ( fabsb > fabsa ) ? fabsb : fabsa;
|
||||
return ( diff <= largest * maxRelDiff );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaInterpolationTools::linear( const std::vector<double>& x, const std::vector<double>& y, double value )
|
||||
{
|
||||
assert( x.size() == y.size() );
|
||||
|
||||
// Handle cases with only one data point.
|
||||
if ( x.size() <= 1 )
|
||||
{
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
// Find the lower boundary
|
||||
bool found = false;
|
||||
int lowerIndex = 0;
|
||||
for ( int i = 0; i < static_cast<int>( x.size() - 1 ); i++ )
|
||||
{
|
||||
if ( x[i] <= value && x[i + 1] >= value )
|
||||
{
|
||||
lowerIndex = i;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Value is outside of the defined range
|
||||
if ( !found )
|
||||
{
|
||||
// Check if we are just outside the boundaries
|
||||
if ( almostEqual( value, x[0] ) )
|
||||
return y[0];
|
||||
else if ( almostEqual( value, x[x.size() - 1] ) )
|
||||
return y[x.size() - 1];
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
int upperIndex = lowerIndex + 1;
|
||||
|
||||
double lowerX = x[lowerIndex];
|
||||
double lowerY = y[lowerIndex];
|
||||
double upperX = x[upperIndex];
|
||||
double upperY = y[upperIndex];
|
||||
|
||||
double deltaY = upperY - lowerY;
|
||||
double deltaX = upperX - lowerX;
|
||||
|
||||
return lowerY + ( ( value - lowerX ) / deltaX ) * deltaY;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaInterpolationTools::extrapolate( const std::vector<double>& x, const std::vector<double>& y, double value )
|
||||
{
|
||||
return y[0] + ( value - x[0] ) / ( x[1] - x[0] ) * ( y[1] - y[0] );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiaInterpolationTools::findNextDataPoint( const std::vector<double>& values, int index )
|
||||
{
|
||||
for ( size_t i = index; i < values.size(); i++ )
|
||||
{
|
||||
if ( values[i] != std::numeric_limits<double>::infinity() ) return static_cast<int>( i );
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiaInterpolationTools::findPreviousDataPoint( const std::vector<double>& values, int index )
|
||||
{
|
||||
assert( index >= 0 );
|
||||
|
||||
for ( int i = index; i >= 0; i-- )
|
||||
{
|
||||
if ( values[i] != std::numeric_limits<double>::infinity() ) return static_cast<int>( i );
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiaInterpolationTools::extrapolateRange( int start,
|
||||
int end,
|
||||
int firstPoint,
|
||||
int lastPoint,
|
||||
const std::vector<double>& x,
|
||||
std::vector<double>& y )
|
||||
{
|
||||
std::vector<double> xs = { x[firstPoint], x[lastPoint] };
|
||||
std::vector<double> ys = { y[firstPoint], y[lastPoint] };
|
||||
for ( int index = start; index < end; index++ )
|
||||
{
|
||||
y[index] = extrapolate( xs, ys, x[index] );
|
||||
}
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiaInterpolationTools::interpolateRange( int start,
|
||||
int end,
|
||||
int firstPoint,
|
||||
int lastPoint,
|
||||
const std::vector<double>& x,
|
||||
std::vector<double>& y )
|
||||
{
|
||||
assert( start <= end );
|
||||
|
||||
std::vector<double> xs = { x[firstPoint], x[lastPoint] };
|
||||
std::vector<double> ys = { y[firstPoint], y[lastPoint] };
|
||||
for ( int index = start; index < end; index++ )
|
||||
{
|
||||
y[index] = RiaInterpolationTools::linear( xs, ys, x[index] );
|
||||
}
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaInterpolationTools::interpolateMissingValues( const std::vector<double>& x, std::vector<double>& y )
|
||||
{
|
||||
assert( x.size() == y.size() );
|
||||
|
||||
int index = 0;
|
||||
|
||||
// Previous index which is not inf
|
||||
int prevSetIndex = -1;
|
||||
|
||||
while ( index < static_cast<int>( y.size() ) )
|
||||
{
|
||||
// Missing values are inf in the input data
|
||||
if ( y[index] == std::numeric_limits<double>::infinity() )
|
||||
{
|
||||
// Find the next index with a value
|
||||
int nextSetIndex = findNextDataPoint( y, index + 1 );
|
||||
|
||||
if ( prevSetIndex == -1 )
|
||||
{
|
||||
// The first value is inf: need to find next two valid points and extrapolate
|
||||
int nextSetIndex2 = findNextDataPoint( y, nextSetIndex + 1 );
|
||||
index = extrapolateRange( index, nextSetIndex, nextSetIndex, nextSetIndex2, x, y );
|
||||
}
|
||||
else if ( nextSetIndex == -1 )
|
||||
{
|
||||
// The last value is inf: extrapolate from two last data points
|
||||
int prevSetIndex2 = findPreviousDataPoint( y, prevSetIndex - 1 );
|
||||
index = extrapolateRange( index, (int)y.size(), prevSetIndex2, prevSetIndex, x, y );
|
||||
}
|
||||
else if ( nextSetIndex != static_cast<int>( y.size() ) )
|
||||
{
|
||||
// The missing values somewhere between non-inf data: interpolate all the values
|
||||
index = interpolateRange( index, nextSetIndex, prevSetIndex, nextSetIndex, x, y );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing to do for the values which are not missing
|
||||
prevSetIndex = index;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020 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 <vector>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaInterpolationTools
|
||||
{
|
||||
public:
|
||||
static double linear( const std::vector<double>& x, const std::vector<double>& y, double value );
|
||||
|
||||
// Interpolate/extrapolate away inf values in y vector.
|
||||
static void interpolateMissingValues( const std::vector<double>& x, std::vector<double>& y );
|
||||
|
||||
private:
|
||||
static int interpolateRange( int start,
|
||||
int end,
|
||||
int firstPoint,
|
||||
int lastPoint,
|
||||
const std::vector<double>& x,
|
||||
std::vector<double>& y );
|
||||
static int extrapolateRange( int start,
|
||||
int end,
|
||||
int firstPoint,
|
||||
int lastPoint,
|
||||
const std::vector<double>& x,
|
||||
std::vector<double>& y );
|
||||
static int findNextDataPoint( const std::vector<double>& values, int index );
|
||||
static int findPreviousDataPoint( const std::vector<double>& values, int index );
|
||||
static double extrapolate( const std::vector<double>& x, const std::vector<double>& y, double value );
|
||||
};
|
||||
@@ -0,0 +1,334 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaLogging.h"
|
||||
#include "RiaGuiApplication.h"
|
||||
#include "RiaRegressionTestRunner.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4668 )
|
||||
// Define this one to tell windows.h to not define min() and max() as macros
|
||||
#if defined WIN32 && !defined NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#pragma warning( pop )
|
||||
#else
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaDefaultConsoleLogger : public RiaLogger
|
||||
{
|
||||
public:
|
||||
RiaDefaultConsoleLogger();
|
||||
|
||||
int level() const override;
|
||||
void setLevel( int logLevel ) override;
|
||||
void error( const char* message ) override;
|
||||
void warning( const char* message ) override;
|
||||
void info( const char* message ) override;
|
||||
void debug( const char* message ) override;
|
||||
|
||||
private:
|
||||
static void writeMessageToConsole( const char* prefix, const char* message );
|
||||
static void writeToConsole( const std::string& str );
|
||||
|
||||
private:
|
||||
int m_logLevel;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaDefaultConsoleLogger::RiaDefaultConsoleLogger()
|
||||
: m_logLevel( int( RILogLevel::RI_LL_WARNING ) )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiaDefaultConsoleLogger::level() const
|
||||
{
|
||||
return m_logLevel;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaDefaultConsoleLogger::setLevel( int logLevel )
|
||||
{
|
||||
m_logLevel = logLevel;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaDefaultConsoleLogger::error( const char* message )
|
||||
{
|
||||
writeMessageToConsole( "ERROR: ", message );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaDefaultConsoleLogger::warning( const char* message )
|
||||
{
|
||||
writeMessageToConsole( "warn: ", message );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaDefaultConsoleLogger::info( const char* message )
|
||||
{
|
||||
writeMessageToConsole( "info: ", message );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaDefaultConsoleLogger::debug( const char* message )
|
||||
{
|
||||
writeMessageToConsole( "debug: ", message );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaDefaultConsoleLogger::writeMessageToConsole( const char* prefix, const char* message )
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
// VF_ASSERT(prefix);
|
||||
oss << prefix;
|
||||
|
||||
if ( message )
|
||||
{
|
||||
oss << message << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << "<no message>" << std::endl;
|
||||
}
|
||||
|
||||
writeToConsole( oss.str() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaDefaultConsoleLogger::writeToConsole( const std::string& str )
|
||||
{
|
||||
#ifdef WIN32
|
||||
AllocConsole();
|
||||
HANDLE hStdOutputHandle = GetStdHandle( STD_OUTPUT_HANDLE );
|
||||
if ( hStdOutputHandle )
|
||||
{
|
||||
DWORD stringLength = static_cast<DWORD>( str.length() );
|
||||
|
||||
unsigned long iDum = 0;
|
||||
WriteConsoleA( hStdOutputHandle, str.c_str(), stringLength, &iDum, nullptr );
|
||||
}
|
||||
#else
|
||||
fputs( str.c_str(), stderr );
|
||||
#endif
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
|
||||
std::unique_ptr<RiaLogger> RiaLogging::sm_logger = std::make_unique<RiaDefaultConsoleLogger>();
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaLogger* RiaLogging::loggerInstance()
|
||||
{
|
||||
return sm_logger.get();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaLogging::setLoggerInstance( std::unique_ptr<RiaLogger> loggerInstance )
|
||||
{
|
||||
sm_logger = std::move( loggerInstance );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaLogging::error( const QString& message )
|
||||
{
|
||||
if ( sm_logger && sm_logger->level() >= int( RILogLevel::RI_LL_ERROR ) )
|
||||
{
|
||||
#pragma omp critical( critical_section_logging )
|
||||
sm_logger->error( message.toLatin1().constData() );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaLogging::warning( const QString& message )
|
||||
{
|
||||
if ( sm_logger && sm_logger->level() >= int( RILogLevel::RI_LL_WARNING ) )
|
||||
{
|
||||
#pragma omp critical( critical_section_logging )
|
||||
sm_logger->warning( message.toLatin1().constData() );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaLogging::info( const QString& message )
|
||||
{
|
||||
if ( sm_logger && sm_logger->level() >= int( RILogLevel::RI_LL_INFO ) )
|
||||
{
|
||||
#pragma omp critical( critical_section_logging )
|
||||
sm_logger->info( message.toLatin1().constData() );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaLogging::debug( const QString& message )
|
||||
{
|
||||
if ( sm_logger && sm_logger->level() >= int( RILogLevel::RI_LL_DEBUG ) )
|
||||
{
|
||||
#pragma omp critical( critical_section_logging )
|
||||
sm_logger->debug( message.toLatin1().constData() );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaLogging::errorInMessageBox( QWidget* parent, const QString& title, const QString& text )
|
||||
{
|
||||
if ( RiaGuiApplication::isRunning() && !RiaRegressionTestRunner::instance()->isRunningRegressionTests() )
|
||||
{
|
||||
QMessageBox::warning( parent, title, text );
|
||||
}
|
||||
|
||||
RiaLogging::error( text );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiuMessageLoggerBase::RiuMessageLoggerBase()
|
||||
: m_logLevel( (int)RILogLevel::RI_LL_WARNING )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiuMessageLoggerBase::level() const
|
||||
{
|
||||
return m_logLevel;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMessageLoggerBase::setLevel( int logLevel )
|
||||
{
|
||||
m_logLevel = logLevel;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMessageLoggerBase::error( const char* message )
|
||||
{
|
||||
writeMessageWithPrefixToLogger( "ERROR: ", message );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMessageLoggerBase::warning( const char* message )
|
||||
{
|
||||
writeMessageWithPrefixToLogger( "warning: ", message );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMessageLoggerBase::info( const char* message )
|
||||
{
|
||||
writeMessageWithPrefixToLogger( "info: ", message );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMessageLoggerBase::debug( const char* message )
|
||||
{
|
||||
writeMessageWithPrefixToLogger( "debug: ", message );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMessageLoggerBase::writeMessageWithPrefixToLogger( const char* prefix, const char* message )
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << prefix;
|
||||
|
||||
if ( message )
|
||||
{
|
||||
oss << message << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << "<no message>" << std::endl;
|
||||
}
|
||||
|
||||
writeMessageToLogger( oss.str() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaStdOutLogger::writeMessageToLogger( const std::string& str )
|
||||
{
|
||||
std::cout << str;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 <memory>
|
||||
#include <string>
|
||||
|
||||
class QString;
|
||||
class QWidget;
|
||||
|
||||
enum class RILogLevel
|
||||
{
|
||||
RI_LL_ERROR = 1,
|
||||
RI_LL_WARNING = 2,
|
||||
RI_LL_INFO = 3,
|
||||
RI_LL_DEBUG = 4
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
// Logger interface for the application
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaLogger
|
||||
{
|
||||
public:
|
||||
virtual ~RiaLogger() {}
|
||||
|
||||
virtual int level() const = 0;
|
||||
virtual void setLevel( int logLevel ) = 0;
|
||||
|
||||
virtual void error( const char* message ) = 0;
|
||||
virtual void warning( const char* message ) = 0;
|
||||
virtual void info( const char* message ) = 0;
|
||||
virtual void debug( const char* message ) = 0;
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaLogging
|
||||
{
|
||||
public:
|
||||
static RiaLogger* loggerInstance();
|
||||
static void setLoggerInstance( std::unique_ptr<RiaLogger> loggerInstance );
|
||||
|
||||
static void error( const QString& message );
|
||||
static void warning( const QString& message );
|
||||
static void info( const QString& message );
|
||||
static void debug( const QString& message );
|
||||
|
||||
static void errorInMessageBox( QWidget* parent, const QString& title, const QString& text );
|
||||
|
||||
private:
|
||||
static std::unique_ptr<RiaLogger> sm_logger;
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiuMessageLoggerBase : public RiaLogger
|
||||
{
|
||||
public:
|
||||
explicit RiuMessageLoggerBase();
|
||||
|
||||
int level() const override;
|
||||
void setLevel( int logLevel ) override;
|
||||
|
||||
void error( const char* message ) override;
|
||||
void warning( const char* message ) override;
|
||||
void info( const char* message ) override;
|
||||
void debug( const char* message ) override;
|
||||
|
||||
protected:
|
||||
virtual void writeMessageToLogger( const std::string& str ) = 0;
|
||||
|
||||
private:
|
||||
void writeMessageWithPrefixToLogger( const char* prefix, const char* message );
|
||||
|
||||
private:
|
||||
int m_logLevel;
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaStdOutLogger : public RiuMessageLoggerBase
|
||||
{
|
||||
public:
|
||||
void writeMessageToLogger( const std::string& str ) override;
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020- 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 "cafAssert.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
class RiaMedianCalculator
|
||||
{
|
||||
public:
|
||||
RiaMedianCalculator() = default;
|
||||
|
||||
void add( T value );
|
||||
double median() const;
|
||||
bool valid() const;
|
||||
|
||||
private:
|
||||
std::vector<T> m_values;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void RiaMedianCalculator<T>::add( T value )
|
||||
{
|
||||
m_values.insert( std::lower_bound( m_values.begin(), m_values.end(), value ), value );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
double RiaMedianCalculator<T>::median() const
|
||||
{
|
||||
CAF_ASSERT( valid() && "You must ensure the result is valid before calling this" );
|
||||
|
||||
auto count = m_values.size();
|
||||
if ( count == 1u )
|
||||
return m_values.front();
|
||||
else if ( count % 2 == 0 )
|
||||
{
|
||||
return ( m_values[count / 2 - 1] + m_values[count / 2] ) * 0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_values[count / 2];
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
bool RiaMedianCalculator<T>::valid() const
|
||||
{
|
||||
return !m_values.empty();
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "cvfVector3.h"
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
|
||||
// Y - North, X - East, Z - up but depth is negative Z
|
||||
// azi is measured from the Northing (Y) Axis in Clockwise direction looking down
|
||||
// inc is measured from the negative Z (depth) axis
|
||||
|
||||
const double singularityEpsilon = 1.0e-5;
|
||||
|
||||
class RiaOffshoreSphericalCoords
|
||||
{
|
||||
public:
|
||||
explicit RiaOffshoreSphericalCoords( const cvf::Vec3f& vec )
|
||||
{
|
||||
// Azimuth:
|
||||
if ( fabs( vec[0] ) < singularityEpsilon && fabs( vec[1] ) < singularityEpsilon )
|
||||
incAziR[1] = 0.0f;
|
||||
else
|
||||
incAziR[1] = atan2( vec[0], vec[1] ); // atan2(Y, X)
|
||||
|
||||
// R
|
||||
incAziR[2] = vec.length();
|
||||
|
||||
// Inclination from vertical down
|
||||
if ( fabs( incAziR[2] ) < singularityEpsilon )
|
||||
incAziR[0] = 0.0f;
|
||||
else
|
||||
incAziR[0] = acos( -vec[2] / incAziR[2] );
|
||||
}
|
||||
|
||||
explicit RiaOffshoreSphericalCoords( const cvf::Vec3d& vec )
|
||||
{
|
||||
// Azimuth:
|
||||
if ( fabs( vec[0] ) < singularityEpsilon && fabs( vec[1] ) < singularityEpsilon )
|
||||
incAziR[1] = 0.0;
|
||||
else
|
||||
incAziR[1] = atan2( vec[0], vec[1] ); // atan2(Y, X)
|
||||
|
||||
// R
|
||||
incAziR[2] = vec.length();
|
||||
|
||||
// Inclination from vertical down
|
||||
if ( fabs( incAziR[2] ) < singularityEpsilon )
|
||||
incAziR[0] = 0.0;
|
||||
else
|
||||
incAziR[0] = acos( -vec[2] / incAziR[2] );
|
||||
}
|
||||
double inc() const { return incAziR[0]; }
|
||||
double azi() const { return incAziR[1]; }
|
||||
double r() const { return incAziR[2]; }
|
||||
|
||||
// Note that this is a double function, while the rest of the class is float.
|
||||
// Todo: Convert class to a template to enable float and double versions of everything
|
||||
static cvf::Vec3d unitVectorFromAziInc( double azimuth, double inclination )
|
||||
{
|
||||
return cvf::Vec3d( sin( azimuth ) * sin( inclination ), cos( azimuth ) * sin( inclination ), -cos( inclination ) );
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<double, 3> incAziR;
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaOptionItemFactory.h"
|
||||
|
||||
#include "Rim3dView.h"
|
||||
#include "RimCase.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaOptionItemFactory::appendOptionItemFromViewNameAndCaseName( Rim3dView* view,
|
||||
QList<caf::PdmOptionItemInfo>* optionItems )
|
||||
{
|
||||
if ( !view || !optionItems ) return;
|
||||
|
||||
QString displayName = view->autoName();
|
||||
|
||||
caf::IconProvider iconProvider = view->uiCapability()->uiIconProvider();
|
||||
|
||||
optionItems->push_back( caf::PdmOptionItemInfo( displayName, view, false, iconProvider ) );
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "cafPdmUiItem.h"
|
||||
|
||||
#include <QList>
|
||||
|
||||
class Rim3dView;
|
||||
|
||||
class RiaOptionItemFactory
|
||||
{
|
||||
public:
|
||||
static void appendOptionItemFromViewNameAndCaseName( Rim3dView* view, QList<caf::PdmOptionItemInfo>* optionItems );
|
||||
};
|
||||
@@ -0,0 +1,159 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaProjectFileVersionTools.h"
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaProjectFileVersionTools::isCandidateVersionNewerThanOther( const QString& candidateProjectFileVersion,
|
||||
const QString& projectFileVersion )
|
||||
{
|
||||
int candidateMajorVersion = 0;
|
||||
int candidateMinorVersion = 0;
|
||||
int candidatePatchNumber = 0;
|
||||
int candidateDevelopmentId = 0;
|
||||
|
||||
RiaProjectFileVersionTools::decodeVersionString( candidateProjectFileVersion,
|
||||
&candidateMajorVersion,
|
||||
&candidateMinorVersion,
|
||||
&candidatePatchNumber,
|
||||
&candidateDevelopmentId );
|
||||
|
||||
int majorVersion = 0;
|
||||
int minorVersion = 0;
|
||||
int patchNumber = 0;
|
||||
int developmentId = 0;
|
||||
|
||||
RiaProjectFileVersionTools::decodeVersionString( projectFileVersion,
|
||||
&majorVersion,
|
||||
&minorVersion,
|
||||
&patchNumber,
|
||||
&developmentId );
|
||||
|
||||
return RiaProjectFileVersionTools::isCandidateNewerThanOther( candidateMajorVersion,
|
||||
candidateMinorVersion,
|
||||
candidatePatchNumber,
|
||||
candidateDevelopmentId,
|
||||
majorVersion,
|
||||
minorVersion,
|
||||
patchNumber,
|
||||
developmentId );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaProjectFileVersionTools::decodeVersionString( const QString& projectFileVersion,
|
||||
int* majorVersion,
|
||||
int* minorVersion,
|
||||
int* patch,
|
||||
int* developmentId )
|
||||
{
|
||||
if ( projectFileVersion.isEmpty() ) return;
|
||||
|
||||
QStringList subStrings = projectFileVersion.split( "." );
|
||||
|
||||
if ( subStrings.size() > 0 )
|
||||
{
|
||||
*majorVersion = subStrings[0].toInt();
|
||||
}
|
||||
|
||||
if ( subStrings.size() > 1 )
|
||||
{
|
||||
*minorVersion = subStrings[1].toInt();
|
||||
}
|
||||
|
||||
if ( subStrings.size() > 2 )
|
||||
{
|
||||
QString candidate = subStrings[2];
|
||||
QString candidateDigitsOnly = RiaProjectFileVersionTools::stringOfDigits( candidate );
|
||||
|
||||
*patch = candidateDigitsOnly.toInt();
|
||||
}
|
||||
|
||||
if ( subStrings.size() > 3 )
|
||||
{
|
||||
QString candidate = subStrings.back();
|
||||
QString candidateDigitsOnly = RiaProjectFileVersionTools::stringOfDigits( candidate );
|
||||
|
||||
*developmentId = candidateDigitsOnly.toInt();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaProjectFileVersionTools::isCandidateNewerThanOther( int candidateMajorVersion,
|
||||
int candidateMinorVersion,
|
||||
int candidatePatchNumber,
|
||||
int candidateDevelopmentId,
|
||||
int otherMajorVersion,
|
||||
int otherMinorVersion,
|
||||
int otherPatchNumber,
|
||||
int otherDevelopmentId )
|
||||
{
|
||||
if ( candidateMajorVersion != otherMajorVersion )
|
||||
{
|
||||
return ( candidateMajorVersion > otherMajorVersion );
|
||||
}
|
||||
|
||||
if ( candidateMinorVersion != otherMinorVersion )
|
||||
{
|
||||
return ( candidateMinorVersion > otherMinorVersion );
|
||||
}
|
||||
|
||||
if ( candidatePatchNumber != otherPatchNumber )
|
||||
{
|
||||
return ( candidatePatchNumber > otherPatchNumber );
|
||||
}
|
||||
|
||||
if ( candidateDevelopmentId != otherDevelopmentId )
|
||||
{
|
||||
return ( candidateDevelopmentId > otherDevelopmentId );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaProjectFileVersionTools::stringOfDigits( const QString& string )
|
||||
{
|
||||
QString digitsOnly;
|
||||
|
||||
for ( const auto& c : string )
|
||||
{
|
||||
if ( c.isDigit() )
|
||||
{
|
||||
digitsOnly += c;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !digitsOnly.isEmpty() )
|
||||
{
|
||||
return digitsOnly;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return digitsOnly;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 <QString>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaProjectFileVersionTools
|
||||
{
|
||||
public:
|
||||
static bool isCandidateVersionNewerThanOther( const QString& candidateProjectFileVersion,
|
||||
const QString& otherProjectFileVersion );
|
||||
|
||||
// Public to be able to unit test function, not intended to be used
|
||||
static void decodeVersionString( const QString& projectFileVersion,
|
||||
int* majorVersion,
|
||||
int* minorVersion,
|
||||
int* patch,
|
||||
int* developmentId );
|
||||
|
||||
private:
|
||||
static bool isCandidateNewerThanOther( int candidateMajorVersion,
|
||||
int candidateMinorVersion,
|
||||
int candidatePatchNumber,
|
||||
int candidateDevelopmentId,
|
||||
int otherMajorVersion,
|
||||
int otherMinorVersion,
|
||||
int otherPatchNumber,
|
||||
int otherDevelopmentId );
|
||||
|
||||
static QString stringOfDigits( const QString& string );
|
||||
};
|
||||
@@ -0,0 +1,354 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) Statoil ASA
|
||||
// Copyright (C) Ceetron Solutions AS
|
||||
//
|
||||
// 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 "RiaProjectModifier.h"
|
||||
|
||||
#include "RimCaseCollection.h"
|
||||
#include "RimEclipseCaseCollection.h"
|
||||
#include "RimEclipseInputCase.h"
|
||||
#include "RimEclipseResultCase.h"
|
||||
#include "RimGeoMechCase.h"
|
||||
#include "RimIdenticalGridCaseGroup.h"
|
||||
#include "RimOilField.h"
|
||||
#include "RimProject.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaProjectModifier::RiaProjectModifier()
|
||||
: m_invalidateExternalFilePaths( false )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaProjectModifier::setReplaceCaseFirstOccurrence( const QString& newGridFileName )
|
||||
{
|
||||
m_caseIdToGridFileNameMap[RiaProjectModifier::firstOccurrenceId()] = makeFilePathAbsolute( newGridFileName );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaProjectModifier::setReplaceCase( int caseIdToReplace, const QString& newGridFileName )
|
||||
{
|
||||
if ( caseIdToReplace >= 0 )
|
||||
{
|
||||
m_caseIdToGridFileNameMap[caseIdToReplace] = makeFilePathAbsolute( newGridFileName );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaProjectModifier::setReplaceSourceCasesFirstOccurrence( const std::vector<QString>& newGridFileNames )
|
||||
{
|
||||
m_groupIdToGridFileNamesMap[RiaProjectModifier::firstOccurrenceId()] = newGridFileNames;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaProjectModifier::setReplaceSourceCasesById( int caseGroupIdToReplace, const std::vector<QString>& newGridFileNames )
|
||||
{
|
||||
if ( caseGroupIdToReplace >= 0 )
|
||||
{
|
||||
m_groupIdToGridFileNamesMap[caseGroupIdToReplace] = newGridFileNames;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaProjectModifier::setReplacePropertiesFolderFirstOccurrence( QString newPropertiesFolder )
|
||||
{
|
||||
m_caseIdToPropertiesFolderMap[RiaProjectModifier::firstOccurrenceId()] = makeFilePathAbsolute( newPropertiesFolder );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaProjectModifier::setReplacePropertiesFolder( int caseIdToReplace, QString newPropertiesFolder )
|
||||
{
|
||||
if ( caseIdToReplace >= 0 )
|
||||
{
|
||||
m_caseIdToPropertiesFolderMap[caseIdToReplace] = makeFilePathAbsolute( newPropertiesFolder );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaProjectModifier::setInvalidateExternalFilePaths()
|
||||
{
|
||||
m_invalidateExternalFilePaths = true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaProjectModifier::invalidateExternalFilePaths( RimProject* project )
|
||||
{
|
||||
std::vector<caf::FilePath*> filePaths = project->allFilePaths();
|
||||
|
||||
const QString invalidPath = "path_does_not_exist";
|
||||
for ( caf::FilePath* filePath : filePaths )
|
||||
{
|
||||
filePath->setPath( invalidPath );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaProjectModifier::applyModificationsToProject( RimProject* project )
|
||||
{
|
||||
if ( m_caseIdToGridFileNameMap.size() > 0 )
|
||||
{
|
||||
replaceCase( project );
|
||||
}
|
||||
|
||||
if ( m_groupIdToGridFileNamesMap.size() > 0 )
|
||||
{
|
||||
replaceSourceCases( project );
|
||||
}
|
||||
|
||||
if ( m_caseIdToPropertiesFolderMap.size() > 0 )
|
||||
{
|
||||
replacePropertiesFolder( project );
|
||||
}
|
||||
|
||||
if ( m_invalidateExternalFilePaths )
|
||||
{
|
||||
invalidateExternalFilePaths( project );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaProjectModifier::replaceSourceCases( RimProject* project )
|
||||
{
|
||||
for ( RimOilField* oilField : project->oilFields() )
|
||||
{
|
||||
RimEclipseCaseCollection* analysisModels = oilField ? oilField->analysisModels() : nullptr;
|
||||
if ( analysisModels )
|
||||
{
|
||||
for ( RimIdenticalGridCaseGroup* caseGroup : analysisModels->caseGroups )
|
||||
{
|
||||
for ( auto item : m_groupIdToGridFileNamesMap )
|
||||
{
|
||||
int groupIdToReplace = item.first;
|
||||
if ( groupIdToReplace == RiaProjectModifier::firstOccurrenceId() )
|
||||
{
|
||||
groupIdToReplace = firstGroupId( project );
|
||||
}
|
||||
|
||||
if ( groupIdToReplace == caseGroup->groupId() )
|
||||
{
|
||||
RimCaseCollection* caseCollection = caseGroup->caseCollection;
|
||||
caseCollection->reservoirs.deleteAllChildObjects();
|
||||
|
||||
for ( QString fileName : item.second )
|
||||
{
|
||||
QString caseName = caseNameFromGridFileName( fileName );
|
||||
|
||||
// Use this slightly hackish method in order to get a new unique ID
|
||||
RimEclipseResultCase* resCase = new RimEclipseResultCase;
|
||||
resCase->setCaseInfo( caseName, fileName );
|
||||
|
||||
caseCollection->reservoirs.push_back( resCase );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaProjectModifier::replaceCase( RimProject* project )
|
||||
{
|
||||
std::vector<RimCase*> allCases;
|
||||
project->allCases( allCases );
|
||||
|
||||
for ( RimCase* rimCase : allCases )
|
||||
{
|
||||
RimEclipseResultCase* eclipseResultCase = dynamic_cast<RimEclipseResultCase*>( rimCase );
|
||||
RimGeoMechCase* geomechCase = dynamic_cast<RimGeoMechCase*>( rimCase );
|
||||
if ( eclipseResultCase || geomechCase )
|
||||
{
|
||||
for ( auto item : m_caseIdToGridFileNameMap )
|
||||
{
|
||||
int caseIdToReplace = item.first;
|
||||
if ( caseIdToReplace == RiaProjectModifier::firstOccurrenceId() )
|
||||
{
|
||||
caseIdToReplace = firstCaseId( project );
|
||||
}
|
||||
|
||||
if ( caseIdToReplace == rimCase->caseId() )
|
||||
{
|
||||
QString replaceFileName = item.second;
|
||||
if ( eclipseResultCase )
|
||||
{
|
||||
eclipseResultCase->setGridFileName( replaceFileName );
|
||||
eclipseResultCase->caseUserDescription = caseNameFromGridFileName( replaceFileName );
|
||||
}
|
||||
else if ( geomechCase )
|
||||
{
|
||||
geomechCase->setGridFileName( replaceFileName );
|
||||
geomechCase->caseUserDescription = caseNameFromGridFileName( replaceFileName );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaProjectModifier::replacePropertiesFolder( RimProject* project )
|
||||
{
|
||||
std::vector<RimCase*> allCases;
|
||||
project->allCases( allCases );
|
||||
|
||||
for ( RimCase* rimCase : allCases )
|
||||
{
|
||||
RimEclipseInputCase* inputCase = dynamic_cast<RimEclipseInputCase*>( rimCase );
|
||||
|
||||
if ( inputCase )
|
||||
{
|
||||
for ( auto item : m_caseIdToPropertiesFolderMap )
|
||||
{
|
||||
int caseIdToReplace = item.first;
|
||||
|
||||
if ( caseIdToReplace == RiaProjectModifier::firstOccurrenceId() )
|
||||
{
|
||||
caseIdToReplace = firstInputCaseId( project );
|
||||
}
|
||||
|
||||
if ( caseIdToReplace == inputCase->caseId() )
|
||||
{
|
||||
inputCase->updateAdditionalFileFolder( item.second );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Returns absolute path name to the specified file.
|
||||
///
|
||||
/// If \a relOrAbsolutePath is a relative, the current working directory for the process will be
|
||||
/// used in order to make the path absolute.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaProjectModifier::makeFilePathAbsolute( const QString& relOrAbsolutePath )
|
||||
{
|
||||
QFileInfo theFile( relOrAbsolutePath );
|
||||
theFile.makeAbsolute();
|
||||
return theFile.filePath();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaProjectModifier::caseNameFromGridFileName( const QString& fullGridFilePathName )
|
||||
{
|
||||
QFileInfo fi( fullGridFilePathName );
|
||||
|
||||
return fi.baseName();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiaProjectModifier::firstCaseId( RimProject* project )
|
||||
{
|
||||
std::vector<RimCase*> allCases;
|
||||
project->allCases( allCases );
|
||||
|
||||
for ( RimCase* rimCase : allCases )
|
||||
{
|
||||
RimEclipseResultCase* resultCase = dynamic_cast<RimEclipseResultCase*>( rimCase );
|
||||
if ( resultCase )
|
||||
{
|
||||
return resultCase->caseId();
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiaProjectModifier::firstGroupId( RimProject* project )
|
||||
{
|
||||
for ( size_t oilFieldIdx = 0; oilFieldIdx < project->oilFields().size(); oilFieldIdx++ )
|
||||
{
|
||||
RimOilField* oilField = project->oilFields[oilFieldIdx];
|
||||
RimEclipseCaseCollection* analysisModels = oilField ? oilField->analysisModels() : nullptr;
|
||||
if ( analysisModels )
|
||||
{
|
||||
if ( analysisModels->caseGroups.size() > 0 )
|
||||
{
|
||||
return analysisModels->caseGroups[0]->groupId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiaProjectModifier::firstInputCaseId( RimProject* project )
|
||||
{
|
||||
std::vector<RimCase*> allCases;
|
||||
project->allCases( allCases );
|
||||
|
||||
for ( RimCase* rimCase : allCases )
|
||||
{
|
||||
RimEclipseInputCase* resultCase = dynamic_cast<RimEclipseInputCase*>( rimCase );
|
||||
if ( resultCase )
|
||||
{
|
||||
return resultCase->caseId();
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiaProjectModifier::firstOccurrenceId()
|
||||
{
|
||||
return -999;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) Statoil ASA
|
||||
// Copyright (C) Ceetron Solutions AS
|
||||
//
|
||||
// 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 "cvfObject.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class RimProject;
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaProjectModifier : public cvf::Object
|
||||
{
|
||||
public:
|
||||
RiaProjectModifier();
|
||||
|
||||
void setReplaceCaseFirstOccurrence( const QString& newGridFileName );
|
||||
void setReplaceCase( int caseIdToReplace, const QString& newGridFileName );
|
||||
|
||||
void setReplaceSourceCasesFirstOccurrence( const std::vector<QString>& newGridFileNames );
|
||||
void setReplaceSourceCasesById( int caseGroupIdToReplace, const std::vector<QString>& newGridFileNames );
|
||||
|
||||
void setReplacePropertiesFolderFirstOccurrence( QString newPropertiesFolder );
|
||||
void setReplacePropertiesFolder( int caseIdToReplace, QString newPropertiesFolder );
|
||||
|
||||
// Used by the regression test system to invalidate all paths to test if the tests run as expected if external files
|
||||
// are missing/invalid
|
||||
void setInvalidateExternalFilePaths();
|
||||
|
||||
bool applyModificationsToProject( RimProject* project );
|
||||
|
||||
private:
|
||||
void replaceSourceCases( RimProject* project );
|
||||
void replaceCase( RimProject* project );
|
||||
void replacePropertiesFolder( RimProject* project );
|
||||
void invalidateExternalFilePaths( RimProject* project );
|
||||
|
||||
static QString makeFilePathAbsolute( const QString& relOrAbsolutePath );
|
||||
static QString caseNameFromGridFileName( const QString& fullGridFilePathName );
|
||||
|
||||
static int firstCaseId( RimProject* project );
|
||||
static int firstGroupId( RimProject* project );
|
||||
static int firstInputCaseId( RimProject* project );
|
||||
|
||||
static int firstOccurrenceId();
|
||||
|
||||
private:
|
||||
std::map<int, QString> m_caseIdToGridFileNameMap;
|
||||
std::map<int, std::vector<QString>> m_groupIdToGridFileNamesMap;
|
||||
std::map<int, QString> m_caseIdToPropertiesFolderMap;
|
||||
bool m_invalidateExternalFilePaths;
|
||||
};
|
||||
@@ -0,0 +1,528 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaQDateTimeTools.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QLocale>
|
||||
#include <QString>
|
||||
|
||||
#include "cafAppEnum.h"
|
||||
#include "cafPdmUiItem.h"
|
||||
|
||||
#include <cvfAssert.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_DAY = DateTimeSpan( 0, 0, 1 );
|
||||
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_WEEK = DateTimeSpan( 0, 0, 7 );
|
||||
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_MONTH = DateTimeSpan( 0, 1, 0 );
|
||||
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_QUARTER = DateTimeSpan( 0, 3, 0 );
|
||||
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_HALFYEAR = DateTimeSpan( 0, 6, 0 );
|
||||
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_YEAR = DateTimeSpan( 1, 0, 0 );
|
||||
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_DECADE = DateTimeSpan( 10, 0, 0 );
|
||||
|
||||
namespace caf
|
||||
{
|
||||
// clang-format off
|
||||
|
||||
template <>
|
||||
void caf::AppEnum<RiaQDateTimeTools::DateFormatComponents>::setUp()
|
||||
{
|
||||
addItem( RiaQDateTimeTools::DATE_FORMAT_NONE, "NO_DATE", "No Date" );
|
||||
addItem( RiaQDateTimeTools::DATE_FORMAT_YEAR, "YEAR", "Year Only" );
|
||||
addItem( RiaQDateTimeTools::DATE_FORMAT_YEAR_MONTH, "YEAR_MONTH", "Year and Month" );
|
||||
addItem( RiaQDateTimeTools::DATE_FORMAT_YEAR_MONTH_DAY, "YEAR_MONTH_DAY", "Year, Month and Day" );
|
||||
setDefault( RiaQDateTimeTools::DATE_FORMAT_YEAR_MONTH_DAY );
|
||||
}
|
||||
|
||||
template <>
|
||||
void caf::AppEnum<RiaQDateTimeTools::TimeFormatComponents>::setUp()
|
||||
{
|
||||
addItem( RiaQDateTimeTools::TimeFormatComponents::TIME_FORMAT_NONE, "NO_TIME", "No Time of Day" );
|
||||
addItem( RiaQDateTimeTools::TimeFormatComponents::TIME_FORMAT_HOUR, "HOUR", "Hour Only" );
|
||||
addItem( RiaQDateTimeTools::TimeFormatComponents::TIME_FORMAT_HOUR_MINUTE, "HOUR_MINUTE", "Hour and Minute" );
|
||||
addItem( RiaQDateTimeTools::TimeFormatComponents::TIME_FORMAT_HOUR_MINUTE_SECOND, "HOUR_MINUTE_SECONDS", "Hour, Minutes and Seconds" );
|
||||
setDefault( RiaQDateTimeTools::TimeFormatComponents::TIME_FORMAT_NONE );
|
||||
}
|
||||
|
||||
template <>
|
||||
void caf::AppEnum<RiaQDateTimeTools::DateTimePeriod>::setUp()
|
||||
{
|
||||
addItem( RiaQDateTimeTools::DateTimePeriod::NONE, "NONE", "None" );
|
||||
addItem( RiaQDateTimeTools::DateTimePeriod::DAY, "DAY", "Day" );
|
||||
addItem( RiaQDateTimeTools::DateTimePeriod::WEEK, "WEEK", "Week" );
|
||||
addItem( RiaQDateTimeTools::DateTimePeriod::MONTH, "MONTH", "Month" );
|
||||
addItem( RiaQDateTimeTools::DateTimePeriod::QUARTER, "QUARTER", "Quarter" );
|
||||
addItem( RiaQDateTimeTools::DateTimePeriod::HALFYEAR, "HALFYEAR", "Half Year" );
|
||||
addItem( RiaQDateTimeTools::DateTimePeriod::YEAR, "YEAR", "Year" );
|
||||
addItem( RiaQDateTimeTools::DateTimePeriod::DECADE, "DECADE", "Decade" );
|
||||
setDefault( RiaQDateTimeTools::DateTimePeriod::NONE );
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
} // namespace caf
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
Qt::TimeSpec RiaQDateTimeTools::currentTimeSpec()
|
||||
{
|
||||
return Qt::UTC;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
quint64 RiaQDateTimeTools::secondsInDay()
|
||||
{
|
||||
return 60 * 60 * 24;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
quint64 RiaQDateTimeTools::secondsInYear()
|
||||
{
|
||||
return 60 * 60 * 24 * 365;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::fromString( const QString& dateString, const QString& format )
|
||||
{
|
||||
QDateTime dt = QDateTime::fromString( dateString, format );
|
||||
dt.setTimeSpec( currentTimeSpec() );
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::fromYears( double years )
|
||||
{
|
||||
double yearsAfterEpoch = years - 1970.0;
|
||||
|
||||
QDateTime dt = RiaQDateTimeTools::epoch();
|
||||
|
||||
return RiaQDateTimeTools::addYears( dt, yearsAfterEpoch );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::fromTime_t( time_t t )
|
||||
{
|
||||
auto qdt = createUtcDateTime();
|
||||
qdt.setTime_t( t );
|
||||
return qdt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::addMSecs( const QDateTime& dt, double msecs )
|
||||
{
|
||||
return dt.addMSecs( msecs );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::addDays( const QDateTime& dt, double days )
|
||||
{
|
||||
double integerPart = 0.0;
|
||||
double fractionPart = 0.0;
|
||||
|
||||
fractionPart = modf( days, &integerPart );
|
||||
|
||||
QDateTime tmp = dt.addDays( integerPart );
|
||||
tmp = tmp.addSecs( fractionPart * RiaQDateTimeTools::secondsInDay() );
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::addYears( const QDateTime& dt, double years )
|
||||
{
|
||||
double integerPart = 0.0;
|
||||
double fractionPart = 0.0;
|
||||
|
||||
fractionPart = modf( years, &integerPart );
|
||||
|
||||
QDateTime tmp = dt.addYears( integerPart );
|
||||
tmp = tmp.addSecs( fractionPart * RiaQDateTimeTools::secondsInYear() );
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::addSpan( const QDateTime& dt, DateTimeSpan span )
|
||||
{
|
||||
return createUtcDateTime( dt ).addYears( span.years() ).addMonths( span.months() ).addDays( span.days() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::subtractSpan( const QDateTime& dt, DateTimeSpan span )
|
||||
{
|
||||
return createUtcDateTime( dt ).addYears( -span.years() ).addMonths( -span.months() ).addDays( -span.days() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::addPeriod( const QDateTime& dt, RiaQDateTimeTools::DateTimePeriod period )
|
||||
{
|
||||
return addSpan( dt, timeSpan( period ) );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::subtractPeriod( const QDateTime& dt, RiaQDateTimeTools::DateTimePeriod period )
|
||||
{
|
||||
return subtractSpan( dt, timeSpan( period ) );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::epoch()
|
||||
{
|
||||
// NB: Not able to use QDateTime::fromMSecsSinceEpoch as this was introduced in Qt 4.7
|
||||
|
||||
QDateTime dt;
|
||||
dt.setDate( QDate( 1970, 1, 1 ) );
|
||||
dt.setTimeSpec( currentTimeSpec() );
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::createUtcDateTime()
|
||||
{
|
||||
auto qdt = QDateTime();
|
||||
qdt.setTimeSpec( currentTimeSpec() );
|
||||
return qdt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::createUtcDateTime( const QDate& date )
|
||||
{
|
||||
auto qdt = QDateTime( date );
|
||||
qdt.setTimeSpec( currentTimeSpec() );
|
||||
return qdt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::createUtcDateTime( const QDate& date, const QTime& time )
|
||||
{
|
||||
auto qdt = QDateTime( date, time, currentTimeSpec() );
|
||||
return qdt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::createUtcDateTime( const QDateTime& dt )
|
||||
{
|
||||
auto qdt = QDateTime( dt );
|
||||
qdt.setTimeSpec( currentTimeSpec() );
|
||||
return qdt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaQDateTimeTools::lessThan( const QDateTime& dt1, const QDateTime& dt2 )
|
||||
{
|
||||
// dt1 < dt2
|
||||
return dt1.secsTo( dt2 ) > 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const DateTimeSpan RiaQDateTimeTools::timeSpan( RiaQDateTimeTools::DateTimePeriod period )
|
||||
{
|
||||
switch ( period )
|
||||
{
|
||||
case RiaQDateTimeTools::DateTimePeriod::DAY:
|
||||
return TIMESPAN_DAY;
|
||||
case RiaQDateTimeTools::DateTimePeriod::WEEK:
|
||||
return TIMESPAN_WEEK;
|
||||
case RiaQDateTimeTools::DateTimePeriod::MONTH:
|
||||
return TIMESPAN_MONTH;
|
||||
case RiaQDateTimeTools::DateTimePeriod::QUARTER:
|
||||
return TIMESPAN_QUARTER;
|
||||
case RiaQDateTimeTools::DateTimePeriod::HALFYEAR:
|
||||
return TIMESPAN_HALFYEAR;
|
||||
case RiaQDateTimeTools::DateTimePeriod::YEAR:
|
||||
return TIMESPAN_YEAR;
|
||||
case RiaQDateTimeTools::DateTimePeriod::DECADE:
|
||||
return TIMESPAN_DECADE;
|
||||
}
|
||||
CVF_ASSERT( false );
|
||||
return DateTimeSpan();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaQDateTimeTools::truncateTime( const QDateTime& dt, RiaQDateTimeTools::DateTimePeriod period )
|
||||
{
|
||||
int y = dt.date().year();
|
||||
int m = dt.date().month();
|
||||
int d = dt.date().day();
|
||||
int dow = dt.date().dayOfWeek();
|
||||
|
||||
switch ( period )
|
||||
{
|
||||
case RiaQDateTimeTools::DateTimePeriod::DAY:
|
||||
return createUtcDateTime( QDate( y, m, d ) );
|
||||
case RiaQDateTimeTools::DateTimePeriod::WEEK:
|
||||
return createUtcDateTime( QDate( y, m, d ).addDays( -dow + 1 ) );
|
||||
case RiaQDateTimeTools::DateTimePeriod::MONTH:
|
||||
return createUtcDateTime( QDate( y, m, 1 ) );
|
||||
case RiaQDateTimeTools::DateTimePeriod::QUARTER:
|
||||
return createUtcDateTime( QDate( y, ( ( m - 1 ) / 3 ) * 3 + 1, 1 ) );
|
||||
case RiaQDateTimeTools::DateTimePeriod::HALFYEAR:
|
||||
return createUtcDateTime( QDate( y, ( ( m - 1 ) / 6 ) * 6 + 1, 1 ) );
|
||||
case RiaQDateTimeTools::DateTimePeriod::YEAR:
|
||||
return createUtcDateTime( QDate( y, 1, 1 ) );
|
||||
case RiaQDateTimeTools::DateTimePeriod::DECADE:
|
||||
return createUtcDateTime( QDate( ( y / 10 ) * 10, 1, 1 ) );
|
||||
}
|
||||
CVF_ASSERT( false );
|
||||
return createUtcDateTime();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<RiaQDateTimeTools::DateTimePeriod> RiaQDateTimeTools::dateTimePeriods()
|
||||
{
|
||||
std::vector<DateTimePeriod> allPeriods;
|
||||
|
||||
for ( size_t i = 0; i < DateTimePeriodEnum::size(); i++ )
|
||||
{
|
||||
allPeriods.push_back( DateTimePeriodEnum::fromIndex( i ) );
|
||||
}
|
||||
|
||||
return allPeriods;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaQDateTimeTools::dateTimePeriodName( RiaQDateTimeTools::DateTimePeriod period )
|
||||
{
|
||||
return DateTimePeriodEnum::uiText( period );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaQDateTimeTools::toStringUsingApplicationLocale( const QDateTime& dt, const QString& format )
|
||||
{
|
||||
// Default application locale is set in RiaMain
|
||||
// QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates));
|
||||
//
|
||||
// QDate/QDateTime use system locale for toString() functions
|
||||
|
||||
QLocale defaultApplicationLocale;
|
||||
|
||||
return defaultApplicationLocale.toString( dt, format );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaQDateTimeTools::createTimeFormatStringFromDates( const std::vector<QDateTime>& dates )
|
||||
{
|
||||
bool hasHoursAndMinutesInTimesteps = false;
|
||||
bool hasSecondsInTimesteps = false;
|
||||
bool hasMillisecondsInTimesteps = false;
|
||||
|
||||
for ( size_t i = 0; i < dates.size(); i++ )
|
||||
{
|
||||
if ( dates[i].time().msec() != 0.0 )
|
||||
{
|
||||
hasMillisecondsInTimesteps = true;
|
||||
hasSecondsInTimesteps = true;
|
||||
hasHoursAndMinutesInTimesteps = true;
|
||||
break;
|
||||
}
|
||||
else if ( dates[i].time().second() != 0.0 )
|
||||
{
|
||||
hasHoursAndMinutesInTimesteps = true;
|
||||
hasSecondsInTimesteps = true;
|
||||
}
|
||||
else if ( dates[i].time().hour() != 0.0 || dates[i].time().minute() != 0.0 )
|
||||
{
|
||||
hasHoursAndMinutesInTimesteps = true;
|
||||
}
|
||||
}
|
||||
|
||||
QString formatString = dateFormatString();
|
||||
if ( hasHoursAndMinutesInTimesteps )
|
||||
{
|
||||
formatString += " - hh:mm";
|
||||
if ( hasSecondsInTimesteps )
|
||||
{
|
||||
formatString += ":ss";
|
||||
if ( hasMillisecondsInTimesteps )
|
||||
{
|
||||
formatString += ".zzz";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return formatString;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaQDateTimeTools::dateFormatString()
|
||||
{
|
||||
return "dd.MMM yyyy";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<QString> RiaQDateTimeTools::supportedDateFormats()
|
||||
{
|
||||
std::vector<QString> dateFormats;
|
||||
|
||||
// See enum DateFormatComponents in header
|
||||
// The semi-colon separated components are:
|
||||
// DATE_FORMAT_YEAR, ..YEAR_MONTH, ..YEAR_MONTH_DAY
|
||||
dateFormats.push_back( "yyyy;yyyy-MM;yyyy-MM-dd" );
|
||||
dateFormats.push_back( "yyyy;MMM yyyy;dd. MMM yyyy" );
|
||||
dateFormats.push_back( "yyyy;MMM yyyy;MMM dd. yyyy" );
|
||||
dateFormats.push_back( "yyyy;MM/yyyy;dd/MM/yyyy" );
|
||||
dateFormats.push_back( "yyyy;M/yyyy;d/M/yyyy" );
|
||||
dateFormats.push_back( "yyyy;M/yyyy;M/d/yyyy" );
|
||||
dateFormats.push_back( "yy;M/yy;d/M/yy" );
|
||||
dateFormats.push_back( "yy;M/yy;M/d/yy" );
|
||||
dateFormats.push_back( "yyyy;MM-yyyy;dd-MM-yyyy" );
|
||||
dateFormats.push_back( "yyyy;MM.yyyy;dd.MM.yyyy" );
|
||||
dateFormats.push_back( "yyyy;MM-yyyy;MM-dd-yyyy" );
|
||||
dateFormats.push_back( "yyyy;MM.yyyy;MM.dd.yyyy" );
|
||||
dateFormats.push_back( "yy;MM-yy;dd-MM-yy" );
|
||||
dateFormats.push_back( "yy;MM-yy;MM-dd-yy" );
|
||||
|
||||
return dateFormats;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<QString> RiaQDateTimeTools::supportedTimeFormats()
|
||||
{
|
||||
std::vector<QString> timeFormats;
|
||||
|
||||
// See enum TimeFormatComponents in header
|
||||
// The semi-colon separated components are:
|
||||
// TIME_FORMAT_HOUR, ..HOUR_MINUTE, ..HOUR_MINUTE_SECOND and ..HOUR_MINUTE_MILLISECOND
|
||||
timeFormats.push_back( "HH;HH:mm;HH:mm:ss;HH:mm:ss.zzz" );
|
||||
timeFormats.push_back( "H;H:mm;H:mm:ss;H:mm:ss.zzz" );
|
||||
timeFormats.push_back( "hh AP;hh:mm AP;hh:mm:ss AP;hh:mm:ss.zzz AP" );
|
||||
timeFormats.push_back( "h AP;h:mm AP;h:mm:ss AP;h:mm:ss.zzz AP" );
|
||||
|
||||
return timeFormats;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaQDateTimeTools::dateFormatString( const QString& fullDateFormat, DateFormatComponents dateComponents )
|
||||
{
|
||||
if ( dateComponents == DATE_FORMAT_NONE ) return "";
|
||||
|
||||
QStringList allVariants = fullDateFormat.split( ";" );
|
||||
if ( static_cast<int>( dateComponents ) < allVariants.size() )
|
||||
{
|
||||
return allVariants[dateComponents];
|
||||
}
|
||||
CVF_ASSERT( false && "Date format string is malformed" );
|
||||
return "";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaQDateTimeTools::timeFormatString( const QString& fullTimeFormat, TimeFormatComponents timeComponents )
|
||||
{
|
||||
if ( timeComponents == TimeFormatComponents::TIME_FORMAT_NONE ) return "";
|
||||
|
||||
QStringList allVariants = fullTimeFormat.split( ";" );
|
||||
if ( static_cast<int>( timeComponents ) < allVariants.size() )
|
||||
{
|
||||
return allVariants[static_cast<int>( timeComponents )];
|
||||
}
|
||||
CVF_ASSERT( false && "Time format string is malformed" );
|
||||
return "";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QList<caf::PdmOptionItemInfo> RiaQDateTimeTools::createOptionItems( const std::vector<time_t>& timeSteps )
|
||||
{
|
||||
QList<caf::PdmOptionItemInfo> options;
|
||||
|
||||
std::vector<QDateTime> dateTimes;
|
||||
for ( time_t timeT : timeSteps )
|
||||
{
|
||||
QDateTime dateTime = RiaQDateTimeTools::fromTime_t( timeT );
|
||||
|
||||
dateTimes.push_back( dateTime );
|
||||
}
|
||||
|
||||
QString formatString = RiaQDateTimeTools::createTimeFormatStringFromDates( dateTimes );
|
||||
|
||||
for ( size_t i = 0; i < dateTimes.size(); i++ )
|
||||
{
|
||||
const auto& dt = dateTimes[i];
|
||||
QString text = RiaQDateTimeTools::toStringUsingApplicationLocale( dt, formatString );
|
||||
options.push_back( { text, static_cast<int>( i ) } );
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "cafAppEnum.h"
|
||||
|
||||
#include <qglobal.h>
|
||||
#include <qnamespace.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
#include <QVariant>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class QDateTime;
|
||||
class QDate;
|
||||
class QTime;
|
||||
class DateTimeSpan;
|
||||
|
||||
namespace caf
|
||||
{
|
||||
class PdmOptionItemInfo;
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaQDateTimeTools
|
||||
{
|
||||
static const DateTimeSpan TIMESPAN_DAY;
|
||||
static const DateTimeSpan TIMESPAN_WEEK;
|
||||
static const DateTimeSpan TIMESPAN_MONTH;
|
||||
static const DateTimeSpan TIMESPAN_QUARTER;
|
||||
static const DateTimeSpan TIMESPAN_HALFYEAR;
|
||||
static const DateTimeSpan TIMESPAN_YEAR;
|
||||
static const DateTimeSpan TIMESPAN_DECADE;
|
||||
|
||||
public:
|
||||
enum DateFormatComponents
|
||||
{
|
||||
DATE_FORMAT_UNSPECIFIED = -2,
|
||||
DATE_FORMAT_NONE = -1,
|
||||
DATE_FORMAT_YEAR = 0,
|
||||
DATE_FORMAT_YEAR_MONTH,
|
||||
DATE_FORMAT_YEAR_MONTH_DAY,
|
||||
DATE_FORMAT_SIZE
|
||||
};
|
||||
|
||||
enum class TimeFormatComponents
|
||||
{
|
||||
TIME_FORMAT_UNSPECIFIED = -2,
|
||||
TIME_FORMAT_NONE = -1,
|
||||
TIME_FORMAT_HOUR,
|
||||
TIME_FORMAT_HOUR_MINUTE,
|
||||
TIME_FORMAT_HOUR_MINUTE_SECOND,
|
||||
TIME_FORMAT_HOUR_MINUTE_SECOND_MILLISECOND,
|
||||
TIME_FORMAT_SIZE
|
||||
};
|
||||
|
||||
enum class DateTimePeriod
|
||||
{
|
||||
NONE = -1,
|
||||
DAY,
|
||||
WEEK,
|
||||
MONTH,
|
||||
QUARTER,
|
||||
HALFYEAR,
|
||||
YEAR,
|
||||
DECADE
|
||||
};
|
||||
using DateTimePeriodEnum = caf::AppEnum<DateTimePeriod>;
|
||||
|
||||
static Qt::TimeSpec currentTimeSpec();
|
||||
|
||||
static QDateTime fromString( const QString& dateString, const QString& format );
|
||||
static QDateTime fromYears( double years );
|
||||
static QDateTime fromTime_t( time_t t );
|
||||
|
||||
static QDateTime addMSecs( const QDateTime& dt, double msecs );
|
||||
static QDateTime addDays( const QDateTime& dt, double days );
|
||||
static QDateTime addYears( const QDateTime& dt, double years );
|
||||
static QDateTime addSpan( const QDateTime& dt, DateTimeSpan span );
|
||||
static QDateTime subtractSpan( const QDateTime& dt, DateTimeSpan span );
|
||||
static QDateTime addPeriod( const QDateTime& dt, RiaQDateTimeTools::DateTimePeriod period );
|
||||
static QDateTime subtractPeriod( const QDateTime& dt, RiaQDateTimeTools::DateTimePeriod period );
|
||||
|
||||
static QDateTime epoch();
|
||||
|
||||
static QDateTime createUtcDateTime();
|
||||
static QDateTime createUtcDateTime( const QDate& date );
|
||||
static QDateTime createUtcDateTime( const QDate& date, const QTime& time );
|
||||
static QDateTime createUtcDateTime( const QDateTime& dt );
|
||||
|
||||
static bool lessThan( const QDateTime& dt1, const QDateTime& dt2 );
|
||||
|
||||
static const DateTimeSpan timeSpan( RiaQDateTimeTools::DateTimePeriod period );
|
||||
static QDateTime truncateTime( const QDateTime& dt, RiaQDateTimeTools::DateTimePeriod period );
|
||||
|
||||
static std::vector<RiaQDateTimeTools::DateTimePeriod> dateTimePeriods();
|
||||
static QString dateTimePeriodName( RiaQDateTimeTools::DateTimePeriod period );
|
||||
|
||||
// This function uses C locale to make sure the text representation of a date is stable, independent of the locale
|
||||
// settings on local machine. Required for stable regression testing.
|
||||
static QString toStringUsingApplicationLocale( const QDateTime& dt, const QString& format );
|
||||
|
||||
static QString createTimeFormatStringFromDates( const std::vector<QDateTime>& dates );
|
||||
static QString dateFormatString();
|
||||
|
||||
static std::vector<QString> supportedDateFormats();
|
||||
static std::vector<QString> supportedTimeFormats();
|
||||
|
||||
static QString
|
||||
dateFormatString( const QString& fullDateFormat,
|
||||
DateFormatComponents dateComponents = DateFormatComponents::DATE_FORMAT_YEAR_MONTH_DAY );
|
||||
static QString
|
||||
timeFormatString( const QString& fullTimeFormat,
|
||||
TimeFormatComponents timeComponents = TimeFormatComponents::TIME_FORMAT_HOUR_MINUTE_SECOND );
|
||||
|
||||
static QList<caf::PdmOptionItemInfo> createOptionItems( const std::vector<time_t>& timeSteps );
|
||||
|
||||
private:
|
||||
static quint64 secondsInDay();
|
||||
static quint64 secondsInYear();
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class DateTimeSpan
|
||||
{
|
||||
public:
|
||||
DateTimeSpan()
|
||||
: m_years( 0 )
|
||||
, m_months( 0 )
|
||||
, m_days( 0 )
|
||||
{
|
||||
}
|
||||
DateTimeSpan( int years, int months, int days )
|
||||
: m_years( years )
|
||||
, m_months( months )
|
||||
, m_days( days )
|
||||
{
|
||||
}
|
||||
|
||||
int years() const { return m_years; }
|
||||
int months() const { return m_months; }
|
||||
int days() const { return m_days; }
|
||||
|
||||
bool isEmpty() { return m_years == 0 && m_months == 0 && m_days; }
|
||||
|
||||
private:
|
||||
int m_years;
|
||||
int m_months;
|
||||
int m_days;
|
||||
};
|
||||
@@ -0,0 +1,135 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS
|
||||
//
|
||||
// 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 "RiaRegressionTest.h"
|
||||
|
||||
#include "cafPdmSettings.h"
|
||||
#include "cafPdmUiFilePathEditor.h"
|
||||
#include "cafPdmUiTextEditor.h"
|
||||
|
||||
CAF_PDM_SOURCE_INIT( RiaRegressionTest, "RiaRegressionTest" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaRegressionTest::RiaRegressionTest( void )
|
||||
{
|
||||
CAF_PDM_InitFieldNoDefault( &folderContainingCompareTool,
|
||||
"workingFolder",
|
||||
"Folder containing <b>compare</b>",
|
||||
"",
|
||||
"Location of compare tool from Image Magic suite",
|
||||
"" );
|
||||
folderContainingCompareTool.uiCapability()->setUiEditorTypeName( caf::PdmUiFilePathEditor::uiEditorTypeName() );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &folderContainingDiffTool,
|
||||
"folderContainingDiffTool",
|
||||
"Folder containing <b>diff</b>",
|
||||
"",
|
||||
"Location of diff tool used for text compare",
|
||||
"" );
|
||||
folderContainingDiffTool.uiCapability()->setUiEditorTypeName( caf::PdmUiFilePathEditor::uiEditorTypeName() );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &folderContainingGitTool,
|
||||
"folderContainingGitTool",
|
||||
"Folder containing <b>git</b>",
|
||||
"",
|
||||
"Location of git tool used for text compare",
|
||||
"" );
|
||||
folderContainingGitTool.uiCapability()->setUiEditorTypeName( caf::PdmUiFilePathEditor::uiEditorTypeName() );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( ®ressionTestFolder, "regressionTestFolder", "Regression Test Folder", "", "", "" );
|
||||
regressionTestFolder.uiCapability()->setUiEditorTypeName( caf::PdmUiFilePathEditor::uiEditorTypeName() );
|
||||
|
||||
CAF_PDM_InitField( &showInteractiveDiffImages, "showInteractiveDiffImages", false, "Interactive Diff Images", "", "", "" );
|
||||
CAF_PDM_InitField( &useOpenMPForGeometryCreation,
|
||||
"useOpenMPForGeometryCreation",
|
||||
true,
|
||||
"Use OpenMP For Geometry Creation",
|
||||
"",
|
||||
"",
|
||||
"" );
|
||||
|
||||
CAF_PDM_InitField( &openReportInBrowser, "openReportInBrowser", false, "Open Generated Report in Browser", "", "", "" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &testFilter,
|
||||
"testFilter",
|
||||
"Test Filter",
|
||||
"",
|
||||
"If empty, all tests are executed.\nTo execute a subset of tests, specify folder names "
|
||||
"separated by ;",
|
||||
"" );
|
||||
testFilter.uiCapability()->setUiEditorTypeName( caf::PdmUiTextEditor::uiEditorTypeName() );
|
||||
|
||||
CAF_PDM_InitField( &appendTestsAfterTestFilter,
|
||||
"appendTestsAfterTestFilter",
|
||||
false,
|
||||
"Append All Tests After Test Filter",
|
||||
"",
|
||||
"",
|
||||
"" );
|
||||
|
||||
CAF_PDM_InitField( &invalidateExternalFilePaths,
|
||||
"invalidateExternalFilePaths",
|
||||
false,
|
||||
"Invalidate External File Paths",
|
||||
"",
|
||||
"",
|
||||
"" );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaRegressionTest::~RiaRegressionTest( void )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaRegressionTest::writeSettingsToApplicationStore() const
|
||||
{
|
||||
caf::PdmSettings::writeFieldsToApplicationStore( this );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaRegressionTest::readSettingsFromApplicationStore()
|
||||
{
|
||||
caf::PdmSettings::readFieldsFromApplicationStore( this );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaRegressionTest::defineEditorAttribute( const caf::PdmFieldHandle* field,
|
||||
QString uiConfigName,
|
||||
caf::PdmUiEditorAttribute* attribute )
|
||||
{
|
||||
if ( field == &folderContainingDiffTool || field == &folderContainingCompareTool ||
|
||||
field == ®ressionTestFolder || field == &folderContainingGitTool )
|
||||
{
|
||||
caf::PdmUiFilePathEditorAttribute* myAttr = dynamic_cast<caf::PdmUiFilePathEditorAttribute*>( attribute );
|
||||
if ( myAttr )
|
||||
{
|
||||
myAttr->m_selectDirectory = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS
|
||||
//
|
||||
// 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 "cafAppEnum.h"
|
||||
#include "cafPdmField.h"
|
||||
#include "cafPdmObject.h"
|
||||
|
||||
class RiaRegressionTest : public caf::PdmObject
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
RiaRegressionTest( void );
|
||||
~RiaRegressionTest( void ) override;
|
||||
|
||||
void writeSettingsToApplicationStore() const;
|
||||
void readSettingsFromApplicationStore();
|
||||
|
||||
public:
|
||||
caf::PdmField<QString> folderContainingCompareTool;
|
||||
caf::PdmField<QString> folderContainingDiffTool;
|
||||
caf::PdmField<QString> folderContainingGitTool;
|
||||
caf::PdmField<QString> regressionTestFolder;
|
||||
caf::PdmField<QString> testFilter;
|
||||
caf::PdmField<bool> showInteractiveDiffImages;
|
||||
caf::PdmField<bool> useOpenMPForGeometryCreation;
|
||||
caf::PdmField<bool> openReportInBrowser;
|
||||
caf::PdmField<bool> appendTestsAfterTestFilter;
|
||||
caf::PdmField<bool> invalidateExternalFilePaths;
|
||||
|
||||
protected:
|
||||
void defineEditorAttribute( const caf::PdmFieldHandle* field,
|
||||
QString uiConfigName,
|
||||
caf::PdmUiEditorAttribute* attribute ) override;
|
||||
};
|
||||
@@ -0,0 +1,679 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaRegressionTestRunner.h"
|
||||
|
||||
#include "RiaGitDiff.h"
|
||||
#include "RiaGuiApplication.h"
|
||||
#include "RiaImageCompareReporter.h"
|
||||
#include "RiaImageFileCompare.h"
|
||||
#include "RiaLogging.h"
|
||||
#include "RiaProjectModifier.h"
|
||||
#include "RiaRegressionTest.h"
|
||||
#include "RiaTextFileCompare.h"
|
||||
|
||||
#include "RicfCommandFileExecutor.h"
|
||||
|
||||
#include "Rim3dView.h"
|
||||
#include "RimCase.h"
|
||||
#include "RimMainPlotCollection.h"
|
||||
#include "RimProject.h"
|
||||
|
||||
#include "RiuMainWindow.h"
|
||||
#include "RiuMainWindowTools.h"
|
||||
#include "RiuPlotMainWindow.h"
|
||||
#include "RiuViewer.h"
|
||||
|
||||
#include "ExportCommands/RicSnapshotAllPlotsToFileFeature.h"
|
||||
#include "ExportCommands/RicSnapshotAllViewsToFileFeature.h"
|
||||
|
||||
#include "cafUtils.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QDir>
|
||||
#include <QElapsedTimer>
|
||||
#include <QMdiSubWindow>
|
||||
#include <QSettings>
|
||||
#include <QStatusBar>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
namespace RegTestNames
|
||||
{
|
||||
const QString generatedFilesFolderName = "RegTestGeneratedFiles";
|
||||
const QString baseFilesFolderName = "RegTestBaseFiles";
|
||||
const QString generatedFolderName = "RegTestGeneratedImages";
|
||||
const QString diffFolderName = "RegTestDiffImages";
|
||||
const QString baseFolderName = "RegTestBaseImages";
|
||||
const QString testProjectName = "RegressionTest";
|
||||
const QString testFolderFilter = "TestCase*";
|
||||
const QString imageCompareExeName = "compare";
|
||||
const QString reportFileName = "ResInsightRegressionTestReport.html";
|
||||
const QString commandFileFilter = "commandfile-*";
|
||||
}; // namespace RegTestNames
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void logInfoTextWithTimeInSeconds( const QElapsedTimer& time, const QString& msg )
|
||||
{
|
||||
double timeRunning = time.elapsed() / 1000.0;
|
||||
|
||||
QString timeText = QString( "(%1 s) " ).arg( timeRunning, 0, 'f', 1 );
|
||||
|
||||
RiaLogging::info( timeText + msg );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaRegressionTestRunner::RiaRegressionTestRunner()
|
||||
: m_runningRegressionTests( false )
|
||||
, m_appendAllTestsAfterLastItemInFilter( false )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaRegressionTestRunner* RiaRegressionTestRunner::instance()
|
||||
{
|
||||
static RiaRegressionTestRunner* singleton = new RiaRegressionTestRunner;
|
||||
return singleton;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaRegressionTestRunner::runRegressionTest()
|
||||
{
|
||||
m_runningRegressionTests = true;
|
||||
|
||||
QString currentApplicationPath = QDir::currentPath();
|
||||
|
||||
RiaRegressionTest regressionTestConfig;
|
||||
regressionTestConfig.readSettingsFromApplicationStore();
|
||||
if ( !regressionTestConfig.folderContainingCompareTool().isEmpty() )
|
||||
{
|
||||
// Windows Only : The image compare tool requires current working directory to be at the folder
|
||||
// containing the image compare tool
|
||||
|
||||
QDir::setCurrent( regressionTestConfig.folderContainingCompareTool() );
|
||||
}
|
||||
|
||||
QString generatedFolderName = RegTestNames::generatedFolderName;
|
||||
QString diffFolderName = RegTestNames::diffFolderName;
|
||||
QString baseFolderName = RegTestNames::baseFolderName;
|
||||
QString regTestProjectName = RegTestNames::testProjectName;
|
||||
QString regTestFolderFilter = RegTestNames::testFolderFilter;
|
||||
|
||||
QDir testDir( m_rootPath ); // If string is empty it will end up as cwd
|
||||
testDir.setFilter( QDir::Dirs );
|
||||
QStringList dirNameFilter;
|
||||
dirNameFilter.append( regTestFolderFilter );
|
||||
testDir.setNameFilters( dirNameFilter );
|
||||
|
||||
QFileInfoList folderList = subDirectoriesForTestExecution( testDir );
|
||||
|
||||
// delete diff and generated images
|
||||
|
||||
for ( const QFileInfo& fi : folderList )
|
||||
{
|
||||
QDir testCaseFolder( fi.filePath() );
|
||||
|
||||
{
|
||||
QDir genDir( testCaseFolder.filePath( generatedFolderName ) );
|
||||
removeDirectoryWithContent( genDir );
|
||||
}
|
||||
|
||||
{
|
||||
QDir diffDir( testCaseFolder.filePath( diffFolderName ) );
|
||||
removeDirectoryWithContent( diffDir );
|
||||
}
|
||||
|
||||
{
|
||||
QDir generatedFiles( testCaseFolder.filePath( RegTestNames::generatedFilesFolderName ) );
|
||||
removeDirectoryWithContent( generatedFiles );
|
||||
}
|
||||
}
|
||||
|
||||
QString htmlReportFileName =
|
||||
generateHtmlReport( folderList, baseFolderName, generatedFolderName, diffFolderName, testDir );
|
||||
|
||||
if ( regressionTestConfig.openReportInBrowser() )
|
||||
{
|
||||
QDesktopServices::openUrl( htmlReportFileName );
|
||||
}
|
||||
|
||||
RiaLogging::info( "--------------------------------------------------" );
|
||||
RiaLogging::info( QTime::currentTime().toString() + ": Launching regression tests" );
|
||||
RiaLogging::info( "--------------------------------------------------" );
|
||||
|
||||
QElapsedTimer timeStamp;
|
||||
timeStamp.start();
|
||||
logInfoTextWithTimeInSeconds( timeStamp, "Starting regression tests\n" );
|
||||
|
||||
RiaApplication* app = RiaApplication::instance();
|
||||
|
||||
for ( const QFileInfo& folderFileInfo : folderList )
|
||||
{
|
||||
QDir testCaseFolder( folderFileInfo.filePath() );
|
||||
|
||||
bool anyCommandFilesExecuted =
|
||||
findAndExecuteCommandFiles( testCaseFolder, regressionTestConfig, htmlReportFileName );
|
||||
|
||||
if ( !anyCommandFilesExecuted )
|
||||
{
|
||||
QString projectFileName;
|
||||
|
||||
if ( testCaseFolder.exists( regTestProjectName + ".rip" ) )
|
||||
{
|
||||
projectFileName = regTestProjectName + ".rip";
|
||||
}
|
||||
|
||||
if ( testCaseFolder.exists( regTestProjectName + ".rsp" ) )
|
||||
{
|
||||
projectFileName = regTestProjectName + ".rsp";
|
||||
}
|
||||
|
||||
if ( !projectFileName.isEmpty() )
|
||||
{
|
||||
cvf::ref<RiaProjectModifier> projectModifier;
|
||||
if ( regressionTestConfig.invalidateExternalFilePaths )
|
||||
{
|
||||
projectModifier = cvf::make_ref<RiaProjectModifier>();
|
||||
projectModifier->setInvalidateExternalFilePaths();
|
||||
}
|
||||
logInfoTextWithTimeInSeconds( timeStamp, "Initializing test :" + testCaseFolder.absolutePath() );
|
||||
|
||||
app->loadProject( testCaseFolder.filePath( projectFileName ),
|
||||
RiaApplication::ProjectLoadAction::PLA_NONE,
|
||||
projectModifier.p() );
|
||||
|
||||
// Wait until all command objects have completed
|
||||
app->waitUntilCommandObjectsHasBeenProcessed();
|
||||
|
||||
setDefaultSnapshotSizeFor3dViews();
|
||||
|
||||
QString fullPathGeneratedFolder = testCaseFolder.absoluteFilePath( generatedFolderName );
|
||||
RicSnapshotAllViewsToFileFeature::exportSnapshotOfViewsIntoFolder( fullPathGeneratedFolder );
|
||||
|
||||
QApplication::processEvents();
|
||||
setDefaultSnapshotSizeForPlotWindows();
|
||||
|
||||
RicSnapshotAllPlotsToFileFeature::exportSnapshotOfPlotsIntoFolder( fullPathGeneratedFolder );
|
||||
|
||||
app->closeProject();
|
||||
}
|
||||
else
|
||||
{
|
||||
RiaLogging::error( "Could not find a regression test file named : " + testCaseFolder.absolutePath() +
|
||||
"/" + regTestProjectName + ".rsp" );
|
||||
}
|
||||
}
|
||||
|
||||
// Do a complete reset of project settings to avoid transfer of settings to next regression test
|
||||
app->resetProject();
|
||||
|
||||
QDir baseDir( testCaseFolder.filePath( baseFolderName ) );
|
||||
QDir genDir( testCaseFolder.filePath( generatedFolderName ) );
|
||||
QDir diffDir( testCaseFolder.filePath( diffFolderName ) );
|
||||
if ( !diffDir.exists() ) testCaseFolder.mkdir( diffFolderName );
|
||||
baseDir.setFilter( QDir::Files );
|
||||
QStringList baseImageFileNames = baseDir.entryList();
|
||||
|
||||
for ( int fIdx = 0; fIdx < baseImageFileNames.size(); ++fIdx )
|
||||
{
|
||||
QString fileName = baseImageFileNames[fIdx];
|
||||
RiaImageFileCompare imgComparator( RegTestNames::imageCompareExeName );
|
||||
bool ok = imgComparator.runComparison( genDir.filePath( fileName ),
|
||||
baseDir.filePath( fileName ),
|
||||
diffDir.filePath( fileName ) );
|
||||
if ( !ok )
|
||||
{
|
||||
qDebug() << "Error comparing :" << imgComparator.errorMessage() << "\n" << imgComparator.errorDetails();
|
||||
}
|
||||
}
|
||||
|
||||
logInfoTextWithTimeInSeconds( timeStamp, "Completed test :" + testCaseFolder.absolutePath() );
|
||||
}
|
||||
|
||||
// Invoke git diff
|
||||
|
||||
{
|
||||
QString folderContainingGit = regressionTestConfig.folderContainingGitTool();
|
||||
RiaGitDiff gitDiff( folderContainingGit );
|
||||
gitDiff.executeDiff( m_rootPath );
|
||||
|
||||
QString diffText = gitDiff.diffOutput();
|
||||
if ( !diffText.isEmpty() )
|
||||
{
|
||||
QFile file( htmlReportFileName );
|
||||
if ( file.open( QIODevice::Append | QIODevice::Text ) )
|
||||
{
|
||||
QTextStream stream( &file );
|
||||
|
||||
QString divSectionForDiff = R"(
|
||||
<div id = "destination-elem-id"[innerHtml] = "outputHtml">
|
||||
original
|
||||
</div>
|
||||
|
||||
)";
|
||||
stream << divSectionForDiff;
|
||||
stream << "</body>";
|
||||
|
||||
{
|
||||
QString generateDiffString = R"(
|
||||
<script type="text/javascript">
|
||||
|
||||
function generateDiff() {
|
||||
return `
|
||||
)";
|
||||
|
||||
generateDiffString += diffText;
|
||||
|
||||
generateDiffString += R"(
|
||||
`;
|
||||
};
|
||||
)";
|
||||
|
||||
generateDiffString += R"(
|
||||
var diffHtml = Diff2Html.getPrettyHtml(
|
||||
generateDiff(),
|
||||
{inputFormat: 'diff', showFiles: true, matching: 'lines', outputFormat: 'side-by-side'}
|
||||
);
|
||||
|
||||
document.getElementById("destination-elem-id").innerHTML = diffHtml;
|
||||
</script>
|
||||
</html>
|
||||
)";
|
||||
stream << generateDiffString;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RiaLogging::info( "\n" );
|
||||
logInfoTextWithTimeInSeconds( timeStamp, "Completed regression tests" );
|
||||
|
||||
QDir::setCurrent( currentApplicationPath );
|
||||
|
||||
m_runningRegressionTests = false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaRegressionTestRunner::findAndExecuteCommandFiles( const QDir& testCaseFolder,
|
||||
const RiaRegressionTest& regressionTestConfig,
|
||||
const QString& htmlReportFileName )
|
||||
{
|
||||
QStringList filterList;
|
||||
filterList << RegTestNames::commandFileFilter;
|
||||
|
||||
QFileInfoList commandFileEntries = testCaseFolder.entryInfoList( filterList );
|
||||
if ( commandFileEntries.empty() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QString currentAbsolutePath = QDir::current().absolutePath();
|
||||
|
||||
// Set current path to the folder containing the command file, as this is required when using file references
|
||||
// in the command file
|
||||
QDir::setCurrent( testCaseFolder.path() );
|
||||
|
||||
for ( const auto& fileInfo : commandFileEntries )
|
||||
{
|
||||
QString commandFile = fileInfo.absoluteFilePath();
|
||||
|
||||
QFile file( commandFile );
|
||||
if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
|
||||
{
|
||||
RiaLogging::error( "Failed to open command file : " + commandFile );
|
||||
}
|
||||
else
|
||||
{
|
||||
QTextStream in( &file );
|
||||
RicfCommandFileExecutor::instance()->executeCommands( in );
|
||||
}
|
||||
}
|
||||
|
||||
QDir::setCurrent( currentAbsolutePath );
|
||||
|
||||
// Create diff based on generated folders
|
||||
{
|
||||
QString html;
|
||||
|
||||
RiaTextFileCompare textFileCompare( regressionTestConfig.folderContainingDiffTool() );
|
||||
|
||||
QString baseFilesFolderName = testCaseFolder.filePath( RegTestNames::baseFilesFolderName );
|
||||
QString generatedFilesFolderName = testCaseFolder.filePath( RegTestNames::generatedFilesFolderName );
|
||||
|
||||
QFileInfo fib( baseFilesFolderName );
|
||||
QFileInfo fig( generatedFilesFolderName );
|
||||
|
||||
if ( fib.exists() && fig.exists() )
|
||||
{
|
||||
{
|
||||
QString headerText = testCaseFolder.dirName();
|
||||
|
||||
html += "<table>\n";
|
||||
html += " <tr>\n";
|
||||
html +=
|
||||
" <td colspan=\"3\" bgcolor=\"darkblue\" height=\"40\"> <b><font color=\"white\" size=\"3\"> " +
|
||||
headerText + " </font></b> </td>\n";
|
||||
html += " </tr>\n";
|
||||
|
||||
textFileCompare.runComparison( baseFilesFolderName, generatedFilesFolderName );
|
||||
|
||||
QString diff = textFileCompare.diffOutput();
|
||||
if ( diff.isEmpty() )
|
||||
{
|
||||
html += " <tr>\n";
|
||||
html += " <td colspan=\"3\" bgcolor=\"lightgray\"> <font color=\"green\">No text diff "
|
||||
"detected</font> </td> \n";
|
||||
html += " </tr>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
html += " <tr>\n";
|
||||
html += " <td colspan=\"3\" bgcolor=\"lightgray\"> <font color=\"red\">Text diff detected - "
|
||||
"output from diff tool : </font> </td> \n";
|
||||
html += " </tr>\n";
|
||||
}
|
||||
|
||||
// Table end
|
||||
html += "</table>\n";
|
||||
|
||||
if ( !diff.isEmpty() )
|
||||
{
|
||||
html += QString( "<code> %1 </code>" ).arg( diff );
|
||||
}
|
||||
}
|
||||
|
||||
QFile file( htmlReportFileName );
|
||||
if ( file.open( QIODevice::Append | QIODevice::Text ) )
|
||||
{
|
||||
QTextStream stream( &file );
|
||||
|
||||
stream << html;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaRegressionTestRunner::generateHtmlReport( const QFileInfoList& folderList,
|
||||
const QString& baseFolderName,
|
||||
const QString& generatedFolderName,
|
||||
const QString& diffFolderName,
|
||||
const QDir& testDir )
|
||||
{
|
||||
RiaImageCompareReporter imageCompareReporter;
|
||||
|
||||
// Minor workaround
|
||||
// Use registry to define if interactive diff images should be created
|
||||
// Defined by user in RiaRegressionTest
|
||||
{
|
||||
QSettings settings;
|
||||
|
||||
bool useInteractiveDiff = settings.value( "showInteractiveDiffImages" ).toBool();
|
||||
if ( useInteractiveDiff )
|
||||
{
|
||||
imageCompareReporter.showInteractiveOnly();
|
||||
}
|
||||
}
|
||||
|
||||
for ( const QFileInfo& fi : folderList )
|
||||
{
|
||||
QDir testCaseFolder( fi.filePath() );
|
||||
|
||||
QString testFolderName = testCaseFolder.dirName();
|
||||
QString reportBaseFolderName = testCaseFolder.filePath( baseFolderName );
|
||||
QString reportGeneratedFolderName = testCaseFolder.filePath( generatedFolderName );
|
||||
QString reportDiffFolderName = testCaseFolder.filePath( diffFolderName );
|
||||
|
||||
imageCompareReporter.addImageDirectoryComparisonSet( testFolderName.toStdString(),
|
||||
reportBaseFolderName.toStdString(),
|
||||
reportGeneratedFolderName.toStdString(),
|
||||
reportDiffFolderName.toStdString() );
|
||||
}
|
||||
|
||||
QString htmlReportFileName = testDir.filePath( RegTestNames::reportFileName );
|
||||
|
||||
QString htmldiff2htmlText = diff2htmlHeaderText( m_rootPath );
|
||||
imageCompareReporter.generateHTMLReport( htmlReportFileName.toStdString(), htmldiff2htmlText.toStdString() );
|
||||
|
||||
return htmlReportFileName;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaRegressionTestRunner::removeDirectoryWithContent( QDir& dirToDelete )
|
||||
{
|
||||
caf::Utils::removeDirectoryAndFilesRecursively( dirToDelete.absolutePath() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaRegressionTestRunner::setDefaultSnapshotSizeFor3dViews()
|
||||
{
|
||||
RiuMainWindow* mainWnd = RiuMainWindow::instance();
|
||||
if ( !mainWnd ) return;
|
||||
|
||||
QSize defaultSize = RiaRegressionTestRunner::regressionDefaultImageSize();
|
||||
|
||||
RiuMainWindowTools::setFixedWindowSizeFor3dViews( mainWnd, defaultSize.width(), defaultSize.height() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaRegressionTestRunner::setDefaultSnapshotSizeForPlotWindows()
|
||||
{
|
||||
RiuPlotMainWindow* plotMainWindow = RiaGuiApplication::instance()->mainPlotWindow();
|
||||
if ( !plotMainWindow ) return;
|
||||
|
||||
QSize defaultSize = RiaRegressionTestRunner::regressionDefaultImageSize();
|
||||
|
||||
RiuMainWindowTools::setWindowSizeOnWidgetsInMdiWindows( plotMainWindow, defaultSize.width(), defaultSize.height() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QSize RiaRegressionTestRunner::regressionDefaultImageSize()
|
||||
{
|
||||
return QSize( 1000, 745 );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaRegressionTestRunner::diff2htmlHeaderText( const QString& testRootPath )
|
||||
{
|
||||
QString html;
|
||||
|
||||
QString oldProjPath = QDir::fromNativeSeparators( testRootPath );
|
||||
QStringList pathFolders = oldProjPath.split( "/", QString::KeepEmptyParts );
|
||||
|
||||
QString path;
|
||||
for ( const auto& f : pathFolders )
|
||||
{
|
||||
if ( f.compare( "ProjectFiles", Qt::CaseInsensitive ) == 0 ) break;
|
||||
path += f;
|
||||
path += "/";
|
||||
}
|
||||
|
||||
{
|
||||
html = R"(
|
||||
<!-- CSS -->
|
||||
<link rel = "stylesheet" type = "text/css" href = "dist/diff2html.css">
|
||||
|
||||
<!--Javascripts-->
|
||||
<script type = "text/javascript" src = "dist/diff2html.js"></script>
|
||||
<script type = "text/javascript" src = "dist/diff2html-ui.js"></script>
|
||||
)";
|
||||
|
||||
QString pathToDiff2html = path + "diff2html/dist/";
|
||||
html = html.replace( "dist/", pathToDiff2html );
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QFileInfoList RiaRegressionTestRunner::subDirectoriesForTestExecution( const QDir& directory )
|
||||
{
|
||||
if ( m_testFilter.isEmpty() )
|
||||
{
|
||||
QFileInfoList folderList = directory.entryInfoList();
|
||||
|
||||
return folderList;
|
||||
}
|
||||
|
||||
bool anyMatchFound = false;
|
||||
|
||||
QFileInfoList foldersMatchingTestFilter;
|
||||
|
||||
QFileInfoList folderList = directory.entryInfoList();
|
||||
for ( const auto& fi : folderList )
|
||||
{
|
||||
QString path = fi.path();
|
||||
QString baseName = fi.baseName();
|
||||
|
||||
for ( const auto& s : m_testFilter )
|
||||
{
|
||||
QString trimmed = s.trimmed();
|
||||
if ( ( m_appendAllTestsAfterLastItemInFilter && anyMatchFound ) ||
|
||||
baseName.contains( trimmed, Qt::CaseInsensitive ) )
|
||||
{
|
||||
foldersMatchingTestFilter.push_back( fi );
|
||||
anyMatchFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return foldersMatchingTestFilter;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaRegressionTestRunner::executeRegressionTests()
|
||||
{
|
||||
RiaRegressionTest testConfig;
|
||||
testConfig.readSettingsFromApplicationStore();
|
||||
|
||||
QString testPath = testConfig.regressionTestFolder();
|
||||
QStringList testFilter = testConfig.testFilter().split( ";", QString::SkipEmptyParts );
|
||||
|
||||
if ( testConfig.appendTestsAfterTestFilter )
|
||||
{
|
||||
m_appendAllTestsAfterLastItemInFilter = true;
|
||||
}
|
||||
|
||||
executeRegressionTests( testPath, testFilter );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaRegressionTestRunner::executeRegressionTests( const QString& regressionTestPath, const QStringList& testFilter )
|
||||
{
|
||||
RiuMainWindow* mainWnd = RiuMainWindow::instance();
|
||||
if ( mainWnd )
|
||||
{
|
||||
mainWnd->hideAllDockWidgets();
|
||||
mainWnd->statusBar()->close();
|
||||
|
||||
mainWnd->setDefaultWindowSize();
|
||||
|
||||
m_regressionTestSettings.readSettingsFromApplicationStore();
|
||||
|
||||
m_rootPath = regressionTestPath;
|
||||
m_testFilter = testFilter;
|
||||
runRegressionTest();
|
||||
|
||||
mainWnd->loadWinGeoAndDockToolBarLayout();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaRegressionTestRunner::isRunningRegressionTests() const
|
||||
{
|
||||
return m_runningRegressionTests;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaRegressionTestRunner::useOpenMPForGeometryCreation() const
|
||||
{
|
||||
if ( !m_runningRegressionTests ) return false;
|
||||
|
||||
return m_regressionTestSettings.useOpenMPForGeometryCreation;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaRegressionTestRunner::updateRegressionTest( const QString& testRootPath )
|
||||
{
|
||||
// Find all sub folders
|
||||
|
||||
QDir testDir( testRootPath ); // If string is empty it will end up as cwd
|
||||
testDir.setFilter( QDir::Dirs );
|
||||
QStringList dirNameFilter;
|
||||
dirNameFilter.append( RegTestNames::testFolderFilter );
|
||||
testDir.setNameFilters( dirNameFilter );
|
||||
|
||||
QFileInfoList folderList = testDir.entryInfoList();
|
||||
|
||||
for ( const auto& fi : folderList )
|
||||
{
|
||||
QDir testCaseFolder( fi.filePath() );
|
||||
|
||||
QDir baseDir( testCaseFolder.filePath( RegTestNames::baseFolderName ) );
|
||||
removeDirectoryWithContent( baseDir );
|
||||
testCaseFolder.mkdir( RegTestNames::baseFolderName );
|
||||
|
||||
QDir genDir( testCaseFolder.filePath( RegTestNames::generatedFolderName ) );
|
||||
|
||||
QStringList imageFileNames = genDir.entryList();
|
||||
|
||||
for ( int fIdx = 0; fIdx < imageFileNames.size(); ++fIdx )
|
||||
{
|
||||
QString fileName = imageFileNames[fIdx];
|
||||
QFile::copy( genDir.filePath( fileName ), baseDir.filePath( fileName ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaRegressionTest.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QSize>
|
||||
#include <QStringList>
|
||||
|
||||
class QDir;
|
||||
class RiaRegressionTest;
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaRegressionTestRunner
|
||||
{
|
||||
public:
|
||||
static RiaRegressionTestRunner* instance();
|
||||
|
||||
void executeRegressionTests( const QString& regressionTestPath, const QStringList& testFilter );
|
||||
void executeRegressionTests();
|
||||
|
||||
bool isRunningRegressionTests() const;
|
||||
bool useOpenMPForGeometryCreation() const;
|
||||
|
||||
static void updateRegressionTest( const QString& testRootPath );
|
||||
|
||||
static void setDefaultSnapshotSizeFor3dViews();
|
||||
static void setDefaultSnapshotSizeForPlotWindows();
|
||||
|
||||
private:
|
||||
RiaRegressionTestRunner();
|
||||
|
||||
void runRegressionTest();
|
||||
|
||||
bool findAndExecuteCommandFiles( const QDir& testCaseFolder,
|
||||
const RiaRegressionTest& regressionTestConfig,
|
||||
const QString& htmlReportFileName );
|
||||
|
||||
QString generateHtmlReport( const QFileInfoList& folderList,
|
||||
const QString& baseFolderName,
|
||||
const QString& generatedFolderName,
|
||||
const QString& diffFolderName,
|
||||
const QDir& testDir );
|
||||
|
||||
static void removeDirectoryWithContent( QDir& dirToDelete );
|
||||
static QSize regressionDefaultImageSize();
|
||||
static QString diff2htmlHeaderText( const QString& testRootPath );
|
||||
QFileInfoList subDirectoriesForTestExecution( const QDir& directory );
|
||||
|
||||
private:
|
||||
QString m_rootPath;
|
||||
QStringList m_testFilter;
|
||||
bool m_appendAllTestsAfterLastItemInFilter;
|
||||
bool m_runningRegressionTests;
|
||||
RiaRegressionTest m_regressionTestSettings;
|
||||
};
|
||||
@@ -0,0 +1,136 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaSimWellBranchTools.h"
|
||||
|
||||
#include "RiaApplication.h"
|
||||
|
||||
#include "RigEclipseCaseData.h"
|
||||
|
||||
#include "RimEclipseCase.h"
|
||||
#include "RimProject.h"
|
||||
#include "RimWellPlotTools.h"
|
||||
|
||||
#include "cafPdmUiOrdering.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<const RigWellPath*> RiaSimWellBranchTools::simulationWellBranches( const QString& simWellName,
|
||||
bool useAutoDetectionOfBranches )
|
||||
{
|
||||
RiaApplication* app = RiaApplication::instance();
|
||||
RimProject* proj = app->project();
|
||||
|
||||
// Find first case containing the specified simulation well
|
||||
std::vector<RimEclipseCase*> simCases;
|
||||
proj->descendantsIncludingThisOfType( simCases );
|
||||
|
||||
auto caseItr = std::find_if( simCases.begin(), simCases.end(), [&simWellName]( const RimEclipseCase* eclCase ) {
|
||||
const auto& eclData = eclCase->eclipseCaseData();
|
||||
return eclData != nullptr && eclData->hasSimulationWell( simWellName );
|
||||
} );
|
||||
RimEclipseCase* eclipseCase = caseItr != simCases.end() ? *caseItr : nullptr;
|
||||
RigEclipseCaseData* eclCaseData = eclipseCase != nullptr ? eclipseCase->eclipseCaseData() : nullptr;
|
||||
return eclCaseData != nullptr ? eclCaseData->simulationWellBranches( simWellName, false, useAutoDetectionOfBranches )
|
||||
: std::vector<const RigWellPath*>();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QList<caf::PdmOptionItemInfo>
|
||||
RiaSimWellBranchTools::valueOptionsForBranchIndexField( const std::vector<const RigWellPath*>& simulationWellPaths )
|
||||
{
|
||||
QList<caf::PdmOptionItemInfo> options;
|
||||
|
||||
size_t branchCount = simulationWellPaths.size();
|
||||
if ( simulationWellPaths.size() == 0 )
|
||||
{
|
||||
options.push_front( caf::PdmOptionItemInfo( "None", -1 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( int bIdx = 0; bIdx < static_cast<int>( branchCount ); ++bIdx )
|
||||
{
|
||||
options.push_back(
|
||||
caf::PdmOptionItemInfo( "Branch " + QString::number( bIdx + 1 ), QVariant::fromValue( bIdx ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaSimWellBranchTools::appendSimWellBranchFieldsIfRequiredFromWellName( caf::PdmUiOrdering* uiOrdering,
|
||||
const QString& wellPathOrSimWellName,
|
||||
const caf::PdmField<bool>& branchDetectionField,
|
||||
const caf::PdmField<int>& branchIndexField )
|
||||
{
|
||||
if ( !RimWellPlotTools::hasAssociatedWellPath( wellPathOrSimWellName ) )
|
||||
{
|
||||
const QString simWellName = RimWellPlotTools::simWellName( wellPathOrSimWellName );
|
||||
|
||||
RiaSimWellBranchTools::appendSimWellBranchFieldsIfRequiredFromSimWellName( uiOrdering,
|
||||
simWellName,
|
||||
branchDetectionField,
|
||||
branchIndexField );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaSimWellBranchTools::appendSimWellBranchFieldsIfRequiredFromSimWellName( caf::PdmUiOrdering* uiOrdering,
|
||||
const QString& simWellName,
|
||||
const caf::PdmField<bool>& branchDetectionField,
|
||||
const caf::PdmField<int>& branchIndexField )
|
||||
{
|
||||
if ( RiaSimWellBranchTools::simulationWellBranches( simWellName, true ).size() > 1 )
|
||||
{
|
||||
uiOrdering->add( &branchDetectionField );
|
||||
|
||||
if ( RiaSimWellBranchTools::simulationWellBranches( simWellName, branchDetectionField ).size() > 1 )
|
||||
{
|
||||
uiOrdering->add( &branchIndexField );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiaSimWellBranchTools::clampBranchIndex( const QString& simWellName, int branchIndexValue, bool branchDetection )
|
||||
{
|
||||
auto branches = RiaSimWellBranchTools::simulationWellBranches( simWellName, branchDetection );
|
||||
|
||||
if ( branches.size() == 0 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int maxIndexValue = static_cast<int>( branches.size() ) - 1;
|
||||
if ( branchIndexValue > maxIndexValue )
|
||||
{
|
||||
branchIndexValue = maxIndexValue;
|
||||
}
|
||||
|
||||
return branchIndexValue;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "cafPdmField.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
#include <vector>
|
||||
|
||||
class RigWellPath;
|
||||
|
||||
namespace caf
|
||||
{
|
||||
class PdmOptionItemInfo;
|
||||
class PdmUiOrdering;
|
||||
} // namespace caf
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaSimWellBranchTools
|
||||
{
|
||||
public:
|
||||
static std::vector<const RigWellPath*> simulationWellBranches( const QString& simWellName,
|
||||
bool useAutoDetectionOfBranches );
|
||||
|
||||
static QList<caf::PdmOptionItemInfo>
|
||||
valueOptionsForBranchIndexField( const std::vector<const RigWellPath*>& simulationWellPaths );
|
||||
|
||||
static void appendSimWellBranchFieldsIfRequiredFromWellName( caf::PdmUiOrdering* uiOrdering,
|
||||
const QString& wellPathOrSimWellName,
|
||||
const caf::PdmField<bool>& branchDetectionField,
|
||||
const caf::PdmField<int>& branchIndexField );
|
||||
|
||||
static void appendSimWellBranchFieldsIfRequiredFromSimWellName( caf::PdmUiOrdering* uiOrdering,
|
||||
const QString& simWellName,
|
||||
const caf::PdmField<bool>& branchDetectionField,
|
||||
const caf::PdmField<int>& branchIndexField );
|
||||
|
||||
static int clampBranchIndex( const QString& simWellName, int branchIndexValue, bool branchDetection );
|
||||
};
|
||||
@@ -0,0 +1,96 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011- Statoil ASA
|
||||
// Copyright (C) 2013- Ceetron Solutions AS
|
||||
// Copyright (C) 2011-2012 Ceetron AS
|
||||
//
|
||||
// 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 "RiaStatisticsTools.h"
|
||||
|
||||
#include "RifEclipseSummaryAddress.h"
|
||||
#include "RigStatisticsMath.h"
|
||||
|
||||
#include "cafAssert.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const QString RiaStatisticsTools::replacePercentileByPValueText( const QString& percentile )
|
||||
{
|
||||
QString result = percentile;
|
||||
|
||||
if ( result == ENSEMBLE_STAT_P10_QUANTITY_NAME )
|
||||
{
|
||||
result = ENSEMBLE_STAT_P90_QUANTITY_NAME;
|
||||
}
|
||||
else if ( result == ENSEMBLE_STAT_P90_QUANTITY_NAME )
|
||||
{
|
||||
result = ENSEMBLE_STAT_P10_QUANTITY_NAME;
|
||||
}
|
||||
else if ( percentile.contains( QString( "%1:" ).arg( ENSEMBLE_STAT_P10_QUANTITY_NAME ) ) )
|
||||
{
|
||||
result.replace( ENSEMBLE_STAT_P10_QUANTITY_NAME, ENSEMBLE_STAT_P90_QUANTITY_NAME );
|
||||
}
|
||||
else if ( percentile.contains( QString( "%1:" ).arg( ENSEMBLE_STAT_P90_QUANTITY_NAME ) ) )
|
||||
{
|
||||
result.replace( ENSEMBLE_STAT_P90_QUANTITY_NAME, ENSEMBLE_STAT_P10_QUANTITY_NAME );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaStatisticsTools::pearsonCorrelation( const std::vector<double>& xValues, const std::vector<double>& yValues )
|
||||
{
|
||||
const double eps = 1.0e-8;
|
||||
double rangeX = 0.0, rangeY = 0.0;
|
||||
RigStatisticsMath::calculateBasicStatistics( xValues, nullptr, nullptr, nullptr, &rangeX, nullptr, nullptr );
|
||||
RigStatisticsMath::calculateBasicStatistics( yValues, nullptr, nullptr, nullptr, &rangeY, nullptr, nullptr );
|
||||
if ( rangeX < eps || rangeY < eps ) return 0.0;
|
||||
|
||||
if ( xValues.size() != yValues.size() ) return 0.0;
|
||||
if ( xValues.empty() ) return 0.0;
|
||||
|
||||
size_t sampleSize = xValues.size();
|
||||
|
||||
double meanX = 0.0, meanY = 0.0;
|
||||
for ( size_t i = 0; i < sampleSize; ++i )
|
||||
{
|
||||
meanX += xValues[i];
|
||||
meanY += yValues[i];
|
||||
}
|
||||
meanX /= sampleSize;
|
||||
meanY /= sampleSize;
|
||||
|
||||
double sumNumerator = 0.0;
|
||||
double sumxDiffSquared = 0.0, sumyDiffSquared = 0.0;
|
||||
for ( size_t i = 0; i < sampleSize; ++i )
|
||||
{
|
||||
double xDiff = xValues[i] - meanX;
|
||||
double yDiff = yValues[i] - meanY;
|
||||
sumNumerator += xDiff * yDiff;
|
||||
sumxDiffSquared += xDiff * xDiff;
|
||||
sumyDiffSquared += yDiff * yDiff;
|
||||
}
|
||||
|
||||
if ( sumxDiffSquared < eps && sumyDiffSquared < eps ) return 1.0;
|
||||
if ( sumxDiffSquared < eps || sumyDiffSquared < eps ) return 0.0;
|
||||
|
||||
return sumNumerator / ( std::sqrt( sumxDiffSquared ) * std::sqrt( sumyDiffSquared ) );
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011- Statoil ASA
|
||||
// Copyright (C) 2013- Ceetron Solutions AS
|
||||
// Copyright (C) 2011-2012 Ceetron AS
|
||||
//
|
||||
// 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 <cmath>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
class QString;
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaStatisticsTools
|
||||
{
|
||||
public:
|
||||
static const QString replacePercentileByPValueText( const QString& percentile );
|
||||
|
||||
template <class NumberType>
|
||||
static bool isInvalidNumber( NumberType value )
|
||||
{
|
||||
return !isValidNumber<NumberType>( value );
|
||||
}
|
||||
|
||||
template <class NumberType>
|
||||
static bool isValidNumber( NumberType value )
|
||||
{
|
||||
if ( std::isinf( value ) ) return false;
|
||||
if ( std::isnan( value ) ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static double pearsonCorrelation( const std::vector<double>& xValues, const std::vector<double>& yValues );
|
||||
};
|
||||
@@ -0,0 +1,192 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaStdStringTools.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::string RiaStdStringTools::trimString( const std::string& s )
|
||||
{
|
||||
auto sCopy = s.substr( 0, s.find_last_not_of( ' ' ) + 1 );
|
||||
sCopy = sCopy.substr( sCopy.find_first_not_of( ' ' ) );
|
||||
|
||||
return sCopy;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaStdStringTools::isNumber( const std::string& s, char decimalPoint )
|
||||
{
|
||||
if ( s.empty() ) return false;
|
||||
if ( findCharMatchCount( s, decimalPoint ) > 1 ) return false;
|
||||
if ( findCharMatchCount( s, '-' ) > 1 ) return false;
|
||||
if ( findCharMatchCount( s, 'e' ) > 1 ) return false;
|
||||
if ( findCharMatchCount( s, 'E' ) > 1 ) return false;
|
||||
|
||||
std::string matchChars( "0123456789eE-+" );
|
||||
matchChars.append( 1, decimalPoint );
|
||||
|
||||
auto it = s.find_first_not_of( matchChars );
|
||||
|
||||
return ( it == std::string::npos );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int16_t RiaStdStringTools::toInt16( const std::string& s )
|
||||
{
|
||||
return (int16_t)toInt( s );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiaStdStringTools::toInt( const std::string& s )
|
||||
{
|
||||
int intValue = -1;
|
||||
|
||||
try
|
||||
{
|
||||
intValue = std::stoi( s );
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
}
|
||||
|
||||
return intValue;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaStdStringTools::toDouble( const std::string& s )
|
||||
{
|
||||
double doubleValue = -1.0;
|
||||
|
||||
char* end;
|
||||
doubleValue = std::strtod( s.data(), &end );
|
||||
|
||||
return doubleValue;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaStdStringTools::containsAlphabetic( const std::string& s )
|
||||
{
|
||||
return std::find_if( s.begin(), s.end(), []( char c ) { return isalpha( c ); } ) != s.end();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaStdStringTools::startsWithAlphabetic( const std::string& s )
|
||||
{
|
||||
if ( s.empty() ) return false;
|
||||
|
||||
return isalpha( s[0] ) != 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaStdStringTools::endsWith( const std::string& mainStr, const std::string& toMatch )
|
||||
{
|
||||
if ( mainStr.size() >= toMatch.size() &&
|
||||
mainStr.compare( mainStr.size() - toMatch.size(), toMatch.size(), toMatch ) == 0 )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<std::string> RiaStdStringTools::splitStringBySpace( const std::string& s )
|
||||
{
|
||||
std::vector<std::string> words;
|
||||
|
||||
splitByDelimiter( s, words );
|
||||
|
||||
return words;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RiaStdStringTools::findCharMatchCount( const std::string& s, char c )
|
||||
{
|
||||
size_t count = 0;
|
||||
size_t pos = 0;
|
||||
while ( ( pos = s.find_first_of( c, pos + 1 ) ) != std::string::npos )
|
||||
{
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Function to find Levenshtein Distance between two strings (x and y).
|
||||
/// Adapted from pseudocode from wikipedia: https://en.wikipedia.org/wiki/Levenshtein_distance
|
||||
/// Implementation is the Wagner-Fischer variant: https://en.wikipedia.org/wiki/Wagner-Fischer_algorithm
|
||||
///
|
||||
/// Return value is higher when strings are more "different", and zero when strings are equal.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RiaStdStringTools::computeEditDistance( const std::string& x, const std::string& y )
|
||||
{
|
||||
// for all i and j, T[i,j] will hold the Levenshtein distance between
|
||||
// the first i characters of x and the first j characters of y
|
||||
int m = static_cast<int>( x.length() );
|
||||
int n = static_cast<int>( y.length() );
|
||||
|
||||
std::vector<std::vector<int>> T( m + 1, std::vector<int>( n + 1, 0 ) );
|
||||
|
||||
// source prefixes can be transformed into empty string by
|
||||
// dropping all characters
|
||||
for ( int i = 1; i <= m; i++ )
|
||||
T[i][0] = i;
|
||||
|
||||
// target prefixes can be reached from empty source prefix
|
||||
// by inserting every character
|
||||
for ( int j = 1; j <= n; j++ )
|
||||
T[0][j] = j;
|
||||
|
||||
// fill the lookup table in bottom-up manner
|
||||
for ( int i = 1; i <= m; i++ )
|
||||
{
|
||||
for ( int j = 1; j <= n; j++ )
|
||||
{
|
||||
int substitutionCost;
|
||||
if ( x[i - 1] == y[j - 1] )
|
||||
substitutionCost = 0;
|
||||
else
|
||||
substitutionCost = 1;
|
||||
|
||||
int deletion = T[i - 1][j] + 1;
|
||||
int insertion = T[i][j - 1] + 1;
|
||||
int replacement = T[i - 1][j - 1] + substitutionCost;
|
||||
T[i][j] = std::min( std::min( deletion, insertion ), replacement );
|
||||
}
|
||||
}
|
||||
|
||||
// The distance between the two full strings as the last value computed.
|
||||
return T[m][n];
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 <algorithm>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaStdStringTools
|
||||
{
|
||||
public:
|
||||
static std::string trimString( const std::string& s );
|
||||
static bool isNumber( const std::string& s, char decimalPoint );
|
||||
|
||||
static int16_t toInt16( const std::string& s );
|
||||
static int toInt( const std::string& s );
|
||||
static double toDouble( const std::string& s );
|
||||
static bool containsAlphabetic( const std::string& s );
|
||||
static bool startsWithAlphabetic( const std::string& s );
|
||||
|
||||
static bool endsWith( const std::string& mainStr, const std::string& toMatch );
|
||||
|
||||
static std::vector<std::string> splitStringBySpace( const std::string& s );
|
||||
|
||||
static int computeEditDistance( const std::string& x, const std::string& y );
|
||||
|
||||
private:
|
||||
template <class Container>
|
||||
static void splitByDelimiter( const std::string& str, Container& cont, char delimiter = ' ' );
|
||||
static size_t findCharMatchCount( const std::string& s, char c );
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
template <class Container>
|
||||
void RiaStdStringTools::splitByDelimiter( const std::string& str, Container& cont, char delimiter )
|
||||
{
|
||||
std::stringstream ss( str );
|
||||
std::string token;
|
||||
while ( std::getline( ss, token, delimiter ) )
|
||||
{
|
||||
if ( token.find_first_not_of( delimiter ) != std::string::npos )
|
||||
{
|
||||
cont.push_back( token );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011- Statoil ASA
|
||||
// Copyright (C) 2013- Ceetron Solutions AS
|
||||
// Copyright (C) 2011-2012 Ceetron AS
|
||||
//
|
||||
// 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 "RiaStringEncodingTools.h"
|
||||
|
||||
const std::string RiaStringEncodingTools::toNativeEncoded( const QString& qstring )
|
||||
{
|
||||
#ifdef WIN32
|
||||
return std::string( qstring.toLatin1().data() );
|
||||
#else
|
||||
return std::string( qstring.toUtf8().data() );
|
||||
#endif
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const QString RiaStringEncodingTools::fromNativeEncoded( const char* native )
|
||||
{
|
||||
#ifdef WIN32
|
||||
return QString::fromLatin1( native );
|
||||
#else
|
||||
return QString::fromUtf8( native );
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2011- Statoil ASA
|
||||
// Copyright (C) 2013- Ceetron Solutions AS
|
||||
// Copyright (C) 2011-2012 Ceetron AS
|
||||
//
|
||||
// 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 <QByteArray>
|
||||
#include <QString>
|
||||
#include <string>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaStringEncodingTools
|
||||
{
|
||||
public:
|
||||
static const std::string toNativeEncoded( const QString& qstring );
|
||||
|
||||
static const QString fromNativeEncoded( const char* native );
|
||||
};
|
||||
@@ -0,0 +1,406 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaSummaryCurveAnalyzer.h"
|
||||
#include "RiaStdStringTools.h"
|
||||
|
||||
#include "RiaSummaryCurveDefinition.h"
|
||||
|
||||
#include "RimSummaryCurve.h"
|
||||
#include "RimSummaryCurveCollection.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaSummaryCurveAnalyzer::RiaSummaryCurveAnalyzer()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaSummaryCurveAnalyzer::appendAddresses( const std::vector<RifEclipseSummaryAddress>& allAddresses )
|
||||
{
|
||||
for ( const auto& adr : allAddresses )
|
||||
{
|
||||
analyzeSingleAddress( adr );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaSummaryCurveAnalyzer::appendAddresses( const std::set<RifEclipseSummaryAddress>& allAddresses )
|
||||
{
|
||||
for ( const auto& adr : allAddresses )
|
||||
{
|
||||
analyzeSingleAddress( adr );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<std::string> RiaSummaryCurveAnalyzer::quantities() const
|
||||
{
|
||||
return m_quantities;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<std::string> RiaSummaryCurveAnalyzer::quantityNamesWithHistory() const
|
||||
{
|
||||
assignCategoryToQuantities();
|
||||
|
||||
return m_quantitiesWithMatchingHistory;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<std::string> RiaSummaryCurveAnalyzer::quantityNamesNoHistory() const
|
||||
{
|
||||
assignCategoryToQuantities();
|
||||
|
||||
return m_quantitiesNoMatchingHistory;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::string RiaSummaryCurveAnalyzer::quantityNameForTitle() const
|
||||
{
|
||||
if ( quantityNamesWithHistory().size() == 1 && quantityNamesNoHistory().empty() )
|
||||
{
|
||||
return *quantityNamesWithHistory().begin();
|
||||
}
|
||||
|
||||
if ( quantityNamesNoHistory().size() == 1 && quantityNamesWithHistory().empty() )
|
||||
{
|
||||
return *quantityNamesNoHistory().begin();
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<std::string> RiaSummaryCurveAnalyzer::wellNames() const
|
||||
{
|
||||
return m_wellNames;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<std::string> RiaSummaryCurveAnalyzer::wellGroupNames() const
|
||||
{
|
||||
return m_wellGroupNames;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<int> RiaSummaryCurveAnalyzer::regionNumbers() const
|
||||
{
|
||||
return m_regionNumbers;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<std::string> RiaSummaryCurveAnalyzer::wellCompletions( const std::string& wellName ) const
|
||||
{
|
||||
std::set<std::string> connections;
|
||||
|
||||
for ( const auto& conn : m_wellCompletions )
|
||||
{
|
||||
if ( conn.first == wellName )
|
||||
{
|
||||
connections.insert( conn.second );
|
||||
}
|
||||
}
|
||||
|
||||
return connections;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<int> RiaSummaryCurveAnalyzer::wellSegmentNumbers( const std::string& wellName ) const
|
||||
{
|
||||
std::set<int> segmentNumberForWell;
|
||||
|
||||
for ( const auto& wellSegment : m_wellSegmentNumbers )
|
||||
{
|
||||
if ( wellName.empty() || std::get<0>( wellSegment ) == wellName )
|
||||
{
|
||||
segmentNumberForWell.insert( std::get<1>( wellSegment ) );
|
||||
}
|
||||
}
|
||||
|
||||
return segmentNumberForWell;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<std::string> RiaSummaryCurveAnalyzer::blocks() const
|
||||
{
|
||||
return m_blocks;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<int> RiaSummaryCurveAnalyzer::aquifers() const
|
||||
{
|
||||
return m_aquifers;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<RifEclipseSummaryAddress::SummaryVarCategory> RiaSummaryCurveAnalyzer::categories() const
|
||||
{
|
||||
return m_categories;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<QString> RiaSummaryCurveAnalyzer::identifierTexts( RifEclipseSummaryAddress::SummaryVarCategory category,
|
||||
const std::string& secondaryIdentifier ) const
|
||||
{
|
||||
std::vector<QString> identifierStrings;
|
||||
|
||||
if ( category == RifEclipseSummaryAddress::SUMMARY_REGION )
|
||||
{
|
||||
for ( const auto& regionNumber : m_regionNumbers )
|
||||
{
|
||||
identifierStrings.push_back( QString::number( regionNumber ) );
|
||||
}
|
||||
}
|
||||
else if ( category == RifEclipseSummaryAddress::SUMMARY_WELL )
|
||||
{
|
||||
for ( const auto& wellName : m_wellNames )
|
||||
{
|
||||
identifierStrings.push_back( QString::fromStdString( wellName ) );
|
||||
}
|
||||
}
|
||||
else if ( category == RifEclipseSummaryAddress::SUMMARY_WELL_GROUP )
|
||||
{
|
||||
for ( const auto& wellGroupName : m_wellGroupNames )
|
||||
{
|
||||
identifierStrings.push_back( QString::fromStdString( wellGroupName ) );
|
||||
}
|
||||
}
|
||||
else if ( category == RifEclipseSummaryAddress::SUMMARY_BLOCK )
|
||||
{
|
||||
for ( const auto& ijkBlock : m_blocks )
|
||||
{
|
||||
identifierStrings.push_back( QString::fromStdString( ijkBlock ) );
|
||||
}
|
||||
}
|
||||
else if ( category == RifEclipseSummaryAddress::SUMMARY_WELL_SEGMENT )
|
||||
{
|
||||
auto segmentNumbers = wellSegmentNumbers( secondaryIdentifier );
|
||||
for ( const auto& segment : segmentNumbers )
|
||||
{
|
||||
identifierStrings.push_back( QString::number( segment ) );
|
||||
}
|
||||
}
|
||||
else if ( category == RifEclipseSummaryAddress::SUMMARY_WELL_COMPLETION )
|
||||
{
|
||||
auto connections = wellCompletions( secondaryIdentifier );
|
||||
for ( const auto& conn : connections )
|
||||
{
|
||||
identifierStrings.push_back( QString::fromStdString( conn ) );
|
||||
}
|
||||
}
|
||||
else if ( category == RifEclipseSummaryAddress::SUMMARY_AQUIFER )
|
||||
{
|
||||
for ( const auto& aquifer : m_aquifers )
|
||||
{
|
||||
identifierStrings.push_back( QString::number( aquifer ) );
|
||||
}
|
||||
}
|
||||
|
||||
return identifierStrings;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<RifEclipseSummaryAddress>
|
||||
RiaSummaryCurveAnalyzer::addressesForCategory( const std::set<RifEclipseSummaryAddress>& addresses,
|
||||
RifEclipseSummaryAddress::SummaryVarCategory category )
|
||||
{
|
||||
std::vector<RifEclipseSummaryAddress> filteredAddresses;
|
||||
|
||||
for ( const auto& adr : addresses )
|
||||
{
|
||||
if ( adr.category() == category )
|
||||
{
|
||||
filteredAddresses.push_back( adr );
|
||||
}
|
||||
}
|
||||
|
||||
return filteredAddresses;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::string RiaSummaryCurveAnalyzer::correspondingHistorySummaryCurveName( const std::string& curveName )
|
||||
{
|
||||
static std::string historyIdentifier = "H";
|
||||
|
||||
if ( RiaStdStringTools::endsWith( curveName, historyIdentifier ) )
|
||||
{
|
||||
std::string candidate = curveName.substr( 0, curveName.size() - 1 );
|
||||
return candidate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return curveName + historyIdentifier;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaSummaryCurveAnalyzer::clear()
|
||||
{
|
||||
m_quantities.clear();
|
||||
m_wellNames.clear();
|
||||
m_wellGroupNames.clear();
|
||||
m_regionNumbers.clear();
|
||||
m_categories.clear();
|
||||
m_wellCompletions.clear();
|
||||
m_wellSegmentNumbers.clear();
|
||||
m_blocks.clear();
|
||||
m_aquifers.clear();
|
||||
|
||||
m_quantitiesNoMatchingHistory.clear();
|
||||
m_quantitiesWithMatchingHistory.clear();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaSummaryCurveAnalyzer::assignCategoryToQuantities() const
|
||||
{
|
||||
if ( !m_quantities.empty() )
|
||||
{
|
||||
if ( m_quantitiesWithMatchingHistory.empty() && m_quantitiesNoMatchingHistory.empty() )
|
||||
{
|
||||
computeQuantityNamesWithHistory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaSummaryCurveAnalyzer::computeQuantityNamesWithHistory() const
|
||||
{
|
||||
m_quantitiesNoMatchingHistory.clear();
|
||||
m_quantitiesWithMatchingHistory.clear();
|
||||
|
||||
const std::string historyIdentifier( "H" );
|
||||
|
||||
for ( const auto& s : m_quantities )
|
||||
{
|
||||
std::string correspondingHistoryCurve = correspondingHistorySummaryCurveName( s );
|
||||
|
||||
if ( m_quantities.find( correspondingHistoryCurve ) != m_quantities.end() )
|
||||
{
|
||||
// Insert the curve name without H
|
||||
if ( RiaStdStringTools::endsWith( s, historyIdentifier ) )
|
||||
{
|
||||
m_quantitiesWithMatchingHistory.insert( correspondingHistoryCurve );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_quantitiesWithMatchingHistory.insert( s );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_quantitiesNoMatchingHistory.insert( s );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaSummaryCurveAnalyzer::analyzeSingleAddress( const RifEclipseSummaryAddress& address )
|
||||
{
|
||||
const std::string& wellName = address.wellName();
|
||||
|
||||
if ( !wellName.empty() )
|
||||
{
|
||||
m_wellNames.insert( wellName );
|
||||
}
|
||||
|
||||
if ( !address.quantityName().empty() )
|
||||
{
|
||||
m_quantities.insert( address.quantityName() );
|
||||
}
|
||||
|
||||
if ( !address.wellGroupName().empty() )
|
||||
{
|
||||
m_wellGroupNames.insert( address.wellGroupName() );
|
||||
}
|
||||
|
||||
if ( address.regionNumber() != -1 )
|
||||
{
|
||||
m_regionNumbers.insert( address.regionNumber() );
|
||||
}
|
||||
|
||||
if ( address.category() == RifEclipseSummaryAddress::SUMMARY_WELL_COMPLETION )
|
||||
{
|
||||
auto wellNameAndCompletion = std::make_pair( wellName, address.blockAsString() );
|
||||
m_wellCompletions.insert( wellNameAndCompletion );
|
||||
}
|
||||
else if ( address.category() == RifEclipseSummaryAddress::SUMMARY_WELL_SEGMENT )
|
||||
{
|
||||
auto wellNameAndSegment = std::make_pair( wellName, address.wellSegmentNumber() );
|
||||
m_wellSegmentNumbers.insert( wellNameAndSegment );
|
||||
}
|
||||
else if ( address.category() == RifEclipseSummaryAddress::SUMMARY_BLOCK )
|
||||
{
|
||||
auto text = address.blockAsString();
|
||||
m_blocks.insert( text );
|
||||
}
|
||||
else if ( address.category() == RifEclipseSummaryAddress::SUMMARY_AQUIFER )
|
||||
{
|
||||
m_aquifers.insert( address.aquiferNumber() );
|
||||
}
|
||||
|
||||
if ( address.category() != RifEclipseSummaryAddress::SUMMARY_INVALID )
|
||||
{
|
||||
m_categories.insert( address.category() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RifEclipseSummaryAddress.h"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
class RimSummaryCurveCollection;
|
||||
|
||||
class QString;
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaSummaryCurveAnalyzer
|
||||
{
|
||||
public:
|
||||
RiaSummaryCurveAnalyzer();
|
||||
|
||||
void appendAddresses( const std::set<RifEclipseSummaryAddress>& allAddresses );
|
||||
void appendAddresses( const std::vector<RifEclipseSummaryAddress>& allAddresses );
|
||||
|
||||
void clear();
|
||||
|
||||
std::set<std::string> quantities() const;
|
||||
std::set<std::string> quantityNamesWithHistory() const;
|
||||
std::set<std::string> quantityNamesNoHistory() const;
|
||||
|
||||
std::string quantityNameForTitle() const;
|
||||
|
||||
std::set<std::string> wellNames() const;
|
||||
std::set<std::string> wellGroupNames() const;
|
||||
std::set<int> regionNumbers() const;
|
||||
|
||||
std::set<std::string> wellCompletions( const std::string& wellName ) const;
|
||||
std::set<int> wellSegmentNumbers( const std::string& wellName ) const;
|
||||
std::set<std::string> blocks() const;
|
||||
std::set<int> aquifers() const;
|
||||
|
||||
std::set<RifEclipseSummaryAddress::SummaryVarCategory> categories() const;
|
||||
|
||||
std::vector<QString> identifierTexts( RifEclipseSummaryAddress::SummaryVarCategory category,
|
||||
const std::string& secondaryIdentifier ) const;
|
||||
|
||||
static std::vector<RifEclipseSummaryAddress>
|
||||
addressesForCategory( const std::set<RifEclipseSummaryAddress>& addresses,
|
||||
RifEclipseSummaryAddress::SummaryVarCategory category );
|
||||
|
||||
static std::string correspondingHistorySummaryCurveName( const std::string& curveName );
|
||||
|
||||
private:
|
||||
void assignCategoryToQuantities() const;
|
||||
void computeQuantityNamesWithHistory() const;
|
||||
|
||||
void analyzeSingleAddress( const RifEclipseSummaryAddress& address );
|
||||
|
||||
private:
|
||||
std::set<std::string> m_quantities;
|
||||
mutable std::set<std::string> m_quantitiesWithMatchingHistory;
|
||||
mutable std::set<std::string> m_quantitiesNoMatchingHistory;
|
||||
|
||||
std::set<std::string> m_wellNames;
|
||||
std::set<std::string> m_wellGroupNames;
|
||||
std::set<int> m_regionNumbers;
|
||||
std::set<std::pair<std::string, std::string>> m_wellCompletions;
|
||||
std::set<std::pair<std::string, int>> m_wellSegmentNumbers;
|
||||
std::set<std::string> m_blocks;
|
||||
std::set<int> m_aquifers;
|
||||
|
||||
std::set<RifEclipseSummaryAddress::SummaryVarCategory> m_categories;
|
||||
};
|
||||
@@ -0,0 +1,267 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaSummaryTools.h"
|
||||
|
||||
#include "RiaFilePathTools.h"
|
||||
#include "RifEclipseSummaryAddress.h"
|
||||
|
||||
#include "RimMainPlotCollection.h"
|
||||
#include "RimOilField.h"
|
||||
#include "RimProject.h"
|
||||
#include "RimSummaryAddress.h"
|
||||
#include "RimSummaryCalculation.h"
|
||||
#include "RimSummaryCalculationCollection.h"
|
||||
#include "RimSummaryCalculationVariable.h"
|
||||
#include "RimSummaryCaseMainCollection.h"
|
||||
#include "RimSummaryCrossPlot.h"
|
||||
#include "RimSummaryCrossPlotCollection.h"
|
||||
#include "RimSummaryCurve.h"
|
||||
#include "RimSummaryPlot.h"
|
||||
#include "RimSummaryPlotCollection.h"
|
||||
|
||||
#include "cafPdmObject.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimSummaryPlotCollection* RiaSummaryTools::summaryPlotCollection()
|
||||
{
|
||||
RimProject* project = RimProject::current();
|
||||
|
||||
return project->mainPlotCollection()->summaryPlotCollection();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimSummaryCrossPlotCollection* RiaSummaryTools::summaryCrossPlotCollection()
|
||||
{
|
||||
RimProject* project = RimProject::current();
|
||||
|
||||
return project->mainPlotCollection()->summaryCrossPlotCollection();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimSummaryCaseMainCollection* RiaSummaryTools::summaryCaseMainCollection()
|
||||
{
|
||||
RimProject* project = RimProject::current();
|
||||
RimSummaryCaseMainCollection* summaryCaseMainCollection = project->activeOilField()->summaryCaseMainCollection();
|
||||
CVF_ASSERT( summaryCaseMainCollection );
|
||||
return summaryCaseMainCollection;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Update the summary curves referencing this curve, as the curve is identified by the name
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaSummaryTools::notifyCalculatedCurveNameHasChanged( int calculationId, const QString& currentCurveName )
|
||||
{
|
||||
RimSummaryPlotCollection* summaryPlotColl = RiaSummaryTools::summaryPlotCollection();
|
||||
|
||||
for ( RimSummaryPlot* plot : summaryPlotColl->plots() )
|
||||
{
|
||||
for ( RimSummaryCurve* curve : plot->summaryCurves() )
|
||||
{
|
||||
RifEclipseSummaryAddress adr = curve->summaryAddressY();
|
||||
if ( adr.category() == RifEclipseSummaryAddress::SUMMARY_CALCULATED && adr.id() == calculationId )
|
||||
{
|
||||
RifEclipseSummaryAddress updatedAdr =
|
||||
RifEclipseSummaryAddress::calculatedAddress( currentCurveName.toStdString(), calculationId );
|
||||
curve->setSummaryAddressYAndApplyInterpolation( updatedAdr );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimSummaryPlot* RiaSummaryTools::parentSummaryPlot( caf::PdmObject* object )
|
||||
{
|
||||
if ( parentCrossPlot( object ) )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RimSummaryPlot* summaryPlot = nullptr;
|
||||
|
||||
if ( object )
|
||||
{
|
||||
object->firstAncestorOrThisOfType( summaryPlot );
|
||||
}
|
||||
|
||||
return summaryPlot;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimSummaryPlotCollection* RiaSummaryTools::parentSummaryPlotCollection( caf::PdmObject* object )
|
||||
{
|
||||
RimSummaryPlotCollection* summaryPlotColl = nullptr;
|
||||
|
||||
if ( object )
|
||||
{
|
||||
object->firstAncestorOrThisOfType( summaryPlotColl );
|
||||
}
|
||||
|
||||
return summaryPlotColl;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimSummaryCrossPlot* RiaSummaryTools::parentCrossPlot( caf::PdmObject* object )
|
||||
{
|
||||
RimSummaryCrossPlot* crossPlot = nullptr;
|
||||
|
||||
if ( object )
|
||||
{
|
||||
object->firstAncestorOrThisOfType( crossPlot );
|
||||
}
|
||||
|
||||
return crossPlot;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimSummaryCrossPlotCollection* RiaSummaryTools::parentCrossPlotCollection( caf::PdmObject* object )
|
||||
{
|
||||
RimSummaryCrossPlotCollection* crossPlotColl = nullptr;
|
||||
|
||||
if ( object )
|
||||
{
|
||||
object->firstAncestorOrThisOfType( crossPlotColl );
|
||||
}
|
||||
|
||||
return crossPlotColl;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaSummaryTools::isSummaryCrossPlot( const RimSummaryPlot* plot )
|
||||
{
|
||||
return dynamic_cast<const RimSummaryCrossPlot*>( plot );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaSummaryTools::hasAccumulatedData( const RifEclipseSummaryAddress& address )
|
||||
{
|
||||
if ( address.category() == RifEclipseSummaryAddress::SUMMARY_CALCULATED )
|
||||
{
|
||||
std::vector<RimSummaryCase*> cases;
|
||||
std::vector<RifEclipseSummaryAddress> addresses;
|
||||
|
||||
getSummaryCasesAndAddressesForCalculation( address.id(), cases, addresses );
|
||||
for ( const RifEclipseSummaryAddress& variableAddress : addresses )
|
||||
{
|
||||
if ( !variableAddress.hasAccumulatedData() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// All the variables are accumulated
|
||||
return true;
|
||||
}
|
||||
|
||||
return address.hasAccumulatedData();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaSummaryTools::getSummaryCasesAndAddressesForCalculation( int id,
|
||||
std::vector<RimSummaryCase*>& cases,
|
||||
std::vector<RifEclipseSummaryAddress>& addresses )
|
||||
{
|
||||
RimProject* proj = RimProject::current();
|
||||
|
||||
RimSummaryCalculationCollection* calculationColl = proj->calculationCollection();
|
||||
if ( !calculationColl ) return;
|
||||
|
||||
RimSummaryCalculation* calculation = calculationColl->findCalculationById( id );
|
||||
if ( !calculation ) return;
|
||||
|
||||
for ( RimSummaryCalculationVariable* v : calculation->allVariables() )
|
||||
{
|
||||
cases.push_back( v->summaryCase() );
|
||||
addresses.push_back( v->summaryAddress()->address() );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaSummaryTools::findSuitableEnsembleName( const QStringList& summaryCaseFileNames )
|
||||
{
|
||||
std::vector<QStringList> componentsForAllFilePaths;
|
||||
|
||||
for ( auto filePath : summaryCaseFileNames )
|
||||
{
|
||||
QStringList components = RiaFilePathTools::splitPathIntoComponents( filePath );
|
||||
componentsForAllFilePaths.push_back( components );
|
||||
}
|
||||
|
||||
// Find list of all folders inside a folder matching realization-*
|
||||
QRegularExpression realizationRe( "realization\\-\\d+" );
|
||||
|
||||
QStringList iterations;
|
||||
for ( const auto& fileComponents : componentsForAllFilePaths )
|
||||
{
|
||||
QString lastComponent = "";
|
||||
for ( auto it = fileComponents.rbegin(); it != fileComponents.rend(); ++it )
|
||||
{
|
||||
if ( realizationRe.match( *it ).hasMatch() )
|
||||
{
|
||||
iterations.push_back( lastComponent );
|
||||
}
|
||||
lastComponent = *it;
|
||||
}
|
||||
}
|
||||
|
||||
iterations.removeDuplicates();
|
||||
|
||||
if ( iterations.size() == 1u )
|
||||
{
|
||||
return iterations.front();
|
||||
}
|
||||
else if ( !iterations.empty() )
|
||||
{
|
||||
return QString( "Multiple iterations: %1" ).arg( iterations.join( ", " ) );
|
||||
}
|
||||
|
||||
QString root = RiaFilePathTools::commonRootOfFileNames( summaryCaseFileNames );
|
||||
|
||||
QRegularExpression trimRe( "[^a-zA-Z0-9]+$" );
|
||||
QString trimmedRoot = root.replace( trimRe, "" );
|
||||
if ( trimmedRoot.length() >= 4 )
|
||||
{
|
||||
return trimmedRoot;
|
||||
}
|
||||
|
||||
return "Ensemble";
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 <QString>
|
||||
|
||||
#include <vector>
|
||||
|
||||
class RimSummaryPlotCollection;
|
||||
class RimSummaryPlot;
|
||||
class RimSummaryCrossPlot;
|
||||
class RimSummaryCrossPlotCollection;
|
||||
class RimSummaryCaseMainCollection;
|
||||
class RimSummaryCase;
|
||||
|
||||
class RifEclipseSummaryAddress;
|
||||
|
||||
class QStringList;
|
||||
|
||||
namespace caf
|
||||
{
|
||||
class PdmObject;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaSummaryTools
|
||||
{
|
||||
public:
|
||||
static RimSummaryPlotCollection* summaryPlotCollection();
|
||||
static RimSummaryCrossPlotCollection* summaryCrossPlotCollection();
|
||||
static RimSummaryCaseMainCollection* summaryCaseMainCollection();
|
||||
|
||||
static void notifyCalculatedCurveNameHasChanged( int calculationId, const QString& currentCurveName );
|
||||
|
||||
static RimSummaryPlot* parentSummaryPlot( caf::PdmObject* object );
|
||||
static RimSummaryPlotCollection* parentSummaryPlotCollection( caf::PdmObject* object );
|
||||
|
||||
static RimSummaryCrossPlot* parentCrossPlot( caf::PdmObject* object );
|
||||
static RimSummaryCrossPlotCollection* parentCrossPlotCollection( caf::PdmObject* object );
|
||||
static bool isSummaryCrossPlot( const RimSummaryPlot* plot );
|
||||
|
||||
static bool hasAccumulatedData( const RifEclipseSummaryAddress& address );
|
||||
static void getSummaryCasesAndAddressesForCalculation( int id,
|
||||
std::vector<RimSummaryCase*>& cases,
|
||||
std::vector<RifEclipseSummaryAddress>& addresses );
|
||||
|
||||
static QString findSuitableEnsembleName( const QStringList& summaryCaseFileNames );
|
||||
};
|
||||
@@ -0,0 +1,143 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaTextFileCompare.h"
|
||||
|
||||
#include "cafUtils.h"
|
||||
|
||||
#include <QProcess>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaTextFileCompare::RiaTextFileCompare( const QString& pathToDiffTool )
|
||||
: m_pathToDiffTool( pathToDiffTool )
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaTextFileCompare::~RiaTextFileCompare()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaTextFileCompare::reset()
|
||||
{
|
||||
m_lastError = ErrorType::IC_NO_ERROR;
|
||||
m_errorMsg.clear();
|
||||
m_errorDetails.clear();
|
||||
m_diffOutput.clear();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaTextFileCompare::runComparison( const QString& baseFolder, const QString& generatedFolder )
|
||||
{
|
||||
reset();
|
||||
|
||||
QString fullFilePath = "diff";
|
||||
if ( !m_pathToDiffTool.isEmpty() )
|
||||
{
|
||||
fullFilePath = m_pathToDiffTool + "/" + fullFilePath;
|
||||
}
|
||||
|
||||
// Command line arguments used when invoking 'diff'
|
||||
// See https://docs.freebsd.org/info/diff/diff.info.diff_Options.html
|
||||
QString args = "-r -u --strip-trailing-cr";
|
||||
|
||||
QString completeCommand =
|
||||
QString( "\"%1\" %2 %3 %4" ).arg( fullFilePath ).arg( baseFolder ).arg( generatedFolder ).arg( args );
|
||||
|
||||
// Launch process and wait
|
||||
QProcess proc;
|
||||
proc.start( completeCommand );
|
||||
proc.waitForFinished( 30000 );
|
||||
|
||||
QProcess::ProcessError procError = proc.error();
|
||||
if ( procError != QProcess::UnknownError )
|
||||
{
|
||||
m_lastError = ErrorType::SEVERE_ERROR;
|
||||
m_errorMsg = "Error running 'diff' tool process";
|
||||
m_errorDetails = completeCommand;
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray stdErr = proc.readAllStandardError();
|
||||
int procExitCode = proc.exitCode();
|
||||
|
||||
if ( procExitCode == 0 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ( procExitCode == 1 )
|
||||
{
|
||||
QByteArray stdOut = proc.readAllStandardOutput();
|
||||
m_diffOutput = stdOut;
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
stdErr = stdErr.simplified();
|
||||
|
||||
// Report non-severe error
|
||||
m_lastError = ErrorType::IC_ERROR;
|
||||
m_errorMsg = "Error running 'diff' tool process";
|
||||
m_errorDetails = stdErr;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaTextFileCompare::ErrorType RiaTextFileCompare::error() const
|
||||
{
|
||||
return m_lastError;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaTextFileCompare::errorMessage() const
|
||||
{
|
||||
return m_errorMsg;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaTextFileCompare::errorDetails() const
|
||||
{
|
||||
return m_errorDetails;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaTextFileCompare::diffOutput() const
|
||||
{
|
||||
return m_diffOutput;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 <QString>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
// Execute text compare between to folders recursively using the external tool 'diff'
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaTextFileCompare
|
||||
{
|
||||
public:
|
||||
enum class ErrorType
|
||||
{
|
||||
IC_NO_ERROR, // No error occurred
|
||||
IC_ERROR, // An error occurred
|
||||
SEVERE_ERROR // Severe error occurred, it is likely that another call to compare() will also fail
|
||||
};
|
||||
|
||||
public:
|
||||
explicit RiaTextFileCompare( const QString& pathToDiffTool );
|
||||
~RiaTextFileCompare();
|
||||
|
||||
bool runComparison( const QString& baseFolder, const QString& generatedFolder );
|
||||
ErrorType error() const;
|
||||
QString errorMessage() const;
|
||||
QString errorDetails() const;
|
||||
QString diffOutput() const;
|
||||
|
||||
private:
|
||||
void reset();
|
||||
|
||||
private:
|
||||
const QString m_pathToDiffTool;
|
||||
ErrorType m_lastError;
|
||||
QString m_errorMsg;
|
||||
QString m_errorDetails;
|
||||
QString m_diffOutput;
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaTextStringTools.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaTextStringTools::compare( const QString& expected, const QString& actual )
|
||||
{
|
||||
// Suggestions for improvement
|
||||
// 1. report line number for first change
|
||||
// 2. report line numbers for all changes
|
||||
// 3. add support for compare with content of a text file on disk
|
||||
|
||||
if ( expected.compare( actual ) == 0 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaTextStringTools::trimAndRemoveDoubleSpaces( const QString& s )
|
||||
{
|
||||
int length;
|
||||
QString trimmed = s.trimmed();
|
||||
|
||||
do
|
||||
{
|
||||
length = trimmed.size();
|
||||
trimmed = trimmed.replace( " ", " " );
|
||||
} while ( trimmed.size() < length );
|
||||
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaTextStringTools::commonRoot( const QStringList& stringList )
|
||||
{
|
||||
QString root;
|
||||
if ( !stringList.isEmpty() )
|
||||
{
|
||||
root = stringList.front();
|
||||
for ( const auto& item : stringList )
|
||||
{
|
||||
if ( root.length() > item.length() )
|
||||
{
|
||||
root.truncate( item.length() );
|
||||
}
|
||||
|
||||
for ( int i = 0; i < root.length(); ++i )
|
||||
{
|
||||
if ( root[i] != item[i] )
|
||||
{
|
||||
root.truncate( i );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaTextStringTools::trimNonAlphaNumericCharacters( const QString& s )
|
||||
{
|
||||
QString trimmedString = s;
|
||||
QRegularExpression trimRe( "[^a-zA-Z0-9]+$" );
|
||||
trimmedString.replace( trimRe, "" );
|
||||
return trimmedString;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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
|
||||
|
||||
class QString;
|
||||
class QStringList;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
namespace RiaTextStringTools
|
||||
{
|
||||
bool compare( const QString& expected, const QString& actual );
|
||||
QString trimAndRemoveDoubleSpaces( const QString& s );
|
||||
QString commonRoot( const QStringList& stringList );
|
||||
QString trimNonAlphaNumericCharacters( const QString& s );
|
||||
} // namespace RiaTextStringTools
|
||||
@@ -0,0 +1,292 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 <cvfAssert.h>
|
||||
#include <cvfConfigCore.h>
|
||||
|
||||
#include "RiaTimeHistoryCurveResampler.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
// QString tostring(const QDateTime& dt)
|
||||
//{
|
||||
// int y = dt.date().year();
|
||||
// int m = dt.date().month();
|
||||
// int d = dt.date().day();
|
||||
//
|
||||
// int h = dt.time().hour();
|
||||
// int mm = dt.time().minute();
|
||||
// int s = dt.time().second();
|
||||
//
|
||||
// return QString("%1.%2.%3 %4:%5:%6").arg(y).arg(m).arg(d).arg(h).arg(mm).arg(s);
|
||||
//}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Internal constants
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
#define DOUBLE_INF std::numeric_limits<double>::infinity()
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaTimeHistoryCurveResampler::RiaTimeHistoryCurveResampler()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaTimeHistoryCurveResampler::setCurveData( const std::vector<double>& values, const std::vector<time_t>& timeSteps )
|
||||
{
|
||||
if ( values.empty() || timeSteps.empty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CVF_ASSERT( values.size() == timeSteps.size() );
|
||||
|
||||
clearData();
|
||||
m_originalValues = std::make_pair( values, timeSteps );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaTimeHistoryCurveResampler::resampleAndComputePeriodEndValues( RiaQDateTimeTools::DateTimePeriod period )
|
||||
{
|
||||
computePeriodEndValues( period );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaTimeHistoryCurveResampler::resampleAndComputeWeightedMeanValues( RiaQDateTimeTools::DateTimePeriod period )
|
||||
{
|
||||
computeWeightedMeanValues( period );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::vector<time_t>& RiaTimeHistoryCurveResampler::resampledTimeSteps() const
|
||||
{
|
||||
return m_timeSteps;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const std::vector<double>& RiaTimeHistoryCurveResampler::resampledValues() const
|
||||
{
|
||||
return m_values;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<time_t> RiaTimeHistoryCurveResampler::timeStepsFromTimeRange( RiaQDateTimeTools::DateTimePeriod period,
|
||||
time_t minTime,
|
||||
time_t maxTime )
|
||||
{
|
||||
if ( minTime > maxTime ) return std::vector<time_t>();
|
||||
|
||||
auto firstOriginalTimeStep = QDT::fromTime_t( minTime );
|
||||
auto lastOriginalTimeStep = QDT::fromTime_t( maxTime );
|
||||
|
||||
auto currTimeStep = firstResampledTimeStep( firstOriginalTimeStep, period );
|
||||
|
||||
std::vector<time_t> timeSteps;
|
||||
while ( QDT::lessThan( currTimeStep, lastOriginalTimeStep ) )
|
||||
{
|
||||
timeSteps.push_back( currTimeStep.toTime_t() );
|
||||
currTimeStep = QDT::addPeriod( currTimeStep, period );
|
||||
}
|
||||
timeSteps.push_back( currTimeStep.toTime_t() );
|
||||
|
||||
return timeSteps;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaTimeHistoryCurveResampler::computeWeightedMeanValues( RiaQDateTimeTools::DateTimePeriod period )
|
||||
{
|
||||
size_t origDataSize = m_originalValues.second.size();
|
||||
size_t oi = 0;
|
||||
const auto& origTimeSteps = m_originalValues.second;
|
||||
const auto& origValues = m_originalValues.first;
|
||||
|
||||
if ( origValues.empty() || origTimeSteps.empty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
computeResampledTimeSteps( period );
|
||||
|
||||
m_values.reserve( m_timeSteps.size() );
|
||||
for ( size_t i = 0; i < m_timeSteps.size(); i++ )
|
||||
{
|
||||
double wMean = 0.0;
|
||||
time_t periodStart = i > 0 ? m_timeSteps[i - 1]
|
||||
: QDT::subtractPeriod( QDT::fromTime_t( m_timeSteps[0] ), period ).toTime_t();
|
||||
time_t periodEnd = m_timeSteps[i];
|
||||
time_t periodLength = periodEnd - periodStart;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
time_t origTimeStep = 0;
|
||||
double origValue = 0.0;
|
||||
|
||||
if ( oi > origDataSize ) break;
|
||||
|
||||
if ( oi < origDataSize )
|
||||
{
|
||||
origTimeStep = origTimeSteps[oi];
|
||||
origValue = origValues[oi] != DOUBLE_INF ? origValues[oi] : 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
origTimeStep = periodEnd;
|
||||
origValue = 0.0;
|
||||
}
|
||||
|
||||
if ( oi == 0 )
|
||||
{
|
||||
if ( origTimeStep == m_timeSteps[i] )
|
||||
{
|
||||
wMean += origValue;
|
||||
oi++;
|
||||
break;
|
||||
}
|
||||
origValue = 0.0;
|
||||
}
|
||||
|
||||
time_t startTime = oi > 0 ? std::max( origTimeSteps[oi - 1], periodStart ) : periodStart;
|
||||
time_t endTime = std::min( origTimeStep, periodEnd );
|
||||
|
||||
wMean += origValue * ( endTime - startTime ) / periodLength;
|
||||
|
||||
if ( origTimeStep > m_timeSteps[i] ) break;
|
||||
if ( origTimeStep == m_timeSteps[i] )
|
||||
{
|
||||
oi++;
|
||||
break;
|
||||
}
|
||||
oi++;
|
||||
}
|
||||
|
||||
m_values.push_back( wMean );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaTimeHistoryCurveResampler::computePeriodEndValues( RiaQDateTimeTools::DateTimePeriod period )
|
||||
{
|
||||
size_t origDataSize = m_originalValues.second.size();
|
||||
size_t oi = 0;
|
||||
const auto& origTimeSteps = m_originalValues.second;
|
||||
const auto& origValues = m_originalValues.first;
|
||||
|
||||
if ( origValues.empty() || origTimeSteps.empty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
computeResampledTimeSteps( period );
|
||||
|
||||
m_values.reserve( m_timeSteps.size() );
|
||||
for ( size_t i = 0; i < m_timeSteps.size(); i++ )
|
||||
{
|
||||
while ( oi < origDataSize && origTimeSteps[oi] < m_timeSteps[i] )
|
||||
oi++;
|
||||
|
||||
time_t origTimeStep = oi < origDataSize ? origTimeSteps[oi] : m_timeSteps[i];
|
||||
double origValue = oi < origDataSize ? origValues[oi] : origValues[oi - 1];
|
||||
|
||||
double value;
|
||||
if ( oi > 0 && origTimeStep >= m_timeSteps[i] )
|
||||
{
|
||||
value = interpolatedValue( m_timeSteps[i], origTimeSteps[oi - 1], origValues[oi - 1], origTimeStep, origValue );
|
||||
}
|
||||
else
|
||||
{
|
||||
value = origValue;
|
||||
}
|
||||
|
||||
m_values.push_back( value );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaTimeHistoryCurveResampler::clearData()
|
||||
{
|
||||
m_timeSteps.clear();
|
||||
m_values.clear();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaTimeHistoryCurveResampler::computeResampledTimeSteps( RiaQDateTimeTools::DateTimePeriod period )
|
||||
{
|
||||
CVF_ASSERT( period != RiaQDateTimeTools::DateTimePeriod::NONE && m_originalValues.second.size() > 0 );
|
||||
|
||||
auto firstOriginalTimeStep = QDT::fromTime_t( m_originalValues.second.front() );
|
||||
auto lastOriginalTimeStep = QDT::fromTime_t( m_originalValues.second.back() );
|
||||
|
||||
clearData();
|
||||
auto currTimeStep = firstResampledTimeStep( firstOriginalTimeStep, period );
|
||||
|
||||
while ( QDT::lessThan( currTimeStep, lastOriginalTimeStep ) )
|
||||
{
|
||||
m_timeSteps.push_back( currTimeStep.toTime_t() );
|
||||
currTimeStep = QDT::addPeriod( currTimeStep, period );
|
||||
}
|
||||
|
||||
// Add last time step
|
||||
m_timeSteps.push_back( currTimeStep.toTime_t() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QDateTime RiaTimeHistoryCurveResampler::firstResampledTimeStep( const QDateTime& firstTimeStep,
|
||||
RiaQDateTimeTools::DateTimePeriod period )
|
||||
{
|
||||
QDateTime truncatedTime = QDT::truncateTime( firstTimeStep, period );
|
||||
|
||||
if ( QDT::lessThan( truncatedTime, firstTimeStep ) ) return QDT::addPeriod( truncatedTime, period );
|
||||
return truncatedTime;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaTimeHistoryCurveResampler::interpolatedValue( time_t t, time_t t1, double v1, time_t t2, double v2 )
|
||||
{
|
||||
CVF_ASSERT( t2 >= t1 );
|
||||
|
||||
if ( t <= t1 ) return v1;
|
||||
if ( t >= t2 ) return v2;
|
||||
|
||||
return ( v2 - v1 ) * (double)( t - t1 ) / (double)( t2 - t1 ) + v1;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaCurveDataTools.h"
|
||||
#include "RiaQDateTimeTools.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
using QDT = RiaQDateTimeTools;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RiaTimeHistoryCurveResampler
|
||||
{
|
||||
public:
|
||||
RiaTimeHistoryCurveResampler();
|
||||
|
||||
void setCurveData( const std::vector<double>& values, const std::vector<time_t>& timeSteps );
|
||||
|
||||
void resampleAndComputePeriodEndValues( RiaQDateTimeTools::DateTimePeriod period );
|
||||
void resampleAndComputeWeightedMeanValues( RiaQDateTimeTools::DateTimePeriod period );
|
||||
|
||||
const std::vector<time_t>& resampledTimeSteps() const;
|
||||
const std::vector<double>& resampledValues() const;
|
||||
|
||||
static std::vector<time_t>
|
||||
timeStepsFromTimeRange( RiaQDateTimeTools::DateTimePeriod period, time_t minTime, time_t maxTime );
|
||||
|
||||
private:
|
||||
void computeWeightedMeanValues( RiaQDateTimeTools::DateTimePeriod period );
|
||||
void computePeriodEndValues( RiaQDateTimeTools::DateTimePeriod period );
|
||||
|
||||
void clearData();
|
||||
void computeResampledTimeSteps( RiaQDateTimeTools::DateTimePeriod period );
|
||||
static QDateTime firstResampledTimeStep( const QDateTime& firstTimestep, RiaQDateTimeTools::DateTimePeriod period );
|
||||
inline double interpolatedValue( time_t t, time_t t1, double v1, time_t t2, double v2 );
|
||||
|
||||
private:
|
||||
std::pair<std::vector<double>, std::vector<time_t>> m_originalValues;
|
||||
|
||||
std::vector<time_t> m_timeSteps;
|
||||
std::vector<double> m_values;
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020 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 "RiaTimeTTools.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaTimeTTools::toDouble( time_t time )
|
||||
{
|
||||
double milliSecSinceEpoch = time * 1000; // This is kind of hack, as the c++ standard does not state what
|
||||
// time_t is. "Almost always" secs since epoch according to
|
||||
// cppreference.com
|
||||
return milliSecSinceEpoch;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
time_t RiaTimeTTools::fromDouble( double time )
|
||||
{
|
||||
time_t timet = static_cast<time_t>( time / 1000 );
|
||||
return timet;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
time_t RiaTimeTTools::fromQDateTime( const QDateTime& dateTime )
|
||||
{
|
||||
time_t timet = dateTime.toSecsSinceEpoch();
|
||||
return timet;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020 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 <ctime>
|
||||
|
||||
class QDateTime;
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaTimeTTools
|
||||
{
|
||||
public:
|
||||
static double toDouble( time_t time );
|
||||
static time_t fromDouble( double time );
|
||||
static time_t fromQDateTime( const QDateTime& dateTime );
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020- 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 "RiaValidRegExpValidator.h"
|
||||
|
||||
#include "cafAssert.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaValidRegExpValidator::RiaValidRegExpValidator( const QString& defaultPattern )
|
||||
: QValidator( nullptr )
|
||||
, m_defaultPattern( defaultPattern )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaValidRegExpValidator::isValidCharacter( const QChar& character )
|
||||
{
|
||||
return character.isLetterOrNumber() || character == '-' || character == '_' || character == '.' || character == '[';
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QValidator::State RiaValidRegExpValidator::validate( QString& inputString, int& position ) const
|
||||
{
|
||||
QRegExp inputRe( inputString, Qt::CaseInsensitive, QRegExp::Wildcard );
|
||||
if ( inputRe.isValid() ) // A valid wildcard pattern is always acceptable
|
||||
{
|
||||
return QValidator::Acceptable;
|
||||
}
|
||||
|
||||
if ( position >= inputString.length() )
|
||||
{
|
||||
// This should probably never happen, but the Qt-documentation isn't clear on it.
|
||||
CAF_ASSERT( false );
|
||||
return QValidator::Invalid;
|
||||
}
|
||||
|
||||
// Try to decide whether it can be fixed by typing further characters or not.
|
||||
if ( !isValidCharacter( inputString[position] ) )
|
||||
{
|
||||
// Contains a invalid character: the whole regexp is invalid.
|
||||
return QValidator::Invalid;
|
||||
}
|
||||
|
||||
return QValidator::Intermediate;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaValidRegExpValidator::fixup( QString& inputString ) const
|
||||
{
|
||||
inputString = m_defaultPattern;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020- 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 <QRegExp>
|
||||
#include <QString>
|
||||
#include <QValidator>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Validates a wild card pattern (simpler for user)
|
||||
// Has to use the older QRegExp because QRegularExpression didn't add any
|
||||
// support for wild cards until Qt 5.12.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
class RiaValidRegExpValidator : public QValidator
|
||||
{
|
||||
public:
|
||||
RiaValidRegExpValidator( const QString& defaultPattern );
|
||||
static bool isValidCharacter( const QChar& character );
|
||||
State validate( QString& inputString, int& position ) const override;
|
||||
void fixup( QString& inputString ) const override;
|
||||
|
||||
private:
|
||||
QString m_defaultPattern;
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaWeightedGeometricMeanCalculator.h"
|
||||
|
||||
#include "cvfAssert.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaWeightedGeometricMeanCalculator::RiaWeightedGeometricMeanCalculator()
|
||||
: m_aggregatedWeightedValue( 0.0 )
|
||||
, m_aggregatedWeight( 0.0 )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaWeightedGeometricMeanCalculator::addValueAndWeight( double value, double weight )
|
||||
{
|
||||
CVF_ASSERT( weight >= 0.0 );
|
||||
|
||||
// This can be a very big number, consider other algorithms if that becomes a problem
|
||||
m_aggregatedWeightedValue += ( std::log( value ) * weight );
|
||||
m_aggregatedWeight += weight;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaWeightedGeometricMeanCalculator::weightedMean() const
|
||||
{
|
||||
if ( m_aggregatedWeight > 1e-7 )
|
||||
{
|
||||
return std::exp( m_aggregatedWeightedValue / m_aggregatedWeight );
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaWeightedGeometricMeanCalculator::aggregatedWeight() const
|
||||
{
|
||||
return m_aggregatedWeight;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaWeightedGeometricMeanCalculator::validAggregatedWeight() const
|
||||
{
|
||||
return m_aggregatedWeight > 1.0e-12;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
class RiaWeightedGeometricMeanCalculator
|
||||
{
|
||||
public:
|
||||
RiaWeightedGeometricMeanCalculator();
|
||||
|
||||
void addValueAndWeight( double value, double weight );
|
||||
|
||||
double weightedMean() const;
|
||||
double aggregatedWeight() const;
|
||||
bool validAggregatedWeight() const;
|
||||
|
||||
private:
|
||||
double m_aggregatedWeightedValue;
|
||||
double m_aggregatedWeight;
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaWeightedHarmonicMeanCalculator.h"
|
||||
|
||||
#include "cvfAssert.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaWeightedHarmonicMeanCalculator::RiaWeightedHarmonicMeanCalculator()
|
||||
: m_aggregatedWeightedValue( 0.0 )
|
||||
, m_aggregatedWeight( 0.0 )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaWeightedHarmonicMeanCalculator::addValueAndWeight( double value, double weight )
|
||||
{
|
||||
CVF_ASSERT( weight > 1.0e-12 && std::abs( value ) > 1.0e-12 );
|
||||
|
||||
m_aggregatedWeightedValue += weight / value;
|
||||
m_aggregatedWeight += weight;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaWeightedHarmonicMeanCalculator::weightedMean() const
|
||||
{
|
||||
if ( validAggregatedWeight() )
|
||||
{
|
||||
return m_aggregatedWeight / m_aggregatedWeightedValue;
|
||||
}
|
||||
CVF_ASSERT( false );
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RiaWeightedHarmonicMeanCalculator::aggregatedWeight() const
|
||||
{
|
||||
return m_aggregatedWeight;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaWeightedHarmonicMeanCalculator::validAggregatedWeight() const
|
||||
{
|
||||
return m_aggregatedWeight > 1.0e-12;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
class RiaWeightedHarmonicMeanCalculator
|
||||
{
|
||||
public:
|
||||
RiaWeightedHarmonicMeanCalculator();
|
||||
|
||||
void addValueAndWeight( double value, double weight );
|
||||
|
||||
double weightedMean() const;
|
||||
double aggregatedWeight() const;
|
||||
bool validAggregatedWeight() const;
|
||||
|
||||
private:
|
||||
double m_aggregatedWeightedValue;
|
||||
double m_aggregatedWeight;
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
class RiaWeightedMeanCalculator
|
||||
{
|
||||
public:
|
||||
RiaWeightedMeanCalculator();
|
||||
|
||||
void addValueAndWeight( T value, double weight );
|
||||
|
||||
T weightedMean() const;
|
||||
double aggregatedWeight() const;
|
||||
bool validAggregatedWeight() const;
|
||||
|
||||
private:
|
||||
T m_aggregatedValue;
|
||||
double m_aggregatedWeight;
|
||||
};
|
||||
|
||||
#include "RiaWeightedMeanCalculator.inl"
|
||||
@@ -0,0 +1,74 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "cvfAssert.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
RiaWeightedMeanCalculator<T>::RiaWeightedMeanCalculator()
|
||||
: m_aggregatedValue( T{} )
|
||||
, m_aggregatedWeight( 0.0 )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void RiaWeightedMeanCalculator<T>::addValueAndWeight( T value, double weight )
|
||||
{
|
||||
CVF_ASSERT( weight >= 0.0 );
|
||||
|
||||
m_aggregatedValue = m_aggregatedValue + value * weight;
|
||||
m_aggregatedWeight += weight;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
T RiaWeightedMeanCalculator<T>::weightedMean() const
|
||||
{
|
||||
bool validWeights = validAggregatedWeight();
|
||||
CVF_TIGHT_ASSERT( validWeights );
|
||||
if ( validWeights )
|
||||
{
|
||||
return m_aggregatedValue * ( 1.0 / m_aggregatedWeight );
|
||||
}
|
||||
return T{};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
double RiaWeightedMeanCalculator<T>::aggregatedWeight() const
|
||||
{
|
||||
return m_aggregatedWeight;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
bool RiaWeightedMeanCalculator<T>::validAggregatedWeight() const
|
||||
{
|
||||
return m_aggregatedWeight > 1.0e-12;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020- Equinor AS
|
||||
//
|
||||
// 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 <QString>
|
||||
|
||||
#include <vector>
|
||||
|
||||
class RigWellPath;
|
||||
|
||||
template <typename FloatType>
|
||||
class RiaWellLogUnitTools
|
||||
{
|
||||
public:
|
||||
static const FloatType gravityAcceleration();
|
||||
static const FloatType unitWeightOfWater();
|
||||
static bool stringsMatch( const QString& lhs, const QString& rhs );
|
||||
|
||||
static QString noUnitString();
|
||||
static QString sg_emwUnitString();
|
||||
static QString barUnitString();
|
||||
static QString barX100UnitString();
|
||||
static QString MPaUnitString();
|
||||
static QString gPerCm3UnitString();
|
||||
static QString kgPerM3UnitString();
|
||||
static QString pascalUnitString();
|
||||
static QString pascalUnitStringShort();
|
||||
|
||||
public:
|
||||
static std::vector<FloatType> convertDepths( const std::vector<FloatType>& depthsIn,
|
||||
RiaDefines::DepthUnitType unitsIn,
|
||||
RiaDefines::DepthUnitType unitsOut );
|
||||
|
||||
static std::vector<std::pair<FloatType, FloatType>>
|
||||
convertDepths( const std::vector<std::pair<FloatType, FloatType>>& depthsIn,
|
||||
RiaDefines::DepthUnitType unitsIn,
|
||||
RiaDefines::DepthUnitType unitsOut );
|
||||
|
||||
static FloatType
|
||||
convertDepth( FloatType depthIn, RiaDefines::DepthUnitType unitsIn, RiaDefines::DepthUnitType unitsOut );
|
||||
|
||||
static bool convertValues( const std::vector<FloatType>& tvdRKBs,
|
||||
const std::vector<FloatType>& valuesIn,
|
||||
std::vector<FloatType>* valuesOut,
|
||||
const QString& unitsIn,
|
||||
const QString& unitsOut );
|
||||
static bool convertValues( std::vector<std::pair<FloatType, FloatType>>* measuredDepthsAndValues,
|
||||
const QString& unitsIn,
|
||||
const QString& unitsOut,
|
||||
const RigWellPath* wellPath );
|
||||
|
||||
static std::vector<FloatType> tvdRKBs( const std::vector<FloatType>& measuredDepths, const RigWellPath* wellPath );
|
||||
|
||||
// Supported conversions
|
||||
static std::vector<FloatType> convertGpcm3ToBar( const std::vector<FloatType>& tvdRKBs,
|
||||
const std::vector<FloatType>& valuesInGpcm3 );
|
||||
static std::vector<FloatType> convertBarToGpcm3( const std::vector<FloatType>& tvdRKBs,
|
||||
const std::vector<FloatType>& valuesInBar );
|
||||
|
||||
static std::vector<FloatType> convertNormalizedByPPToBar( const std::vector<FloatType>& tvdRKBs,
|
||||
const std::vector<FloatType>& valuesInBar );
|
||||
static std::vector<FloatType> convertBarToNormalizedByPP( const std::vector<FloatType>& tvdRKBs,
|
||||
const std::vector<FloatType>& valuesInBar );
|
||||
static std::vector<FloatType> multiply( const std::vector<FloatType>& values, FloatType factor );
|
||||
static FloatType pascalPerBar();
|
||||
static FloatType MPaPerBar();
|
||||
static FloatType hydrostaticPorePressureBar( FloatType tvdRKB );
|
||||
};
|
||||
|
||||
#include "RiaWellLogUnitTools.inl"
|
||||
@@ -0,0 +1,476 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2020- Equinor AS
|
||||
//
|
||||
// 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 "RiaEclipseUnitTools.h"
|
||||
#include "RigWellPath.h"
|
||||
|
||||
#include "cafAssert.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
const FloatType RiaWellLogUnitTools<FloatType>::gravityAcceleration()
|
||||
{
|
||||
return (FloatType)9.81;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
const FloatType RiaWellLogUnitTools<FloatType>::unitWeightOfWater()
|
||||
{
|
||||
return RiaWellLogUnitTools<FloatType>::gravityAcceleration() * 1000.0; // N / m^3
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
bool RiaWellLogUnitTools<FloatType>::stringsMatch( const QString& lhs, const QString& rhs )
|
||||
{
|
||||
return QString::compare( lhs, rhs, Qt::CaseInsensitive ) == 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
QString RiaWellLogUnitTools<FloatType>::noUnitString()
|
||||
{
|
||||
return "NO_UNIT";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
QString RiaWellLogUnitTools<FloatType>::sg_emwUnitString()
|
||||
{
|
||||
return "sg_EMW";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
QString RiaWellLogUnitTools<FloatType>::barUnitString()
|
||||
{
|
||||
return "Bar";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
QString RiaWellLogUnitTools<FloatType>::barX100UnitString()
|
||||
{
|
||||
return "Bar x100";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
QString RiaWellLogUnitTools<FloatType>::MPaUnitString()
|
||||
{
|
||||
return "MPa";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
QString RiaWellLogUnitTools<FloatType>::gPerCm3UnitString()
|
||||
{
|
||||
return "g/cm3";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
QString RiaWellLogUnitTools<FloatType>::kgPerM3UnitString()
|
||||
{
|
||||
return "kg/m3";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
QString RiaWellLogUnitTools<FloatType>::pascalUnitString()
|
||||
{
|
||||
return "pascal";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
QString RiaWellLogUnitTools<FloatType>::pascalUnitStringShort()
|
||||
{
|
||||
return "pa";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
std::vector<FloatType> RiaWellLogUnitTools<FloatType>::convertDepths( const std::vector<FloatType>& depthsIn,
|
||||
RiaDefines::DepthUnitType unitsIn,
|
||||
RiaDefines::DepthUnitType unitsOut )
|
||||
{
|
||||
if ( unitsOut == RiaDefines::DepthUnitType::UNIT_METER && unitsIn == RiaDefines::DepthUnitType::UNIT_FEET )
|
||||
{
|
||||
return multiply( depthsIn, RiaEclipseUnitTools::meterPerFeet() );
|
||||
}
|
||||
else if ( unitsOut == RiaDefines::DepthUnitType::UNIT_FEET && unitsIn == RiaDefines::DepthUnitType::UNIT_METER )
|
||||
{
|
||||
return multiply( depthsIn, RiaEclipseUnitTools::feetPerMeter() );
|
||||
}
|
||||
return depthsIn;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
FloatType RiaWellLogUnitTools<FloatType>::convertDepth( FloatType depthIn,
|
||||
RiaDefines::DepthUnitType unitsIn,
|
||||
RiaDefines::DepthUnitType unitsOut )
|
||||
{
|
||||
FloatType factor = 1.0;
|
||||
if ( unitsOut == RiaDefines::DepthUnitType::UNIT_METER && unitsIn == RiaDefines::DepthUnitType::UNIT_FEET )
|
||||
{
|
||||
factor = RiaEclipseUnitTools::meterPerFeet();
|
||||
}
|
||||
else if ( unitsOut == RiaDefines::DepthUnitType::UNIT_FEET && unitsIn == RiaDefines::DepthUnitType::UNIT_METER )
|
||||
{
|
||||
factor = RiaEclipseUnitTools::feetPerMeter();
|
||||
}
|
||||
return depthIn * factor;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
std::vector<std::pair<FloatType, FloatType>>
|
||||
RiaWellLogUnitTools<FloatType>::convertDepths( const std::vector<std::pair<FloatType, FloatType>>& depthsIn,
|
||||
RiaDefines::DepthUnitType unitsIn,
|
||||
RiaDefines::DepthUnitType unitsOut )
|
||||
{
|
||||
std::vector<std::pair<FloatType, FloatType>> convertedDepths( depthsIn.size() );
|
||||
double factor = 1.0;
|
||||
if ( unitsOut == RiaDefines::DepthUnitType::UNIT_METER && unitsIn == RiaDefines::DepthUnitType::UNIT_FEET )
|
||||
{
|
||||
factor = RiaEclipseUnitTools::meterPerFeet();
|
||||
}
|
||||
else if ( unitsOut == RiaDefines::DepthUnitType::UNIT_FEET && unitsIn == RiaDefines::DepthUnitType::UNIT_METER )
|
||||
{
|
||||
factor = RiaEclipseUnitTools::feetPerMeter();
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for ( auto& p : depthsIn )
|
||||
{
|
||||
convertedDepths[i++] = std::make_pair( factor * p.first, factor * p.second );
|
||||
}
|
||||
|
||||
return convertedDepths;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
bool RiaWellLogUnitTools<FloatType>::convertValues( const std::vector<FloatType>& tvdRKBs,
|
||||
const std::vector<FloatType>& valuesIn,
|
||||
std::vector<FloatType>* valuesOut,
|
||||
const QString& unitsIn,
|
||||
const QString& unitsOut )
|
||||
{
|
||||
CAF_ASSERT( valuesOut );
|
||||
|
||||
if ( stringsMatch( unitsIn, unitsOut ) )
|
||||
{
|
||||
*valuesOut = valuesIn;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( stringsMatch( unitsIn, gPerCm3UnitString() ) && stringsMatch( unitsOut, barUnitString() ) )
|
||||
{
|
||||
*valuesOut = convertGpcm3ToBar( tvdRKBs, valuesIn );
|
||||
return true;
|
||||
}
|
||||
else if ( stringsMatch( unitsOut, barUnitString() ) && stringsMatch( unitsOut, gPerCm3UnitString() ) )
|
||||
{
|
||||
*valuesOut = convertBarToGpcm3( tvdRKBs, valuesIn );
|
||||
return true;
|
||||
}
|
||||
else if ( ( stringsMatch( unitsIn, noUnitString() ) || stringsMatch( unitsIn, sg_emwUnitString() ) ) &&
|
||||
stringsMatch( unitsOut, gPerCm3UnitString() ) )
|
||||
{
|
||||
*valuesOut = convertNormalizedByPPToBar( tvdRKBs, valuesIn );
|
||||
*valuesOut = convertBarToGpcm3( tvdRKBs, *valuesOut );
|
||||
return true;
|
||||
}
|
||||
else if ( stringsMatch( unitsIn, gPerCm3UnitString() ) &&
|
||||
( stringsMatch( unitsOut, noUnitString() ) || stringsMatch( unitsOut, sg_emwUnitString() ) ) )
|
||||
{
|
||||
*valuesOut = convertGpcm3ToBar( tvdRKBs, valuesIn );
|
||||
*valuesOut = convertBarToNormalizedByPP( tvdRKBs, *valuesOut );
|
||||
return true;
|
||||
}
|
||||
else if ( stringsMatch( unitsIn, MPaUnitString() ) && stringsMatch( unitsOut, barUnitString() ) )
|
||||
{
|
||||
*valuesOut = multiply( valuesIn, 1.0 / MPaPerBar() );
|
||||
return true;
|
||||
}
|
||||
else if ( stringsMatch( unitsIn, barX100UnitString() ) && stringsMatch( unitsOut, MPaUnitString() ) )
|
||||
{
|
||||
*valuesOut = multiply( valuesIn, (FloatType)100.0 );
|
||||
*valuesOut = multiply( *valuesOut, MPaPerBar() );
|
||||
return true;
|
||||
}
|
||||
else if ( stringsMatch( unitsIn, barX100UnitString() ) && stringsMatch( unitsOut, barUnitString() ) )
|
||||
{
|
||||
*valuesOut = multiply( valuesIn, (FloatType)100 );
|
||||
return true;
|
||||
}
|
||||
else if ( stringsMatch( unitsIn, barUnitString() ) && stringsMatch( unitsOut, MPaUnitString() ) )
|
||||
{
|
||||
*valuesOut = multiply( valuesIn, MPaPerBar() );
|
||||
return true;
|
||||
}
|
||||
else if ( stringsMatch( unitsIn, barUnitString() ) && stringsMatch( unitsOut, barX100UnitString() ) )
|
||||
{
|
||||
*valuesOut = multiply( valuesIn, (FloatType)0.01 );
|
||||
return true;
|
||||
}
|
||||
else if ( ( stringsMatch( unitsIn, noUnitString() ) || stringsMatch( unitsIn, sg_emwUnitString() ) ) &&
|
||||
stringsMatch( unitsOut, barUnitString() ) )
|
||||
{
|
||||
*valuesOut = convertNormalizedByPPToBar( tvdRKBs, valuesIn );
|
||||
return true;
|
||||
}
|
||||
else if ( stringsMatch( unitsIn, barUnitString() ) &&
|
||||
( stringsMatch( unitsOut, noUnitString() ) || stringsMatch( unitsOut, sg_emwUnitString() ) ) )
|
||||
{
|
||||
*valuesOut = convertBarToNormalizedByPP( tvdRKBs, valuesIn );
|
||||
return true;
|
||||
}
|
||||
else if ( ( stringsMatch( unitsIn, pascalUnitString() ) ||
|
||||
stringsMatch( unitsIn, pascalUnitString() ) && stringsMatch( unitsOut, barUnitString() ) ) )
|
||||
{
|
||||
*valuesOut = multiply( valuesIn, 1.0 / pascalPerBar() );
|
||||
return true;
|
||||
}
|
||||
else if ( stringsMatch( unitsIn, barUnitString() ) &&
|
||||
( stringsMatch( unitsIn, pascalUnitString() ) || stringsMatch( unitsIn, pascalUnitString() ) ) )
|
||||
{
|
||||
*valuesOut = multiply( valuesIn, pascalPerBar() );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
bool RiaWellLogUnitTools<FloatType>::convertValues( std::vector<std::pair<FloatType, FloatType>>* measuredDepthsAndValues,
|
||||
const QString& unitsIn,
|
||||
const QString& unitsOut,
|
||||
const RigWellPath* wellPath )
|
||||
{
|
||||
CAF_ASSERT( measuredDepthsAndValues );
|
||||
if ( unitsIn == unitsOut ) return true;
|
||||
|
||||
std::vector<FloatType> tvdRKBs( measuredDepthsAndValues->size(), 0.0 );
|
||||
std::vector<FloatType> values( measuredDepthsAndValues->size(), 0.0 );
|
||||
for ( size_t i = 0; i < measuredDepthsAndValues->size(); ++i )
|
||||
{
|
||||
auto depthValuePair = ( *measuredDepthsAndValues )[i];
|
||||
cvf::Vec3d point = wellPath->interpolatedPointAlongWellPath( depthValuePair.first );
|
||||
|
||||
tvdRKBs[i] = -point.z() + wellPath->rkbDiff();
|
||||
values[i] = depthValuePair.second;
|
||||
}
|
||||
std::vector<FloatType> valuesOut;
|
||||
if ( convertValues( tvdRKBs, values, &valuesOut, unitsIn, unitsOut ) )
|
||||
{
|
||||
CAF_ASSERT( measuredDepthsAndValues->size() == valuesOut.size() );
|
||||
for ( size_t i = 0; i < measuredDepthsAndValues->size(); ++i )
|
||||
{
|
||||
( *measuredDepthsAndValues )[i].second = valuesOut[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
std::vector<FloatType>
|
||||
RiaWellLogUnitTools<FloatType>::tvdRKBs( const std::vector<FloatType>& measuredDepths, const RigWellPath* wellPath )
|
||||
{
|
||||
std::vector<double> tvdRKBs( measuredDepths.size(), 0.0 );
|
||||
for ( size_t i = 0; i < measuredDepths.size(); ++i )
|
||||
{
|
||||
cvf::Vec3d point = wellPath->interpolatedPointAlongWellPath( measuredDepths[i] );
|
||||
tvdRKBs[i] = -point.z() + wellPath->rkbDiff();
|
||||
}
|
||||
return std::vector<FloatType>( tvdRKBs.begin(), tvdRKBs.end() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
std::vector<FloatType> RiaWellLogUnitTools<FloatType>::convertGpcm3ToBar( const std::vector<FloatType>& tvdRKBs,
|
||||
const std::vector<FloatType>& valuesInGpcm3 )
|
||||
{
|
||||
CAF_ASSERT( tvdRKBs.size() == valuesInGpcm3.size() );
|
||||
|
||||
std::vector<FloatType> valuesInBar( valuesInGpcm3.size(), 0.0 );
|
||||
for ( size_t i = 0; i < tvdRKBs.size(); ++i )
|
||||
{
|
||||
// We need SI as input (kg / m^3), so multiply by 1000:
|
||||
FloatType mudWeightsSI = valuesInGpcm3[i] * 1000;
|
||||
|
||||
// To get specific mudWeight (N / m^3):
|
||||
FloatType specificMudWeight = mudWeightsSI * gravityAcceleration();
|
||||
|
||||
// Pore pressure in pascal
|
||||
FloatType valuePascal = specificMudWeight * tvdRKBs[i];
|
||||
|
||||
// Pore pressure in bar
|
||||
valuesInBar[i] = 1.0 / pascalPerBar() * valuePascal;
|
||||
}
|
||||
return valuesInBar;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
std::vector<FloatType> RiaWellLogUnitTools<FloatType>::convertBarToGpcm3( const std::vector<FloatType>& tvdRKBs,
|
||||
const std::vector<FloatType>& valuesInBar )
|
||||
{
|
||||
CAF_ASSERT( tvdRKBs.size() == valuesInBar.size() );
|
||||
|
||||
std::vector<FloatType> valuesInGpcm3( valuesInBar.size(), 0.0 );
|
||||
for ( size_t i = 0; i < tvdRKBs.size(); ++i )
|
||||
{
|
||||
// Pore pressure in pascal (N / m^2)
|
||||
FloatType valuePascal = pascalPerBar() * valuesInBar[i];
|
||||
|
||||
// N / m^3:
|
||||
FloatType specificMudWeight = valuePascal / tvdRKBs[i];
|
||||
|
||||
// Mud weight in SI (kg / m^3):
|
||||
FloatType mudWeightsSI = specificMudWeight / gravityAcceleration();
|
||||
|
||||
// Mud weights g/cm^3:
|
||||
valuesInGpcm3[i] = mudWeightsSI / 1000;
|
||||
}
|
||||
return valuesInGpcm3;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
std::vector<FloatType>
|
||||
RiaWellLogUnitTools<FloatType>::convertNormalizedByPPToBar( const std::vector<FloatType>& tvdRKBs,
|
||||
const std::vector<FloatType>& normalizedValues )
|
||||
{
|
||||
CAF_ASSERT( tvdRKBs.size() == normalizedValues.size() );
|
||||
|
||||
std::vector<FloatType> valuesInBar( tvdRKBs.size(), 0.0 );
|
||||
for ( size_t i = 0; i < tvdRKBs.size(); ++i )
|
||||
{
|
||||
valuesInBar[i] = normalizedValues[i] * hydrostaticPorePressureBar( tvdRKBs[i] );
|
||||
}
|
||||
return valuesInBar;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
std::vector<FloatType>
|
||||
RiaWellLogUnitTools<FloatType>::convertBarToNormalizedByPP( const std::vector<FloatType>& tvdRKBs,
|
||||
const std::vector<FloatType>& valuesInBar )
|
||||
{
|
||||
CAF_ASSERT( tvdRKBs.size() == valuesInBar.size() );
|
||||
|
||||
std::vector<FloatType> normalizedValues( tvdRKBs.size(), 0.0 );
|
||||
for ( size_t i = 0; i < tvdRKBs.size(); ++i )
|
||||
{
|
||||
normalizedValues[i] = valuesInBar[i] / hydrostaticPorePressureBar( tvdRKBs[i] );
|
||||
}
|
||||
return normalizedValues;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
std::vector<FloatType> RiaWellLogUnitTools<FloatType>::multiply( const std::vector<FloatType>& valuesIn, FloatType factor )
|
||||
{
|
||||
std::vector<FloatType> valuesOut( valuesIn.size(), std::numeric_limits<FloatType>::infinity() );
|
||||
for ( size_t i = 0; i < valuesIn.size(); ++i )
|
||||
{
|
||||
valuesOut[i] = valuesIn[i] * factor;
|
||||
}
|
||||
return valuesOut;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
FloatType RiaWellLogUnitTools<FloatType>::pascalPerBar()
|
||||
{
|
||||
return 1.0e5;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
FloatType RiaWellLogUnitTools<FloatType>::MPaPerBar()
|
||||
{
|
||||
return (FloatType)1.0e-1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename FloatType>
|
||||
FloatType RiaWellLogUnitTools<FloatType>::hydrostaticPorePressureBar( FloatType depth )
|
||||
{
|
||||
return (FloatType)1.0 / pascalPerBar() * depth * unitWeightOfWater();
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "RiaWellNameComparer.h"
|
||||
|
||||
#include "RimProject.h"
|
||||
#include "RimWellPath.h"
|
||||
|
||||
#include <regex>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//==================================================================================================
|
||||
QString RiaWellNameComparer::tryFindMatchingSimWellName( QString searchName )
|
||||
{
|
||||
RimProject* proj = RimProject::current();
|
||||
const std::vector<QString>& simWellNames = proj->simulationWellNames();
|
||||
|
||||
if ( searchName.isEmpty() || simWellNames.empty() ) return QString();
|
||||
|
||||
searchName = removeWellNamePrefix( searchName );
|
||||
return tryMatchNameInList( searchName, simWellNames );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaWellNameComparer::tryFindMatchingWellPath( QString wellName )
|
||||
{
|
||||
RimProject* proj = RimProject::current();
|
||||
const std::vector<RimWellPath*>& wellPaths = proj->allWellPaths();
|
||||
|
||||
if ( wellName.isEmpty() || wellPaths.empty() ) return QString();
|
||||
|
||||
std::vector<QString> wellPathNames;
|
||||
for ( const RimWellPath* wellPath : wellPaths )
|
||||
{
|
||||
wellPathNames.push_back( wellPath->name() );
|
||||
}
|
||||
|
||||
wellName = removeWellNamePrefix( wellName );
|
||||
return tryMatchNameInList( wellName, wellPathNames );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaWellNameComparer::tryMatchNameInList( QString searchName, const std::vector<QString>& nameList )
|
||||
{
|
||||
// Try exact name match
|
||||
QString matchedName = tryMatchName( searchName, nameList );
|
||||
if ( !matchedName.isEmpty() )
|
||||
{
|
||||
return matchedName;
|
||||
}
|
||||
|
||||
// Try matching ignoring spaces, dashes and underscores
|
||||
return tryMatchName( searchName, nameList, []( const QString& str ) {
|
||||
QString s = str;
|
||||
s = removeWellNamePrefix( s );
|
||||
return s.remove( ' ' ).remove( '-' ).remove( '_' );
|
||||
} );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaWellNameComparer::tryMatchName( QString searchName,
|
||||
const std::vector<QString>& simWellNames,
|
||||
std::function<QString( QString )> stringFormatter )
|
||||
{
|
||||
if ( searchName.isEmpty() ) return QString();
|
||||
|
||||
if ( stringFormatter != nullptr )
|
||||
{
|
||||
searchName = stringFormatter( searchName );
|
||||
}
|
||||
|
||||
for ( const auto& simWellName : simWellNames )
|
||||
{
|
||||
QString simWn = simWellName;
|
||||
if ( stringFormatter != nullptr )
|
||||
{
|
||||
simWn = stringFormatter( simWn );
|
||||
}
|
||||
if ( QString::compare( simWn, searchName, Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
return simWellName;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaWellNameComparer::removeWellNamePrefix( const QString& name )
|
||||
{
|
||||
// Try to remove prefix on the format 'xx xxxx/xx-'
|
||||
std::regex pattern( "^.*\\d*[/]\\d*[-_]" );
|
||||
|
||||
return QString::fromStdString( std::regex_replace( name.toStdString(), pattern, "" ) );
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 <QString>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class RiaWellNameComparer
|
||||
{
|
||||
public:
|
||||
static QString tryFindMatchingSimWellName( QString searchName );
|
||||
static QString tryFindMatchingWellPath( QString wellName );
|
||||
|
||||
static QString tryMatchNameInList( QString searchName, const std::vector<QString>& nameList );
|
||||
|
||||
private:
|
||||
static QString tryMatchName( QString searchName,
|
||||
const std::vector<QString>& nameList,
|
||||
std::function<QString( QString )> stringFormatter = nullptr );
|
||||
|
||||
static QString removeWellNamePrefix( const QString& name );
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
set (SOURCE_GROUP_HEADER_FILES
|
||||
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaPolyArcLineSampler.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWellPlanCalculator.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaSCurveCalculator.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaArcCurveCalculator.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaJCurveCalculator.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaLineArcWellPathCalculator.h
|
||||
)
|
||||
|
||||
set (SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaPolyArcLineSampler.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWellPlanCalculator.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaSCurveCalculator.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaArcCurveCalculator.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaJCurveCalculator.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaLineArcWellPathCalculator.cpp
|
||||
)
|
||||
|
||||
list(APPEND CODE_HEADER_FILES
|
||||
${SOURCE_GROUP_HEADER_FILES}
|
||||
)
|
||||
|
||||
list(APPEND CODE_SOURCE_FILES
|
||||
${SOURCE_GROUP_SOURCE_FILES}
|
||||
)
|
||||
|
||||
set (QT_MOC_HEADERS
|
||||
${QT_MOC_HEADERS}
|
||||
)
|
||||
|
||||
|
||||
source_group( "Application\\Tools\\WellPathTools" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake )
|
||||
@@ -0,0 +1,102 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaArcCurveCalculator.h"
|
||||
|
||||
#include "RiaOffshoreSphericalCoords.h"
|
||||
#include "cvfGeometryTools.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// + p1
|
||||
/// t1 **
|
||||
/// * + C
|
||||
/// *
|
||||
/// + p2
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaArcCurveCalculator::RiaArcCurveCalculator( cvf::Vec3d p1, cvf::Vec3d t1, cvf::Vec3d p2 )
|
||||
: m_radius( std::numeric_limits<double>::infinity() )
|
||||
, m_arcCS( cvf::Mat4d::ZERO )
|
||||
, m_endAzi( 0 )
|
||||
, m_endInc( 0 )
|
||||
, m_curveStatus( OK )
|
||||
{
|
||||
bool isOk = t1.normalize();
|
||||
if ( !isOk )
|
||||
{
|
||||
// No tangent. Bail out
|
||||
m_curveStatus = FAILED_INPUT_OVERLAP;
|
||||
return;
|
||||
}
|
||||
|
||||
cvf::Vec3d p1p2 = p2 - p1;
|
||||
cvf::Vec3d t12 = p1p2.getNormalized( &isOk );
|
||||
if ( !isOk )
|
||||
{
|
||||
// p1 and p2 in the same place.
|
||||
m_curveStatus = FAILED_INPUT_OVERLAP;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cvf::Vec3d N = ( t1 ^ t12 ).getNormalized( &isOk );
|
||||
if ( !isOk )
|
||||
{
|
||||
// P2 is on the p1 + k*t1 line. We have a straight line
|
||||
m_curveStatus = OK_STRAIGHT_LINE;
|
||||
|
||||
RiaOffshoreSphericalCoords endTangent( t1 );
|
||||
m_endTangent = t1;
|
||||
m_endAzi = endTangent.azi();
|
||||
m_endInc = endTangent.inc();
|
||||
m_radius = std::numeric_limits<double>::infinity();
|
||||
m_arcAngle = 0;
|
||||
m_arcLength = p1p2.length();
|
||||
return;
|
||||
}
|
||||
|
||||
cvf::Vec3d tr1 = ( N ^ t1 ).getNormalized();
|
||||
|
||||
m_radius = 0.5 * p1p2.length() / ( tr1.dot( t12 ) );
|
||||
|
||||
cvf::Vec3d C = p1 + m_radius * tr1;
|
||||
|
||||
cvf::Vec3d nTr1 = -tr1;
|
||||
m_arcCS = cvf::Mat4d::fromCoordSystemAxes( &nTr1, &t1, &N );
|
||||
|
||||
m_arcCS.setTranslation( C );
|
||||
|
||||
m_arcAngle = cvf::GeometryTools::getAngle( N, p1 - C, p2 - C );
|
||||
|
||||
m_arcLength = m_radius * m_arcAngle;
|
||||
|
||||
m_endTangent = N ^ ( p2 - C ).getNormalized();
|
||||
|
||||
RiaOffshoreSphericalCoords endTangent( m_endTangent );
|
||||
m_endAzi = endTangent.azi();
|
||||
m_endInc = endTangent.inc();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaArcCurveCalculator::RiaArcCurveCalculator( cvf::Vec3d p1, double azi1, double inc1, cvf::Vec3d p2 )
|
||||
{
|
||||
cvf::Vec3d t1( RiaOffshoreSphericalCoords::unitVectorFromAziInc( azi1, inc1 ) );
|
||||
|
||||
( *this ) = RiaArcCurveCalculator( p1, t1, p2 );
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "cvfMatrix4.h"
|
||||
#include "cvfVector3.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// + p1
|
||||
/// t1 **
|
||||
/// * + C
|
||||
/// *
|
||||
/// + p2
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
class RiaArcCurveCalculator
|
||||
{
|
||||
public:
|
||||
RiaArcCurveCalculator( cvf::Vec3d p1, cvf::Vec3d t1, cvf::Vec3d p2 );
|
||||
RiaArcCurveCalculator( cvf::Vec3d p1, double azi1, double inc1, cvf::Vec3d p2 );
|
||||
|
||||
enum CurveStatus
|
||||
{
|
||||
OK,
|
||||
OK_STRAIGHT_LINE,
|
||||
FAILED_INPUT_OVERLAP
|
||||
};
|
||||
|
||||
CurveStatus curveStatus() const { return m_curveStatus; }
|
||||
|
||||
cvf::Mat4d arcCS() const { return m_arcCS; }
|
||||
double radius() const { return m_radius; }
|
||||
double arcAngle() const { return m_arcAngle; }
|
||||
double arcLength() const { return m_arcLength; }
|
||||
cvf::Vec3d center() const { return m_arcCS.translation(); }
|
||||
cvf::Vec3d normal() const { return cvf::Vec3d( m_arcCS.col( 2 ) ); }
|
||||
|
||||
double endAzimuth() const { return m_endAzi; }
|
||||
double endInclination() const { return m_endInc; }
|
||||
cvf::Vec3d endTangent() const { return m_endTangent; }
|
||||
|
||||
private:
|
||||
CurveStatus m_curveStatus;
|
||||
|
||||
double m_radius;
|
||||
double m_arcLength;
|
||||
double m_arcAngle;
|
||||
cvf::Mat4d m_arcCS;
|
||||
|
||||
double m_endAzi;
|
||||
double m_endInc;
|
||||
cvf::Vec3d m_endTangent;
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaJCurveCalculator.h"
|
||||
#include "RiaArcCurveCalculator.h"
|
||||
#include "RiaOffshoreSphericalCoords.h"
|
||||
#include "cvfMatrix3.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaJCurveCalculator::RiaJCurveCalculator( cvf::Vec3d p1, double azi1, double inc1, double r1, cvf::Vec3d p2 )
|
||||
: m_c1( cvf::Vec3d::UNDEFINED )
|
||||
, m_n1( cvf::Vec3d::UNDEFINED )
|
||||
, m_radius( std::numeric_limits<double>::infinity() )
|
||||
, m_curveStatus( OK )
|
||||
{
|
||||
cvf::Vec3d t1( RiaOffshoreSphericalCoords::unitVectorFromAziInc( azi1, inc1 ) );
|
||||
|
||||
cvf::Vec3d p1p2 = p2 - p1;
|
||||
|
||||
cvf::Vec3d tr1 = p1p2 - ( p1p2.dot( t1 ) ) * t1;
|
||||
double tr1Length = tr1.length();
|
||||
if ( tr1Length < 1e-9 )
|
||||
{
|
||||
// p2 is on the p1 + t12 line. Degenerates to a line.
|
||||
m_curveStatus = OK_STRAIGHT_LINE;
|
||||
m_firstArcEndpoint = p2;
|
||||
m_endAzi = azi1;
|
||||
m_endInc = inc1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
tr1 /= tr1Length;
|
||||
|
||||
cvf::Vec3d c1 = p1 + r1 * tr1;
|
||||
cvf::Vec3d p2c1 = c1 - p2;
|
||||
|
||||
double p2c1Length = p2c1.length();
|
||||
if ( p2c1Length < r1 || r1 == std::numeric_limits<double>::infinity() )
|
||||
{
|
||||
// Radius is too big. We can not get to point 2 using the requested radius.
|
||||
m_curveStatus = FAILED_RADIUS_TOO_LARGE;
|
||||
|
||||
RiaArcCurveCalculator arc( p1, t1, p2 );
|
||||
if ( arc.curveStatus() == RiaArcCurveCalculator::OK || arc.curveStatus() == RiaArcCurveCalculator::OK_STRAIGHT_LINE )
|
||||
{
|
||||
m_c1 = arc.center();
|
||||
m_n1 = arc.normal();
|
||||
m_firstArcEndpoint = p2;
|
||||
m_endAzi = arc.endAzimuth();
|
||||
m_endInc = arc.endInclination();
|
||||
m_radius = arc.radius();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_firstArcEndpoint = p2;
|
||||
m_endAzi = azi1;
|
||||
m_endInc = inc1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
double d = sqrt( p2c1Length * p2c1Length - r1 * r1 );
|
||||
|
||||
double betha = asin( r1 / p2c1Length );
|
||||
cvf::Vec3d tp2c1 = p2c1 / p2c1Length;
|
||||
cvf::Vec3d nc1 = t1 ^ tr1;
|
||||
|
||||
cvf::Vec3d tp11p2 = -tp2c1.getTransformedVector( cvf::Mat3d::fromRotation( nc1, betha ) );
|
||||
|
||||
m_firstArcEndpoint = p2 - d * tp11p2;
|
||||
m_c1 = c1;
|
||||
m_n1 = nc1;
|
||||
|
||||
RiaOffshoreSphericalCoords endTangent( tp11p2 );
|
||||
m_endAzi = endTangent.azi();
|
||||
m_endInc = endTangent.inc();
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "cvfVector3.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// + p1
|
||||
/// t1 **
|
||||
/// * r1 + C
|
||||
/// *
|
||||
/// + firstArcEndpoint
|
||||
/// *
|
||||
/// *
|
||||
/// + p2
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
class RiaJCurveCalculator
|
||||
{
|
||||
public:
|
||||
RiaJCurveCalculator( cvf::Vec3d p1, double azi1, double inc1, double r1, cvf::Vec3d p2 );
|
||||
enum CurveStatus
|
||||
{
|
||||
OK,
|
||||
OK_STRAIGHT_LINE,
|
||||
FAILED_INPUT_OVERLAP,
|
||||
FAILED_RADIUS_TOO_LARGE
|
||||
};
|
||||
|
||||
CurveStatus curveStatus() const { return m_curveStatus; }
|
||||
|
||||
cvf::Vec3d firstArcEndpoint() const { return m_firstArcEndpoint; }
|
||||
|
||||
double radius() const { return m_radius; }
|
||||
cvf::Vec3d firstCenter() const { return m_c1; }
|
||||
cvf::Vec3d firstNormal() const { return m_n1; }
|
||||
|
||||
double endAzimuth() const { return m_endAzi; }
|
||||
double endInclination() const { return m_endInc; }
|
||||
|
||||
private:
|
||||
CurveStatus m_curveStatus;
|
||||
|
||||
cvf::Vec3d m_firstArcEndpoint;
|
||||
|
||||
double m_radius;
|
||||
cvf::Vec3d m_c1;
|
||||
cvf::Vec3d m_n1;
|
||||
|
||||
double m_endAzi;
|
||||
double m_endInc;
|
||||
};
|
||||
@@ -0,0 +1,297 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaLineArcWellPathCalculator.h"
|
||||
|
||||
#include "RiaJCurveCalculator.h"
|
||||
#include "RiaOffshoreSphericalCoords.h"
|
||||
#include "RiaSCurveCalculator.h"
|
||||
#include "cvfAssert.h"
|
||||
|
||||
#define M_PI 3.14159265358979323846 // pi
|
||||
|
||||
cvf::Vec3d smootheningTargetTangent( const cvf::Vec3d& p1, const cvf::Vec3d& p2, const cvf::Vec3d& p3 );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaLineArcWellPathCalculator::RiaLineArcWellPathCalculator( const cvf::Vec3d& referencePointXyz,
|
||||
const std::vector<WellTarget>& activeWellPathTargets )
|
||||
{
|
||||
// Handle incomplete input
|
||||
|
||||
if ( activeWellPathTargets.size() < 2 )
|
||||
{
|
||||
m_startTangent = cvf::Vec3d::ZERO;
|
||||
|
||||
if ( activeWellPathTargets.size() == 1 )
|
||||
{
|
||||
m_lineArcEndpoints.push_back( activeWellPathTargets[0].targetPointXYZ + referencePointXyz );
|
||||
m_targetStatuses.resize( activeWellPathTargets.size(),
|
||||
{ !activeWellPathTargets[0].isTangentConstrained,
|
||||
0.0,
|
||||
0.0,
|
||||
false,
|
||||
true,
|
||||
std::numeric_limits<double>::infinity(),
|
||||
false,
|
||||
true,
|
||||
std::numeric_limits<double>::infinity() } );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_targetStatuses.resize( activeWellPathTargets.size(),
|
||||
{ false,
|
||||
0.0,
|
||||
0.0,
|
||||
false,
|
||||
false,
|
||||
std::numeric_limits<double>::infinity(),
|
||||
false,
|
||||
false,
|
||||
std::numeric_limits<double>::infinity() } );
|
||||
|
||||
std::vector<WellTarget> adjustedWellPathTargets = activeWellPathTargets;
|
||||
|
||||
// Calculate sensible tangents for targets without a fixed one
|
||||
|
||||
if ( activeWellPathTargets.size() > 2 )
|
||||
{
|
||||
for ( size_t tIdx = 0; tIdx < activeWellPathTargets.size() - 2; ++tIdx )
|
||||
{
|
||||
if ( !activeWellPathTargets[tIdx + 1].isTangentConstrained )
|
||||
{
|
||||
cvf::Vec3d tangent = smootheningTargetTangent( activeWellPathTargets[tIdx].targetPointXYZ,
|
||||
activeWellPathTargets[tIdx + 1].targetPointXYZ,
|
||||
activeWellPathTargets[tIdx + 2].targetPointXYZ );
|
||||
RiaOffshoreSphericalCoords tangentSphCS( tangent );
|
||||
adjustedWellPathTargets[tIdx + 1].azimuth = tangentSphCS.azi();
|
||||
adjustedWellPathTargets[tIdx + 1].inclination = tangentSphCS.inc();
|
||||
adjustedWellPathTargets[tIdx + 1].isTangentConstrained = true;
|
||||
|
||||
m_targetStatuses[tIdx + 1].hasDerivedTangent = true;
|
||||
m_targetStatuses[tIdx + 1].resultAzimuth = tangentSphCS.azi();
|
||||
m_targetStatuses[tIdx + 1].resultInclination = tangentSphCS.inc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_lineArcEndpoints.push_back( activeWellPathTargets[0].targetPointXYZ + referencePointXyz );
|
||||
|
||||
// Handle first segment if it is not an S-Curve
|
||||
|
||||
size_t startSSegmentIdx = 0;
|
||||
size_t endSSegementIdx = activeWellPathTargets.size() - 1;
|
||||
|
||||
if ( !adjustedWellPathTargets[0].isTangentConstrained )
|
||||
{
|
||||
startSSegmentIdx = 1;
|
||||
|
||||
const WellTarget& target1 = adjustedWellPathTargets[0];
|
||||
const WellTarget& target2 = adjustedWellPathTargets[1];
|
||||
WellTargetStatus& target1Status = m_targetStatuses[0];
|
||||
WellTargetStatus& target2Status = m_targetStatuses[1];
|
||||
|
||||
if ( adjustedWellPathTargets[1].isTangentConstrained )
|
||||
{
|
||||
// Create an upside down J curve from target 2 back to 1
|
||||
|
||||
RiaJCurveCalculator jCurve( target2.targetPointXYZ,
|
||||
target2.azimuth + M_PI,
|
||||
M_PI - target2.inclination,
|
||||
target2.radius1,
|
||||
target1.targetPointXYZ );
|
||||
|
||||
if ( jCurve.curveStatus() == RiaJCurveCalculator::OK )
|
||||
{
|
||||
m_lineArcEndpoints.push_back( jCurve.firstArcEndpoint() + referencePointXyz );
|
||||
}
|
||||
else if ( jCurve.curveStatus() == RiaJCurveCalculator::FAILED_RADIUS_TOO_LARGE )
|
||||
{
|
||||
target2Status.hasOverriddenRadius1 = true;
|
||||
target2Status.resultRadius1 = jCurve.radius();
|
||||
}
|
||||
|
||||
m_lineArcEndpoints.push_back( target2.targetPointXYZ + referencePointXyz );
|
||||
|
||||
target1Status.hasDerivedTangent = true;
|
||||
target1Status.resultAzimuth = jCurve.endAzimuth() + M_PI;
|
||||
target1Status.resultInclination = M_PI - jCurve.endInclination();
|
||||
|
||||
target2Status.isRadius1Editable = true;
|
||||
}
|
||||
else // The complete wellpath is a straight line from target 1 to 2
|
||||
{
|
||||
m_lineArcEndpoints.push_back( target2.targetPointXYZ + referencePointXyz );
|
||||
cvf::Vec3d t12 = target2.targetPointXYZ - target1.targetPointXYZ;
|
||||
RiaOffshoreSphericalCoords t12Sph( t12 );
|
||||
|
||||
target1Status.hasDerivedTangent = true;
|
||||
target1Status.resultAzimuth = t12Sph.azi();
|
||||
target1Status.resultInclination = t12Sph.inc();
|
||||
|
||||
target2Status.hasDerivedTangent = true;
|
||||
target2Status.resultAzimuth = t12Sph.azi();
|
||||
target2Status.resultInclination = t12Sph.inc();
|
||||
}
|
||||
|
||||
m_startTangent = RiaOffshoreSphericalCoords::unitVectorFromAziInc( target1Status.resultAzimuth,
|
||||
target1Status.resultInclination );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_startTangent = RiaOffshoreSphericalCoords::unitVectorFromAziInc( activeWellPathTargets[0].azimuth,
|
||||
activeWellPathTargets[0].inclination );
|
||||
}
|
||||
|
||||
if ( !adjustedWellPathTargets.back().isTangentConstrained )
|
||||
{
|
||||
endSSegementIdx -= 1;
|
||||
}
|
||||
|
||||
// Calculate S-curves
|
||||
|
||||
if ( activeWellPathTargets.size() > 1 )
|
||||
{
|
||||
for ( size_t tIdx = startSSegmentIdx; tIdx < endSSegementIdx; ++tIdx )
|
||||
{
|
||||
const WellTarget& target1 = adjustedWellPathTargets[tIdx];
|
||||
const WellTarget& target2 = adjustedWellPathTargets[tIdx + 1];
|
||||
WellTargetStatus& target1Status = m_targetStatuses[tIdx];
|
||||
WellTargetStatus& target2Status = m_targetStatuses[tIdx + 1];
|
||||
|
||||
// Ignore targets in the same place
|
||||
if ( ( target1.targetPointXYZ - target2.targetPointXYZ ).length() < 1e-6 ) continue;
|
||||
|
||||
if ( target1.isTangentConstrained && target2.isTangentConstrained )
|
||||
{
|
||||
RiaSCurveCalculator sCurveCalc( target1.targetPointXYZ,
|
||||
target1.azimuth,
|
||||
target1.inclination,
|
||||
target1.radius2,
|
||||
target2.targetPointXYZ,
|
||||
target2.azimuth,
|
||||
target2.inclination,
|
||||
target2.radius1 );
|
||||
|
||||
if ( sCurveCalc.solveStatus() != RiaSCurveCalculator::CONVERGED )
|
||||
{
|
||||
double p1p2Length = ( target2.targetPointXYZ - target1.targetPointXYZ ).length();
|
||||
sCurveCalc = RiaSCurveCalculator::fromTangentsAndLength( target1.targetPointXYZ,
|
||||
target1.azimuth,
|
||||
target1.inclination,
|
||||
0.2 * p1p2Length,
|
||||
target2.targetPointXYZ,
|
||||
target2.azimuth,
|
||||
target2.inclination,
|
||||
0.2 * p1p2Length );
|
||||
|
||||
// RiaLogging::warning("Using fall-back calculation of well path geometry between active target
|
||||
// number: " + QString::number(tIdx+1) + " and " + QString::number(tIdx+2));
|
||||
|
||||
target1Status.hasOverriddenRadius2 = true;
|
||||
target1Status.resultRadius2 = sCurveCalc.firstRadius();
|
||||
|
||||
target2Status.hasOverriddenRadius1 = true;
|
||||
target2Status.resultRadius1 = sCurveCalc.secondRadius();
|
||||
}
|
||||
|
||||
m_lineArcEndpoints.push_back( sCurveCalc.firstArcEndpoint() + referencePointXyz );
|
||||
m_lineArcEndpoints.push_back( sCurveCalc.secondArcStartpoint() + referencePointXyz );
|
||||
m_lineArcEndpoints.push_back( target2.targetPointXYZ + referencePointXyz );
|
||||
|
||||
target1Status.isRadius2Editable = true;
|
||||
target2Status.isRadius1Editable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle last segment if (its not the same as the first) and it has not been handled as an S-Curve
|
||||
|
||||
if ( adjustedWellPathTargets.size() > 2 && endSSegementIdx < ( adjustedWellPathTargets.size() - 1 ) )
|
||||
{
|
||||
size_t targetCount = adjustedWellPathTargets.size();
|
||||
const WellTarget& target1 = adjustedWellPathTargets[targetCount - 2];
|
||||
const WellTarget& target2 = adjustedWellPathTargets[targetCount - 1];
|
||||
WellTargetStatus& target1Status = m_targetStatuses[targetCount - 2];
|
||||
WellTargetStatus& target2Status = m_targetStatuses[targetCount - 1];
|
||||
|
||||
// Create an ordinary J curve
|
||||
|
||||
RiaJCurveCalculator jCurve( target1.targetPointXYZ,
|
||||
target1.azimuth,
|
||||
target1.inclination,
|
||||
target1.radius2,
|
||||
target2.targetPointXYZ );
|
||||
|
||||
if ( jCurve.curveStatus() == RiaJCurveCalculator::OK )
|
||||
{
|
||||
m_lineArcEndpoints.push_back( jCurve.firstArcEndpoint() + referencePointXyz );
|
||||
}
|
||||
else if ( jCurve.curveStatus() == RiaJCurveCalculator::FAILED_RADIUS_TOO_LARGE )
|
||||
{
|
||||
target1Status.hasOverriddenRadius2 = true;
|
||||
target1Status.resultRadius2 = jCurve.radius();
|
||||
}
|
||||
|
||||
m_lineArcEndpoints.push_back( target2.targetPointXYZ + referencePointXyz );
|
||||
|
||||
target1Status.isRadius2Editable = true;
|
||||
|
||||
target2Status.hasDerivedTangent = true;
|
||||
target2Status.resultAzimuth = jCurve.endAzimuth();
|
||||
target2Status.resultInclination = jCurve.endInclination();
|
||||
}
|
||||
}
|
||||
|
||||
cvf::Vec3d smootheningTargetTangent( const cvf::Vec3d& p1, const cvf::Vec3d& p2, const cvf::Vec3d& p3 )
|
||||
{
|
||||
cvf::Vec3d t12 = p2 - p1;
|
||||
cvf::Vec3d t23 = p3 - p2;
|
||||
|
||||
double length12 = t12.length();
|
||||
double length23 = t23.length();
|
||||
|
||||
t12 /= length12; // Normalize
|
||||
t23 /= length23; // Normalize
|
||||
|
||||
cvf::Vec3d t1t2Hor( t12 );
|
||||
t1t2Hor.z() = 0.0;
|
||||
double t12HorLength = t1t2Hor.length();
|
||||
|
||||
cvf::Vec3d t23Hor( t23 );
|
||||
t23Hor.z() = 0.0;
|
||||
double t23HorLength = t23Hor.length();
|
||||
|
||||
// Calculate weights as combo of inverse distance and horizontal component
|
||||
|
||||
double w12 = t12HorLength * 1.0 / length12;
|
||||
double w23 = t23HorLength * 1.0 / length23;
|
||||
|
||||
// Weight the tangents
|
||||
|
||||
t12 *= w12; // Weight
|
||||
t23 *= w23; // Weight
|
||||
|
||||
// Sum and normalization of weights
|
||||
cvf::Vec3d averageTangent = 1.0 / ( w12 + w23 ) * ( t12 + t23 );
|
||||
|
||||
return averageTangent;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "cvfVector3.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class RiaLineArcWellPathCalculator
|
||||
{
|
||||
public:
|
||||
struct WellTarget
|
||||
{
|
||||
cvf::Vec3d targetPointXYZ;
|
||||
bool isTangentConstrained;
|
||||
double azimuth;
|
||||
double inclination;
|
||||
|
||||
double radius1;
|
||||
double radius2;
|
||||
};
|
||||
|
||||
RiaLineArcWellPathCalculator( const cvf::Vec3d& referencePointXyz,
|
||||
const std::vector<RiaLineArcWellPathCalculator::WellTarget>& targets );
|
||||
|
||||
struct WellTargetStatus
|
||||
{
|
||||
bool hasDerivedTangent;
|
||||
double resultAzimuth;
|
||||
double resultInclination;
|
||||
|
||||
bool isRadius1Editable;
|
||||
bool hasOverriddenRadius1;
|
||||
double resultRadius1;
|
||||
|
||||
bool isRadius2Editable;
|
||||
bool hasOverriddenRadius2;
|
||||
double resultRadius2;
|
||||
};
|
||||
|
||||
cvf::Vec3d startTangent() const { return m_startTangent; }
|
||||
const std::vector<cvf::Vec3d>& lineArcEndpoints() const { return m_lineArcEndpoints; }
|
||||
const std::vector<WellTargetStatus>& targetStatuses() const { return m_targetStatuses; }
|
||||
|
||||
private:
|
||||
cvf::Vec3d m_startTangent;
|
||||
std::vector<cvf::Vec3d> m_lineArcEndpoints;
|
||||
std::vector<WellTargetStatus> m_targetStatuses;
|
||||
};
|
||||
@@ -0,0 +1,188 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaPolyArcLineSampler.h"
|
||||
#include "RiaArcCurveCalculator.h"
|
||||
|
||||
#include "cvfGeometryTools.h"
|
||||
#include "cvfMatrix4.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaPolyArcLineSampler::RiaPolyArcLineSampler( const cvf::Vec3d& startTangent,
|
||||
const std::vector<cvf::Vec3d>& lineArcEndPoints )
|
||||
: m_startTangent( startTangent )
|
||||
, m_lineArcEndPoints( lineArcEndPoints )
|
||||
, m_maxSamplingsInterval( 0.15 )
|
||||
, m_isResamplingLines( true )
|
||||
, m_totalMD( 0.0 )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::pair<std::vector<cvf::Vec3d>, std::vector<double>>
|
||||
RiaPolyArcLineSampler::sampledPointsAndMDs( double sampleInterval, bool isResamplingLines )
|
||||
{
|
||||
CVF_ASSERT( sampleInterval > 0.0 );
|
||||
|
||||
m_maxSamplingsInterval = sampleInterval;
|
||||
m_isResamplingLines = isResamplingLines;
|
||||
|
||||
m_points.clear();
|
||||
m_meshDs.clear();
|
||||
|
||||
double startMD = 0.0;
|
||||
|
||||
std::vector<cvf::Vec3d> pointsNoDuplicates = RiaPolyArcLineSampler::pointsWithoutDuplicates( m_lineArcEndPoints );
|
||||
|
||||
if ( pointsNoDuplicates.size() < 2 ) return std::make_pair( m_points, m_meshDs );
|
||||
|
||||
m_totalMD = startMD;
|
||||
|
||||
cvf::Vec3d p1 = pointsNoDuplicates[0];
|
||||
|
||||
m_points.push_back( p1 );
|
||||
m_meshDs.push_back( m_totalMD );
|
||||
|
||||
cvf::Vec3d t2 = m_startTangent;
|
||||
|
||||
for ( size_t pIdx = 0; pIdx < pointsNoDuplicates.size() - 1; ++pIdx )
|
||||
{
|
||||
sampleSegment( t2, pointsNoDuplicates[pIdx], pointsNoDuplicates[pIdx + 1], &t2 );
|
||||
}
|
||||
|
||||
return std::make_pair( m_points, m_meshDs );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaPolyArcLineSampler::sampleSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent )
|
||||
{
|
||||
cvf::Vec3d p1p2 = p2 - p1;
|
||||
|
||||
CVF_ASSERT( p1p2.lengthSquared() > 1e-20 );
|
||||
|
||||
if ( cvf::GeometryTools::getAngle( t1, p1p2 ) < 1e-5 )
|
||||
{
|
||||
sampleLine( p1, p2, endTangent );
|
||||
}
|
||||
else // resample arc
|
||||
{
|
||||
sampleArc( t1, p1, p2, endTangent );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<cvf::Vec3d> RiaPolyArcLineSampler::pointsWithoutDuplicates( const std::vector<cvf::Vec3d>& points )
|
||||
{
|
||||
std::vector<cvf::Vec3d> outputPoints;
|
||||
|
||||
cvf::Vec3d previousPoint = cvf::Vec3d::UNDEFINED;
|
||||
const double threshold = 1e-6;
|
||||
for ( const auto& p : points )
|
||||
{
|
||||
if ( previousPoint.isUndefined() || ( ( previousPoint - p ).lengthSquared() ) > threshold )
|
||||
{
|
||||
outputPoints.push_back( p );
|
||||
previousPoint = p;
|
||||
}
|
||||
}
|
||||
|
||||
return outputPoints;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaPolyArcLineSampler::sampleLine( cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent )
|
||||
{
|
||||
cvf::Vec3d p1p2 = p2 - p1;
|
||||
|
||||
double p1p2Length = p1p2.length();
|
||||
|
||||
if ( m_isResamplingLines && p1p2Length > m_maxSamplingsInterval )
|
||||
{
|
||||
cvf::Vec3d tp1p2 = p1p2 / p1p2Length;
|
||||
double mdInc = m_maxSamplingsInterval;
|
||||
while ( mdInc < p1p2Length )
|
||||
{
|
||||
cvf::Vec3d ps = p1 + mdInc * tp1p2;
|
||||
m_points.push_back( ps );
|
||||
m_meshDs.push_back( m_totalMD + mdInc );
|
||||
mdInc += m_maxSamplingsInterval;
|
||||
}
|
||||
}
|
||||
|
||||
m_totalMD += p1p2Length;
|
||||
m_points.push_back( p2 );
|
||||
m_meshDs.push_back( m_totalMD );
|
||||
|
||||
( *endTangent ) = p1p2.getNormalized();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaPolyArcLineSampler::sampleArc( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent )
|
||||
{
|
||||
// Find arc CS
|
||||
RiaArcCurveCalculator CS_rad( p1, t1, p2 );
|
||||
|
||||
double radius = CS_rad.radius();
|
||||
cvf::Mat4d arcCS = CS_rad.arcCS();
|
||||
|
||||
double angleInc = m_maxSamplingsInterval / radius;
|
||||
|
||||
angleInc = angleInc < m_maxSamplingArcAngle ? angleInc : m_maxSamplingArcAngle; // Angle from 6 deg dogleg on 10 m
|
||||
|
||||
cvf::Vec3d C = CS_rad.center();
|
||||
cvf::Vec3d N = CS_rad.normal();
|
||||
|
||||
// Sample arc by
|
||||
// Rotate vector an increment, and transform to arc CS
|
||||
|
||||
double arcAngle = cvf::GeometryTools::getAngle( N, p1 - C, p2 - C );
|
||||
if ( arcAngle / angleInc > 5000 )
|
||||
{
|
||||
angleInc = arcAngle / 5000;
|
||||
}
|
||||
|
||||
for ( double angle = angleInc; angle < arcAngle; angle += angleInc )
|
||||
{
|
||||
cvf::Vec3d C_to_incP = cvf::Vec3d::X_AXIS;
|
||||
C_to_incP *= radius;
|
||||
C_to_incP.transformVector( cvf::Mat3d::fromRotation( cvf::Vec3d::Z_AXIS, angle ) );
|
||||
|
||||
C_to_incP.transformPoint( arcCS );
|
||||
|
||||
m_points.push_back( C_to_incP );
|
||||
m_meshDs.push_back( m_totalMD + angle * radius );
|
||||
}
|
||||
|
||||
m_totalMD += arcAngle * radius;
|
||||
m_points.push_back( p2 );
|
||||
m_meshDs.push_back( m_totalMD );
|
||||
|
||||
( *endTangent ) = CS_rad.endTangent();
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "cvfVector3.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class RiaPolyArcLineSampler
|
||||
{
|
||||
public:
|
||||
RiaPolyArcLineSampler( const cvf::Vec3d& startTangent, const std::vector<cvf::Vec3d>& lineArcEndPoints );
|
||||
|
||||
std::pair<std::vector<cvf::Vec3d>, std::vector<double>> sampledPointsAndMDs( double maxSampleInterval,
|
||||
bool isResamplingLines );
|
||||
|
||||
static std::vector<cvf::Vec3d> pointsWithoutDuplicates( const std::vector<cvf::Vec3d>& points );
|
||||
|
||||
private:
|
||||
void sampleLine( cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent );
|
||||
void sampleArc( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent );
|
||||
void sampleSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent );
|
||||
|
||||
std::vector<cvf::Vec3d> m_points;
|
||||
std::vector<double> m_meshDs;
|
||||
|
||||
double m_maxSamplingsInterval;
|
||||
const double m_maxSamplingArcAngle = 0.07310818; // Angle from 6 deg dogleg on 10 m
|
||||
bool m_isResamplingLines;
|
||||
double m_totalMD;
|
||||
|
||||
cvf::Vec3d m_startTangent;
|
||||
std::vector<cvf::Vec3d> m_lineArcEndPoints;
|
||||
};
|
||||
@@ -0,0 +1,478 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaSCurveCalculator.h"
|
||||
|
||||
#include "RiaOffshoreSphericalCoords.h"
|
||||
|
||||
#include "cvfMatrix4.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaSCurveCalculator::RiaSCurveCalculator( cvf::Vec3d p1,
|
||||
double azi1,
|
||||
double inc1,
|
||||
double rad1,
|
||||
cvf::Vec3d p2,
|
||||
double azi2,
|
||||
double inc2,
|
||||
double rad2 )
|
||||
: m_isCalculationOK( false )
|
||||
, m_p1( p1 )
|
||||
, m_p2( p2 )
|
||||
, m_firstArcEndpoint( p1 + 0.3 * ( p2 - p1 ) )
|
||||
, m_secondArcStartpoint( p1 + 0.6 * ( p2 - p1 ) )
|
||||
, m_r1( rad1 )
|
||||
, m_r2( rad2 )
|
||||
, m_ctrlPpointCurveStatus( NOT_SET )
|
||||
, m_solveStatus( NOT_SOLVED )
|
||||
{
|
||||
initializeByFinding_q1q2( p1, azi1, inc1, rad1, p2, azi2, inc2, rad2 );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaSCurveCalculator::RiaSCurveCalculator( cvf::Vec3d p1, cvf::Vec3d q1, cvf::Vec3d p2, cvf::Vec3d q2 )
|
||||
: m_isCalculationOK( true )
|
||||
, m_p1( p1 )
|
||||
, m_p2( p2 )
|
||||
, m_ctrlPpointCurveStatus( NOT_SET )
|
||||
, m_solveStatus( NOT_SOLVED )
|
||||
{
|
||||
using Vec3d = cvf::Vec3d;
|
||||
bool isOk = true;
|
||||
m_isCalculationOK = true;
|
||||
|
||||
Vec3d tq1q2 = ( q2 - q1 ).getNormalized( &isOk ); // !ok means the control points are in the same place. Could
|
||||
// fallback to use only one circle segment + one line.
|
||||
m_isCalculationOK = m_isCalculationOK && isOk;
|
||||
Vec3d t1 = ( q1 - p1 ).getNormalized( &isOk ); // !ok means no tangent specified. Could fallback to use only one
|
||||
// circle segment + one line.
|
||||
m_isCalculationOK = m_isCalculationOK && isOk;
|
||||
Vec3d t2 = ( p2 - q2 ).getNormalized( &isOk ); // !ok means no tangent specified. Could fallback to use only one
|
||||
// circle segment + one line or only one straight line if both
|
||||
// tangents are missing
|
||||
m_isCalculationOK = m_isCalculationOK && isOk;
|
||||
|
||||
if ( !m_isCalculationOK )
|
||||
{
|
||||
m_ctrlPpointCurveStatus = FAILED_INPUT_OVERLAP;
|
||||
}
|
||||
|
||||
{
|
||||
Vec3d td1 = ( tq1q2 - t1 );
|
||||
double td1Length = td1.length();
|
||||
|
||||
if ( td1Length > 1e-10 )
|
||||
{
|
||||
td1 /= td1Length;
|
||||
m_c1 = q1 + ( ( q1 - p1 ).length() / ( td1 * ( -t1 ) ) ) * td1;
|
||||
m_r1 = ( m_c1 - p1 ).length();
|
||||
}
|
||||
else // both control points are along t1. First curve has infinite radius
|
||||
{
|
||||
m_c1 = cvf::Vec3d::UNDEFINED;
|
||||
m_r1 = std::numeric_limits<double>::infinity();
|
||||
|
||||
if ( m_ctrlPpointCurveStatus == NOT_SET )
|
||||
{
|
||||
m_ctrlPpointCurveStatus = OK_INFINITE_RADIUS1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Vec3d td2 = ( -tq1q2 + t2 );
|
||||
double td2Length = td2.length();
|
||||
|
||||
if ( td2Length > 1e-10 )
|
||||
{
|
||||
td2 /= td2Length;
|
||||
m_c2 = q2 + ( ( q2 - p2 ).length() / ( td2 * ( t2 ) ) ) * td2;
|
||||
m_r2 = ( m_c2 - p2 ).length();
|
||||
}
|
||||
else // both control points are along t2. Second curve has infinite radius
|
||||
{
|
||||
m_c2 = cvf::Vec3d::UNDEFINED;
|
||||
m_r2 = std::numeric_limits<double>::infinity();
|
||||
|
||||
if ( m_ctrlPpointCurveStatus == NOT_SET )
|
||||
{
|
||||
m_ctrlPpointCurveStatus = OK_INFINITE_RADIUS2;
|
||||
}
|
||||
else if ( m_ctrlPpointCurveStatus == OK_INFINITE_RADIUS1 )
|
||||
{
|
||||
m_ctrlPpointCurveStatus = OK_INFINITE_RADIUS12;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_firstArcEndpoint = q1 + ( q1 - p1 ).length() * tq1q2;
|
||||
m_secondArcStartpoint = q2 - ( q2 - p2 ).length() * tq1q2;
|
||||
|
||||
if ( ( ( q1 - p1 ).length() + ( q2 - p2 ).length() ) > ( q2 - q1 ).length() ) // first arc end and second arc start
|
||||
// is overlapping
|
||||
{
|
||||
m_ctrlPpointCurveStatus = FAILED_ARC_OVERLAP;
|
||||
m_isCalculationOK = false;
|
||||
}
|
||||
|
||||
if ( m_ctrlPpointCurveStatus == NOT_SET )
|
||||
{
|
||||
m_ctrlPpointCurveStatus = OK;
|
||||
}
|
||||
|
||||
// The Circle normals. Will be set to cvf::Vec3d::ZERO if undefined.
|
||||
|
||||
m_n1 = ( t1 ^ tq1q2 ).getNormalized();
|
||||
m_n2 = ( tq1q2 ^ t2 ).getNormalized();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaSCurveCalculator RiaSCurveCalculator::fromTangentsAndLength( cvf::Vec3d p1,
|
||||
double azi1,
|
||||
double inc1,
|
||||
double lengthToQ1,
|
||||
cvf::Vec3d p2,
|
||||
double azi2,
|
||||
double inc2,
|
||||
double lengthToQ2 )
|
||||
{
|
||||
cvf::Vec3d t1( RiaOffshoreSphericalCoords::unitVectorFromAziInc( azi1, inc1 ) );
|
||||
cvf::Vec3d t2( RiaOffshoreSphericalCoords::unitVectorFromAziInc( azi2, inc2 ) );
|
||||
|
||||
cvf::Vec3d Q1 = p1 + lengthToQ1 * t1;
|
||||
cvf::Vec3d Q2 = p2 - lengthToQ2 * t2;
|
||||
|
||||
RiaSCurveCalculator curveFromControlPoints( p1, Q1, p2, Q2 );
|
||||
|
||||
return curveFromControlPoints;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// Needs to calculate J^-1 * [R1_error, R2_error]
|
||||
/// | dR1_dq1 dR1_dq2 | 1 | dR2_dq2 -dR1_dq2 |
|
||||
/// J = | | J^-1 = ---------------------------------- | |
|
||||
/// | dR2_dq1 dR2_dq2 | dR1_dq1*dR2_dq2 - dR1_dq2*dR2_dq1 | -dR2_dq1 dR1_dq1 |
|
||||
///
|
||||
/// | q1_step | | R1_Error |
|
||||
/// | | = - J^-1 | |
|
||||
/// | q2_step | | R2_Error |
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void calculateNewStepsFromJacobi( double dR1_dq1,
|
||||
double dR1_dq2,
|
||||
double dR2_dq1,
|
||||
double dR2_dq2,
|
||||
double R1_error,
|
||||
double R2_error,
|
||||
double* newStepq1,
|
||||
double* newStepq2 )
|
||||
{
|
||||
double invJacobiScale = 1.0 / ( dR1_dq1 * dR2_dq2 - dR2_dq1 * dR1_dq2 );
|
||||
double invJacobi_R1q1 = invJacobiScale * dR2_dq2;
|
||||
double invJacobi_R1q2 = invJacobiScale * -dR1_dq2;
|
||||
double invJacobi_R2q1 = invJacobiScale * -dR2_dq1;
|
||||
double invJacobi_R2q2 = invJacobiScale * dR1_dq1;
|
||||
|
||||
( *newStepq1 ) = -( invJacobi_R1q1 * R1_error + invJacobi_R1q2 * R2_error );
|
||||
( *newStepq2 ) = -( invJacobi_R2q1 * R1_error + invJacobi_R2q2 * R2_error );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool isZeroCrossing( double newError, double oldError, double maxError )
|
||||
{
|
||||
if ( ( newError < -maxError && maxError < oldError ) || ( newError > maxError && -maxError > oldError ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// Iterating with changing q1, q2 (lengths along tangent) to find solution with R1 = r1 and R2 = r2
|
||||
/// R1(q1, q2), R2(q1, q2)
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaSCurveCalculator::initializeByFinding_q1q2( cvf::Vec3d p1,
|
||||
double azi1,
|
||||
double inc1,
|
||||
double r1,
|
||||
cvf::Vec3d p2,
|
||||
double azi2,
|
||||
double inc2,
|
||||
double r2 )
|
||||
{
|
||||
// Algorithm options
|
||||
|
||||
const int maxIterations = 40;
|
||||
const double maxError = 0.01;
|
||||
const double maxStepSize = 1.0e9;
|
||||
const double maxLengthToQ = 1.0e10;
|
||||
bool enableBackstepping = false;
|
||||
//#define USE_JACOBI_UPDATE
|
||||
//#define DEBUG_OUTPUT_ON
|
||||
|
||||
// Needs the initial partial derivatives to see the direction of change
|
||||
// dR1/dq1, dR1/dq2, dR2/dq1, dR2/dq2
|
||||
// Selects a sensible point in the domain for the evaluation
|
||||
|
||||
double p1p2Length = ( p2 - p1 ).length();
|
||||
double delta = 0.01 * p1p2Length;
|
||||
double initialq1q2 = 0.2 * p1p2Length;
|
||||
double deltaPos = initialq1q2 + delta;
|
||||
|
||||
RiaSCurveCalculator ev_0 =
|
||||
RiaSCurveCalculator::fromTangentsAndLength( p1, azi1, inc1, initialq1q2, p2, azi2, inc2, initialq1q2 );
|
||||
|
||||
if ( ev_0.curveStatus() == RiaSCurveCalculator::OK_INFINITE_RADIUS12 )
|
||||
{
|
||||
*this = ev_0;
|
||||
this->m_solveStatus = CONVERGED;
|
||||
return;
|
||||
} // Todo: Handle infinite radius in one place
|
||||
|
||||
RiaSCurveCalculator ev_dq1 =
|
||||
RiaSCurveCalculator::fromTangentsAndLength( p1, azi1, inc1, deltaPos, p2, azi2, inc2, initialq1q2 );
|
||||
RiaSCurveCalculator ev_dq2 =
|
||||
RiaSCurveCalculator::fromTangentsAndLength( p1, azi1, inc1, initialq1q2, p2, azi2, inc2, deltaPos );
|
||||
|
||||
// Initial Jacobi
|
||||
double dR1_dq1 = ( ( r1 - ev_dq1.firstRadius() ) - ( r1 - ev_0.firstRadius() ) ) / delta;
|
||||
double dR2_dq2 = ( ( r2 - ev_dq2.secondRadius() ) - ( r2 - ev_0.secondRadius() ) ) / delta;
|
||||
|
||||
// Initial function value (error)
|
||||
double R1_error = r1 - ev_0.firstRadius();
|
||||
double R2_error = r2 - ev_0.secondRadius();
|
||||
|
||||
// First steps
|
||||
double q1Step = -R1_error / dR1_dq1;
|
||||
double q2Step = -R2_error / dR2_dq2;
|
||||
|
||||
#ifdef USE_JACOBI_UPDATE
|
||||
double dR1_dq2 = ( ( r1 - ev_dq2.firstRadius() ) - ( r1 - ev_0.firstRadius() ) ) / delta;
|
||||
double dR2_dq1 = ( ( r2 - ev_dq1.secondRadius() ) - ( r2 - ev_0.secondRadius() ) ) / delta;
|
||||
|
||||
calculateNewStepsFromJacobi( dR1_dq1, dR1_dq2, dR2_dq1, dR2_dq2, R1_error, R2_error, &q1Step, &q2Step );
|
||||
#endif
|
||||
|
||||
double q1 = initialq1q2;
|
||||
double q2 = initialq1q2;
|
||||
|
||||
#ifdef DEBUG_OUTPUT_ON
|
||||
std::cout << std::endl;
|
||||
std::cout << "Targets: R1, R2: " << r1 << " , " << r2 << std::endl;
|
||||
|
||||
std::cout << 0 << ": " << q1Step << " , " << q2Step << " : " << q1 << " , " << q2 << " | " << ev_0.isOk() << " : "
|
||||
<< ev_0.firstRadius() << " , " << ev_0.secondRadius() << " : " << R1_error << " , " << R2_error
|
||||
<< std::endl;
|
||||
#endif
|
||||
|
||||
SolveStatus solveResultStatus = NOT_SOLVED;
|
||||
|
||||
int backstepLevel = 0;
|
||||
int iteration = 1;
|
||||
for ( iteration = 1; iteration < maxIterations; ++iteration )
|
||||
{
|
||||
if ( fabs( q1Step ) > maxStepSize || fabs( q2Step ) > maxStepSize )
|
||||
{
|
||||
solveResultStatus = FAILED_MAX_TANGENT_STEP_REACHED;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
std::string q1R1StepCorrMarker;
|
||||
std::string q2R2StepCorrMarker;
|
||||
|
||||
if ( q1 + q1Step < 0 )
|
||||
{
|
||||
q1Step = -0.9 * q1;
|
||||
q1R1StepCorrMarker = "*";
|
||||
}
|
||||
if ( q2 + q2Step < 0 )
|
||||
{
|
||||
q2Step = -0.9 * q2;
|
||||
q2R2StepCorrMarker = "*";
|
||||
}
|
||||
|
||||
q1 += q1Step;
|
||||
q2 += q2Step;
|
||||
|
||||
if ( fabs( q1 ) > maxLengthToQ || fabs( q2 ) > maxLengthToQ )
|
||||
{
|
||||
/// Max length along tangent reached
|
||||
solveResultStatus = FAILED_MAX_LENGTH_ALONG_TANGENT_REACHED;
|
||||
break;
|
||||
}
|
||||
|
||||
RiaSCurveCalculator ev_1 = RiaSCurveCalculator::fromTangentsAndLength( p1, azi1, inc1, q1, p2, azi2, inc2, q2 );
|
||||
|
||||
double R1_error_new = r1 - ev_1.firstRadius();
|
||||
double R2_error_new = r2 - ev_1.secondRadius();
|
||||
|
||||
#ifdef DEBUG_OUTPUT_ON
|
||||
std::cout << iteration << ": " << q1Step << q1R1StepCorrMarker << " , " << q2Step << q2R2StepCorrMarker << " : "
|
||||
<< q1 << " , " << q2 << " | " << ev_1.isOk() << " : " << ev_1.firstRadius() << " , "
|
||||
<< ev_1.secondRadius() << " : " << R1_error_new << " , " << R2_error_new;
|
||||
#endif
|
||||
|
||||
if ( ( fabs( R1_error_new ) < maxError || ev_1.curveStatus() == OK_INFINITE_RADIUS1 ) &&
|
||||
( fabs( R2_error_new ) < maxError || ev_1.curveStatus() == OK_INFINITE_RADIUS2 ) )
|
||||
{
|
||||
ev_0 = ev_1;
|
||||
|
||||
// Result ok !
|
||||
|
||||
solveResultStatus = CONVERGED;
|
||||
|
||||
#ifdef DEBUG_OUTPUT_ON
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ( enableBackstepping ) // Experimental back-stepping
|
||||
{
|
||||
bool isZeroCrossingR1 = isZeroCrossing( R1_error_new, R1_error, maxError );
|
||||
bool isZeroCrossingR2 = isZeroCrossing( R2_error_new, R2_error, maxError );
|
||||
|
||||
if ( isZeroCrossingR2 || isZeroCrossingR1 )
|
||||
{
|
||||
q1 -= q1Step;
|
||||
q2 -= q2Step;
|
||||
|
||||
// if (isZeroCrossingR1)
|
||||
q1Step = 0.9 * q1Step * fabs( R1_error ) / ( fabs( R1_error_new ) + fabs( R1_error ) );
|
||||
// if (isZeroCrossingR2)
|
||||
q2Step = 0.9 * q2Step * fabs( R2_error ) / ( fabs( R2_error_new ) + fabs( R2_error ) );
|
||||
|
||||
++backstepLevel;
|
||||
|
||||
#ifdef DEBUG_OUTPUT_ON
|
||||
std::cout << " Backstep needed. " << std::endl;
|
||||
#endif
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
backstepLevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_OUTPUT_ON
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
|
||||
#ifdef USE_JACOBI_UPDATE
|
||||
|
||||
/// Update Jacobi using Broyden
|
||||
// (R_error_n-Rerror_n-1) - Jn-1*dq
|
||||
// J_n = Jn-1 + --------------------------------- (dq)T
|
||||
// | dqn |^2
|
||||
//
|
||||
|
||||
double dR1_error = R1_error_new - R1_error;
|
||||
double dR2_error = R2_error_new - R2_error;
|
||||
R1_error = R1_error_new;
|
||||
R2_error = R2_error_new;
|
||||
|
||||
double stepNormScale = 1.0 / ( q1Step * q1Step + q2Step * q2Step );
|
||||
|
||||
dR1_dq1 = dR1_dq1 + stepNormScale * ( q1Step * ( dR1_error - q1Step * dR1_dq1 + q2Step * dR1_dq2 ) );
|
||||
dR1_dq2 = dR1_dq2 + stepNormScale * ( q2Step * ( dR1_error - q1Step * dR1_dq1 + q2Step * dR1_dq2 ) );
|
||||
dR2_dq1 = dR2_dq1 + stepNormScale * ( q1Step * ( dR2_error - q1Step * dR2_dq1 + q2Step * dR2_dq2 ) );
|
||||
dR2_dq2 = dR2_dq2 + stepNormScale * ( q2Step * ( dR2_error - q1Step * dR2_dq1 + q2Step * dR2_dq2 ) );
|
||||
|
||||
calculateNewStepsFromJacobi( dR1_dq1, dR1_dq2, dR2_dq1, dR2_dq2, R1_error, R2_error, &q1Step, &q2Step );
|
||||
|
||||
#else
|
||||
|
||||
dR1_dq1 = ( ( r1 - ev_1.firstRadius() ) - ( r1 - ev_0.firstRadius() ) ) / q1Step;
|
||||
dR2_dq2 = ( ( r2 - ev_1.secondRadius() ) - ( r2 - ev_0.secondRadius() ) ) / q2Step;
|
||||
|
||||
R1_error = R1_error_new;
|
||||
R2_error = R2_error_new;
|
||||
|
||||
q1Step = -R1_error / dR1_dq1;
|
||||
q2Step = -R2_error / dR2_dq2;
|
||||
|
||||
#endif
|
||||
|
||||
ev_0 = ev_1;
|
||||
}
|
||||
|
||||
*this = ev_0;
|
||||
if ( iteration >= maxIterations )
|
||||
{
|
||||
m_solveStatus = FAILED_MAX_ITERATIONS_REACHED;
|
||||
// Max iterations reached
|
||||
}
|
||||
else
|
||||
{
|
||||
m_solveStatus = solveResultStatus;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaSCurveCalculator::dump() const
|
||||
{
|
||||
cvf::Vec3d v_C1 = firstCenter();
|
||||
cvf::Vec3d v_C2 = secondCenter();
|
||||
cvf::Vec3d v_N1 = firstNormal();
|
||||
cvf::Vec3d v_N2 = secondNormal();
|
||||
cvf::Vec3d v_P11 = firstArcEndpoint();
|
||||
cvf::Vec3d v_P22 = secondArcStartpoint();
|
||||
|
||||
std::cout << " P1: "
|
||||
<< "[ " << m_p1[0] << " " << m_p1[1] << " " << m_p1[2] << " " << std::endl;
|
||||
std::cout << " P11: "
|
||||
<< "[ " << v_P11[0] << " " << v_P11[1] << " " << v_P11[2] << " " << std::endl;
|
||||
std::cout << " P22: "
|
||||
<< "[ " << v_P22[0] << " " << v_P22[1] << " " << v_P22[2] << " " << std::endl;
|
||||
std::cout << " P2: "
|
||||
<< "[ " << m_p2[0] << " " << m_p2[1] << " " << m_p2[2] << " " << std::endl;
|
||||
std::cout << " C1: "
|
||||
<< "[ " << v_C1[0] << " " << v_C1[1] << " " << v_C1[2] << " " << std::endl;
|
||||
std::cout << " C2: "
|
||||
<< "[ " << v_C2[0] << " " << v_C2[1] << " " << v_C2[2] << " " << std::endl;
|
||||
std::cout << " N1: "
|
||||
<< "[ " << v_N1[0] << " " << v_N1[1] << " " << v_N1[2] << " " << std::endl;
|
||||
std::cout << " N2: "
|
||||
<< "[ " << v_N2[0] << " " << v_N2[1] << " " << v_N2[2] << " " << std::endl;
|
||||
std::cout << " R1: "
|
||||
<< "[ " << firstRadius() << " ]" << std::endl;
|
||||
std::cout << " R2: "
|
||||
<< "[ " << secondRadius() << " ]" << std::endl;
|
||||
std::cout << " CtrPointStatus: " << m_ctrlPpointCurveStatus << " SolveStatus: " << m_solveStatus << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "cvfVector3.h"
|
||||
|
||||
class RiaSCurveCalculator
|
||||
{
|
||||
public:
|
||||
RiaSCurveCalculator( cvf::Vec3d p1, double azi1, double inc1, double r1, cvf::Vec3d p2, double azi2, double inc2, double r2 );
|
||||
|
||||
RiaSCurveCalculator( cvf::Vec3d p1, cvf::Vec3d q1, cvf::Vec3d p2, cvf::Vec3d q2 );
|
||||
|
||||
enum CurveStatus
|
||||
{
|
||||
NOT_SET,
|
||||
OK,
|
||||
OK_INFINITE_RADIUS1,
|
||||
OK_INFINITE_RADIUS2,
|
||||
OK_INFINITE_RADIUS12,
|
||||
FAILED_INPUT_OVERLAP,
|
||||
FAILED_ARC_OVERLAP
|
||||
};
|
||||
enum SolveStatus
|
||||
{
|
||||
NOT_SOLVED,
|
||||
CONVERGED,
|
||||
FAILED_MAX_LENGTH_ALONG_TANGENT_REACHED,
|
||||
FAILED_MAX_TANGENT_STEP_REACHED,
|
||||
FAILED_MAX_ITERATIONS_REACHED
|
||||
};
|
||||
|
||||
bool isOk() const { return m_isCalculationOK; }
|
||||
CurveStatus curveStatus() const { return m_ctrlPpointCurveStatus; }
|
||||
SolveStatus solveStatus() const { return m_solveStatus; }
|
||||
|
||||
cvf::Vec3d firstArcEndpoint() const { return m_firstArcEndpoint; }
|
||||
cvf::Vec3d secondArcStartpoint() const { return m_secondArcStartpoint; }
|
||||
cvf::Vec3d firstCenter() const { return m_c1; }
|
||||
cvf::Vec3d secondCenter() const { return m_c2; }
|
||||
cvf::Vec3d firstNormal() const { return m_n1; }
|
||||
cvf::Vec3d secondNormal() const { return m_n2; }
|
||||
double firstRadius() const { return m_r1; }
|
||||
double secondRadius() const { return m_r2; }
|
||||
|
||||
void dump() const;
|
||||
|
||||
static RiaSCurveCalculator fromTangentsAndLength( cvf::Vec3d p1,
|
||||
double azi1,
|
||||
double inc1,
|
||||
double lengthToQ1,
|
||||
cvf::Vec3d p2,
|
||||
double azi2,
|
||||
double inc2,
|
||||
double lengthToQ2 );
|
||||
|
||||
private:
|
||||
void initializeByFinding_q1q2( cvf::Vec3d p1,
|
||||
double azi1,
|
||||
double inc1,
|
||||
double r1,
|
||||
cvf::Vec3d p2,
|
||||
double azi2,
|
||||
double inc2,
|
||||
double r2 );
|
||||
|
||||
bool m_isCalculationOK;
|
||||
|
||||
CurveStatus m_ctrlPpointCurveStatus;
|
||||
SolveStatus m_solveStatus;
|
||||
|
||||
cvf::Vec3d m_p1;
|
||||
cvf::Vec3d m_p2;
|
||||
cvf::Vec3d m_firstArcEndpoint;
|
||||
cvf::Vec3d m_secondArcStartpoint;
|
||||
cvf::Vec3d m_c1;
|
||||
cvf::Vec3d m_c2;
|
||||
cvf::Vec3d m_n1;
|
||||
cvf::Vec3d m_n2;
|
||||
double m_r1;
|
||||
double m_r2;
|
||||
};
|
||||
@@ -0,0 +1,134 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "RiaWellPlanCalculator.h"
|
||||
#include "RiaArcCurveCalculator.h"
|
||||
#include "RiaOffshoreSphericalCoords.h"
|
||||
|
||||
#include "cvfGeometryTools.h"
|
||||
#include "cvfMatrix4.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiaWellPlanCalculator::RiaWellPlanCalculator( const cvf::Vec3d& startTangent,
|
||||
const std::vector<cvf::Vec3d>& lineArcEndPoints )
|
||||
: m_startTangent( startTangent )
|
||||
, m_lineArcEndPoints( lineArcEndPoints )
|
||||
{
|
||||
if ( m_lineArcEndPoints.size() < 2 ) return;
|
||||
|
||||
WellPlanSegment segment = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
|
||||
|
||||
RiaOffshoreSphericalCoords startAziIncRad( m_startTangent );
|
||||
segment.inc = cvf::Math::toDegrees( startAziIncRad.inc() );
|
||||
segment.azi = cvf::Math::toDegrees( startAziIncRad.azi() );
|
||||
|
||||
segment.TVD = -lineArcEndPoints[0].z();
|
||||
segment.NS = lineArcEndPoints[0].y();
|
||||
segment.EW = lineArcEndPoints[0].x();
|
||||
|
||||
m_wpResult.push_back( segment );
|
||||
|
||||
cvf::Vec3d t2 = m_startTangent;
|
||||
|
||||
for ( size_t pIdx = 0; pIdx < m_lineArcEndPoints.size() - 1; ++pIdx )
|
||||
{
|
||||
addSegment( t2, m_lineArcEndPoints[pIdx], m_lineArcEndPoints[pIdx + 1], &t2 );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaWellPlanCalculator::addSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent )
|
||||
{
|
||||
cvf::Vec3d p1p2 = p2 - p1;
|
||||
double xyLength = std::sqrt( p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y() );
|
||||
double zLength = std::abs( p1p2.z() );
|
||||
|
||||
// We only show two decimals in the well plan anyway.
|
||||
if ( xyLength < 1.0e-2 && zLength < 1.0e-2 ) return;
|
||||
|
||||
if ( cvf::GeometryTools::getAngle( t1, p1p2 ) < 1e-5 )
|
||||
{
|
||||
addLineSegment( p1, p2, endTangent );
|
||||
}
|
||||
else // resample arc
|
||||
{
|
||||
addArcSegment( t1, p1, p2, endTangent );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaWellPlanCalculator::addLineSegment( cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent )
|
||||
{
|
||||
WellPlanSegment segment = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
|
||||
|
||||
cvf::Vec3d p1p2 = p2 - p1;
|
||||
double length = p1p2.length();
|
||||
|
||||
segment.CL = length;
|
||||
segment.MD = m_wpResult.back().MD + length;
|
||||
|
||||
cvf::Vec3d tangent = p1p2 / length;
|
||||
|
||||
RiaOffshoreSphericalCoords aziIncRad( p1p2 );
|
||||
segment.inc = cvf::Math::toDegrees( aziIncRad.inc() );
|
||||
segment.azi = cvf::Math::toDegrees( aziIncRad.azi() );
|
||||
|
||||
segment.TVD = -p2.z();
|
||||
segment.NS = p2.y();
|
||||
segment.EW = p2.x();
|
||||
segment.dogleg = 0.0;
|
||||
segment.build = 0.0;
|
||||
segment.turn = 0.0;
|
||||
|
||||
m_wpResult.push_back( segment );
|
||||
*endTangent = tangent;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaWellPlanCalculator::addArcSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent )
|
||||
{
|
||||
WellPlanSegment segment = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
|
||||
|
||||
RiaArcCurveCalculator arcCalc( p1, t1, p2 );
|
||||
|
||||
segment.CL = arcCalc.arcLength();
|
||||
segment.MD = m_wpResult.back().MD + segment.CL;
|
||||
segment.inc = cvf::Math::toDegrees( arcCalc.endInclination() );
|
||||
segment.azi = cvf::Math::toDegrees( arcCalc.endAzimuth() );
|
||||
segment.TVD = -p2.z();
|
||||
segment.NS = p2.y();
|
||||
segment.EW = p2.x();
|
||||
segment.dogleg = cvf::Math::toDegrees( 30.0 / arcCalc.radius() );
|
||||
RiaOffshoreSphericalCoords startAziIncRad( t1 );
|
||||
double buildInRadsPrLength = ( arcCalc.endInclination() - startAziIncRad.inc() ) / arcCalc.arcLength();
|
||||
double turnInRadsPrLength = ( arcCalc.endAzimuth() - startAziIncRad.azi() ) / arcCalc.arcLength();
|
||||
segment.build = 30 * cvf::Math::toDegrees( buildInRadsPrLength );
|
||||
segment.turn = 30 * cvf::Math::toDegrees( turnInRadsPrLength );
|
||||
|
||||
m_wpResult.push_back( segment );
|
||||
|
||||
( *endTangent ) = arcCalc.endTangent();
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2018- 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 "cvfVector3.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class RiaWellPlanCalculator
|
||||
{
|
||||
public:
|
||||
RiaWellPlanCalculator( const cvf::Vec3d& startTangent, const std::vector<cvf::Vec3d>& lineArcEndPoints );
|
||||
|
||||
struct WellPlanSegment
|
||||
{
|
||||
double MD;
|
||||
double CL;
|
||||
double inc;
|
||||
double azi;
|
||||
double TVD;
|
||||
double NS;
|
||||
double EW;
|
||||
double dogleg;
|
||||
double build;
|
||||
double turn;
|
||||
};
|
||||
|
||||
const std::vector<WellPlanSegment>& wellPlan() const { return m_wpResult; }
|
||||
|
||||
private:
|
||||
void addSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent );
|
||||
void addLineSegment( cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent );
|
||||
void addArcSegment( cvf::Vec3d t1, cvf::Vec3d p1, cvf::Vec3d p2, cvf::Vec3d* endTangent );
|
||||
|
||||
cvf::Vec3d m_startTangent;
|
||||
std::vector<cvf::Vec3d> m_lineArcEndPoints;
|
||||
|
||||
std::vector<WellPlanSegment> m_wpResult;
|
||||
};
|
||||
Reference in New Issue
Block a user