///////////////////////////////////////////////////////////////////////////////// // // 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 // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RimWellPathCollection.h" #include "RiaApplication.h" #include "RiaPreferences.h" #include "RimProject.h" #include "RimWellPath.h" #include "RimWellLogFile.h" #include "RivWellPathCollectionPartMgr.h" #include "RiuMainWindow.h" #include "cafPdmUiEditorHandle.h" #include "cafProgressInfo.h" #include #include #include #include #include namespace caf { template<> void RimWellPathCollection::WellVisibilityEnum::setUp() { addItem(RimWellPathCollection::FORCE_ALL_OFF, "FORCE_ALL_OFF", "Off"); addItem(RimWellPathCollection::ALL_ON, "ALL_ON", "Individual"); addItem(RimWellPathCollection::FORCE_ALL_ON, "FORCE_ALL_ON", "On"); } } CAF_PDM_SOURCE_INIT(RimWellPathCollection, "WellPaths"); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimWellPathCollection::RimWellPathCollection() { CAF_PDM_InitObject("Wells", ":/WellCollection.png", "", ""); CAF_PDM_InitField(&isActive, "Active", true, "Active", "", "", ""); isActive.uiCapability()->setUiHidden(true); CAF_PDM_InitField(&showWellPathLabel, "ShowWellPathLabel", true, "Show well path labels", "", "", ""); cvf::Color3f defWellLabelColor = RiaApplication::instance()->preferences()->defaultWellLabelColor(); CAF_PDM_InitField(&wellPathLabelColor, "WellPathLabelColor", defWellLabelColor, "Well label color", "", "", ""); CAF_PDM_InitField(&wellPathVisibility, "GlobalWellPathVisibility", WellVisibilityEnum(ALL_ON), "Global well path visibility", "", "", ""); CAF_PDM_InitField(&wellPathRadiusScaleFactor, "WellPathRadiusScale", 0.1, "Well Path radius scale", "", "", ""); CAF_PDM_InitField(&wellPathCrossSectionVertexCount, "WellPathVertexCount", 12, "Well Path vertex count", "", "", ""); wellPathCrossSectionVertexCount.xmlCapability()->setIOWritable(false); wellPathCrossSectionVertexCount.xmlCapability()->setIOReadable(false); wellPathCrossSectionVertexCount.uiCapability()->setUiHidden(true); CAF_PDM_InitField(&wellPathClip, "WellPathClip", true, "Clip Well Paths", "", "", ""); CAF_PDM_InitField(&wellPathClipZDistance, "WellPathClipZDistance", 100, "Well path clipping depth distance", "", "", ""); CAF_PDM_InitFieldNoDefault(&wellPaths, "WellPaths", "Well Paths", "", "", ""); wellPaths.uiCapability()->setUiHidden(true); m_wellPathCollectionPartManager = new RivWellPathCollectionPartMgr(this); m_project = NULL; m_asciiFileReader = new RifWellPathAsciiFileReader; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimWellPathCollection::~RimWellPathCollection() { wellPaths.deleteAllChildObjects(); delete m_asciiFileReader; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPathCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { scheduleGeometryRegenAndRedrawViews(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPathCollection::setProject( RimProject* project ) { m_project = project; for (size_t wellPathIdx = 0; wellPathIdx < wellPaths.size(); wellPathIdx++) { wellPaths[wellPathIdx]->setProject(m_project); wellPaths[wellPathIdx]->setCollection(this); } } //-------------------------------------------------------------------------------------------------- /// Read JSON files containing well path data //-------------------------------------------------------------------------------------------------- void RimWellPathCollection::readWellPathFiles() { caf::ProgressInfo progress(wellPaths.size(), "Reading well paths from file"); for (size_t wpIdx = 0; wpIdx < wellPaths.size(); wpIdx++) { if (!wellPaths[wpIdx]->filepath().isEmpty()) { QString errorMessage; if (!wellPaths[wpIdx]->readWellPathFile(&errorMessage)) { QMessageBox::warning(RiuMainWindow::instance(), "File open error", errorMessage); } } RimWellLogFile* wellLogFile = wellPaths[wpIdx]->m_wellLogFile; if (wellLogFile) { QString errorMessage; if (!wellLogFile->readFile(&errorMessage)) { QString displayMessage = "Could not open the well log file: \n" + wellLogFile->fileName(); if (!errorMessage.isEmpty()) { displayMessage += "\n\n"; displayMessage += errorMessage; } QMessageBox::warning(RiuMainWindow::instance(), "File open error", displayMessage); } } progress.setProgressDescription(QString("Reading file %1").arg(wellPaths[wpIdx]->name)); progress.incrementProgress(); } this->sortWellsByName(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPathCollection::addWellPaths( QStringList filePaths ) { std::vector wellPathArray; foreach (QString filePath, filePaths) { // Check if this file is already open bool alreadyOpen = false; for (size_t wpIdx = 0; wpIdx < wellPaths.size(); wpIdx++) { QFile f1; f1.setFileName(filePath); QString s1 = f1.fileName(); QFile f2; f2.setFileName(wellPaths[wpIdx]->filepath()); QString s2 = f2.fileName(); if (s1 == s2) { //printf("Attempting to open well path JSON file that is already open:\n %s\n", (const char*) filePath.toLocal8Bit()); alreadyOpen = true; break; } } if (!alreadyOpen) { QFileInfo fi(filePath); if (fi.suffix().compare("json") == 0) { RimWellPath* wellPath = new RimWellPath(); wellPath->setProject(m_project); wellPath->setCollection(this); wellPath->filepath = filePath; wellPathArray.push_back(wellPath); } else { // Create Well path objects for all the paths in the assumed ascii file size_t wellPathCount = this->m_asciiFileReader->wellDataCount(filePath); for (size_t i = 0; i < wellPathCount; ++i) { RimWellPath* wellPath = new RimWellPath(); wellPath->setProject(m_project); wellPath->setCollection(this); wellPath->filepath = filePath; wellPath->wellPathIndexInFile = static_cast(i); wellPathArray.push_back(wellPath); } } } } readAndAddWellPaths(wellPathArray); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPathCollection::readAndAddWellPaths(std::vector& wellPathArray) { caf::ProgressInfo progress(wellPathArray.size(), "Reading well paths from file"); for (size_t wpIdx = 0; wpIdx < wellPathArray.size(); wpIdx++) { RimWellPath* wellPath = wellPathArray[wpIdx]; wellPath->readWellPathFile(NULL); progress.setProgressDescription(QString("Reading file %1").arg(wellPath->name)); // If a well path with this name exists already, make it read the well path file RimWellPath* existingWellPath = wellPathByName(wellPath->name); if (existingWellPath) { existingWellPath->filepath = wellPath->filepath; existingWellPath->wellPathIndexInFile = wellPath->wellPathIndexInFile; existingWellPath->readWellPathFile(NULL); delete wellPath; } else { wellPaths.push_back(wellPath); } progress.incrementProgress(); } this->sortWellsByName(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPathCollection::addWellLogs(const QStringList& filePaths) { foreach (QString filePath, filePaths) { RimWellLogFile* logFileInfo = RimWellLogFile::readWellLogFile(filePath); if (logFileInfo) { RimWellPath* wellPath = wellPathByName(logFileInfo->wellName()); if (!wellPath) { wellPath = new RimWellPath(); wellPath->setCollection(this); wellPaths.push_back(wellPath); } wellPath->setLogFileInfo(logFileInfo); } } this->sortWellsByName(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPathCollection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { caf::PdmUiGroup* wellHeadGroup = uiOrdering.addNewGroup("Well labels"); wellHeadGroup->add(&showWellPathLabel); wellHeadGroup->add(&wellPathLabelColor); caf::PdmUiGroup* wellPipe = uiOrdering.addNewGroup("Well pipe"); wellPipe->add(&wellPathVisibility); wellPipe->add(&wellPathRadiusScaleFactor); caf::PdmUiGroup* advancedGroup = uiOrdering.addNewGroup("Clipping"); advancedGroup->add(&wellPathClip); advancedGroup->add(&wellPathClipZDistance); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- caf::PdmFieldHandle* RimWellPathCollection::objectToggleField() { return &isActive; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPathCollection::scheduleGeometryRegenAndRedrawViews() { m_wellPathCollectionPartManager->scheduleGeometryRegen(); if (m_project) m_project->createDisplayModelAndRedrawAllViews(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPathCollection::updateFilePathsFromProjectPath() { for (size_t wellPathIdx = 0; wellPathIdx < wellPaths.size(); wellPathIdx++) { wellPaths[wellPathIdx]->updateFilePathsFromProjectPath(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimWellPath* RimWellPathCollection::wellPathByName(const QString& wellPathName) const { for (size_t wellPathIdx = 0; wellPathIdx < wellPaths.size(); wellPathIdx++) { if (wellPaths[wellPathIdx]->name() == wellPathName) { return wellPaths[wellPathIdx]; } } return NULL; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPathCollection::deleteAllWellPaths() { wellPaths.deleteAllChildObjects(); m_asciiFileReader->clear(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPathCollection::removeWellPath(RimWellPath* wellPath) { wellPaths.removeChildObject(wellPath); bool isFilePathUsed = false; for (size_t i = 0; i < wellPaths.size(); i++) { if (wellPaths[i]->filepath == wellPath->filepath) { isFilePathUsed = true; break; } } if (!isFilePathUsed) { // One file can have multiple well paths // If no other well paths are referencing the filepath, remove cached data from the file reader m_asciiFileReader->removeFilePath(wellPath->filepath); } } bool lessWellPath(const caf::PdmPointer& w1, const caf::PdmPointer& w2) { if (w1.notNull() && w2.notNull()) return (w1->name() < w2->name()); else if (w1.notNull()) return true; else return false; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPathCollection::sortWellsByName() { std::sort(wellPaths.begin(), wellPaths.end(), lessWellPath); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RifWellPathAsciiFileReader::readAllWellData(QString filePath) { std::map >::iterator it = m_fileNameToWellDataGroupMap.find(filePath); // If we have the file in the map, assume it is already read. if (it != m_fileNameToWellDataGroupMap.end()) { return; } // Create the data container std::vector& fileWellDataArray = m_fileNameToWellDataGroupMap[filePath]; std::ifstream stream(filePath.toLatin1().data()); double x(HUGE_VAL), y(HUGE_VAL), tvd(HUGE_VAL), md(HUGE_VAL); while(stream.good()) { stream >> x; if (stream.good()) { stream >> y >> tvd >> md; if (!stream.good()) { // -999 or otherwise to few numbers before some word if (x != -999) { // Error in file: missing numbers at this line } stream.clear(); } else { if (!fileWellDataArray.size() ) { fileWellDataArray.push_back(WellData()); fileWellDataArray.back().m_wellPathGeometry = new RigWellPath(); } cvf::Vec3d wellPoint(x, y, -tvd); fileWellDataArray.back().m_wellPathGeometry->m_wellPathPoints.push_back(wellPoint); fileWellDataArray.back().m_wellPathGeometry->m_measuredDepths.push_back(md); x = HUGE_VAL; y = HUGE_VAL; tvd = HUGE_VAL; md = HUGE_VAL; } } else { // Could not read one double. // we assume there is a comment line or a well path description stream.clear(); std::string line; std::getline(stream, line, '\n'); size_t quoteStartIdx = line.find_first_of("'`´’‘"); size_t quoteEndIdx = line.find_last_of("'`´’‘"); std::string wellName; if (quoteStartIdx < line.size() -1 ) { // Extract the text between the quotes wellName = line.substr(quoteStartIdx + 1, quoteEndIdx - 1 - quoteStartIdx); } else if (quoteStartIdx > line.length() && quoteEndIdx > line.length()) { // Did not find any quotes // Supported alternatives are // name WellNameA // wellname: WellNameA std::string lineLowerCase = line; transform(lineLowerCase.begin(), lineLowerCase.end(), lineLowerCase.begin(), ::tolower ); std::string tokenName = "name"; std::size_t foundNameIdx = lineLowerCase.find(tokenName); if (foundNameIdx != std::string::npos) { std::string tokenColon = ":"; std::size_t foundColonIdx = lineLowerCase.find(tokenColon, foundNameIdx); if (foundColonIdx != std::string::npos) { wellName = line.substr(foundColonIdx + tokenColon.length()); } else { wellName = line.substr(foundNameIdx + tokenName.length()); } } } if (wellName.size() > 0) { // Create a new Well data fileWellDataArray.push_back(WellData()); fileWellDataArray.back().m_wellPathGeometry = new RigWellPath(); QString name = wellName.c_str(); fileWellDataArray.back().m_name = name.trimmed(); } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RifWellPathAsciiFileReader::WellData RifWellPathAsciiFileReader::readWellData(QString filePath, int indexInFile) { this->readAllWellData(filePath); std::map >::iterator it = m_fileNameToWellDataGroupMap.find(filePath); CVF_ASSERT(it != m_fileNameToWellDataGroupMap.end()); if (indexInFile < static_cast(it->second.size())) { return it->second[indexInFile]; } else { // Error : The ascii well path file does not contain that many well paths return WellData(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RifWellPathAsciiFileReader::wellDataCount(QString filePath) { std::map >::iterator it = m_fileNameToWellDataGroupMap.find(filePath); // If we have the file in the map, assume it is already read. if (it != m_fileNameToWellDataGroupMap.end()) { return it->second.size(); } this->readAllWellData(filePath); it = m_fileNameToWellDataGroupMap.find(filePath); CVF_ASSERT(it != m_fileNameToWellDataGroupMap.end()); return it->second.size();; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RifWellPathAsciiFileReader::clear() { m_fileNameToWellDataGroupMap.clear(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RifWellPathAsciiFileReader::removeFilePath(const QString& filePath) { m_fileNameToWellDataGroupMap.erase(filePath); }