///////////////////////////////////////////////////////////////////////////////// // // 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 // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RiaApplication.h" #include "RiaArgumentParser.h" #include "RiaBaseDefs.h" #include "RiaFilePathTools.h" #include "RiaFontCache.h" #include "RiaGuiApplication.h" #include "RiaImportEclipseCaseTools.h" #include "RiaLogging.h" #include "RiaPreferences.h" #include "RiaProjectModifier.h" #include "RiaSocketServer.h" #include "RiaVersionInfo.h" #include "RiaViewRedrawScheduler.h" #include "ExportCommands/RicSnapshotAllViewsToFileFeature.h" #include "HoloLensCommands/RicHoloLensSessionManager.h" #include "RicImportGeneralDataFeature.h" #include "RicfCommandFileExecutor.h" #include "RicfMessages.h" #include "Rim2dIntersectionViewCollection.h" #include "RimAnnotationCollection.h" #include "RimAnnotationInViewCollection.h" #include "RimAnnotationTextAppearance.h" #include "RimCellRangeFilterCollection.h" #include "RimCommandObject.h" #include "RimEclipseCaseCollection.h" #include "RimEclipseView.h" #include "RimFlowPlotCollection.h" #include "RimFormationNamesCollection.h" #include "RimFractureTemplateCollection.h" #include "RimGeoMechCase.h" #include "RimGeoMechCellColors.h" #include "RimGeoMechModels.h" #include "RimGeoMechView.h" #include "RimGridCrossPlot.h" #include "RimGridCrossPlotCollection.h" #include "RimIdenticalGridCaseGroup.h" #include "RimMainPlotCollection.h" #include "RimObservedDataCollection.h" #include "RimObservedFmuRftData.h" #include "RimObservedSummaryData.h" #include "RimOilField.h" #include "RimPltPlotCollection.h" #include "RimProject.h" #include "RimRftPlotCollection.h" #include "RimSaturationPressurePlot.h" #include "RimSaturationPressurePlotCollection.h" #include "RimSimWellInViewCollection.h" #include "RimStimPlanColors.h" #include "RimSummaryCase.h" #include "RimSummaryCaseCollection.h" #include "RimSummaryCaseMainCollection.h" #include "RimSummaryCrossPlotCollection.h" #include "RimSummaryPlot.h" #include "RimTextAnnotation.h" #include "RimTextAnnotationInView.h" #include "RimViewLinker.h" #include "RimViewLinkerCollection.h" #include "RimWellLogFile.h" #include "RimWellLogPlot.h" #include "RimWellLogPlotCollection.h" #include "RimWellPathCollection.h" #include "RimWellPathFracture.h" #include "RimWellPltPlot.h" #include "RimWellRftPlot.h" #include "RiuViewer.h" #include "RiuViewerCommands.h" #include "cafPdmSettings.h" #include "cafPdmUiModelChangeDetector.h" #include "cafProgressInfo.h" #include "cafUiProcess.h" #include "cafUtils.h" #include "cvfProgramOptions.h" #include "cvfqtUtils.h" #include #include #include #include #ifdef WIN32 #include #else #include // for usleep #endif // WIN32 #ifdef USE_UNIT_TESTS #include "gtest/gtest.h" #endif // USE_UNIT_TESTS RiaApplication* RiaApplication::s_riaApplication = nullptr; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiaApplication* RiaApplication::instance() { return s_riaApplication; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiaApplication::RiaApplication() : m_socketServer( nullptr ) , m_workerProcess( nullptr ) , m_preferences( nullptr ) , m_runningWorkerProcess( false ) { CAF_ASSERT( s_riaApplication == nullptr ); s_riaApplication = this; // USed to get registry settings in the right place QCoreApplication::setOrganizationName( RI_COMPANY_NAME ); QCoreApplication::setApplicationName( RI_APPLICATION_NAME ); #ifdef WIN32 m_startupDefaultDirectory = QDir::homePath(); #else m_startupDefaultDirectory = QDir::currentPath(); #endif setLastUsedDialogDirectory( "MULTICASEIMPORT", "/" ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiaApplication::~RiaApplication() { delete m_preferences; delete m_project; RiaFontCache::clear(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const char* RiaApplication::getVersionStringApp( bool includeCrtInfo ) { // Use static buf so we can return ptr static char szBuf[1024]; cvf::String crtInfo; if ( includeCrtInfo ) { #ifdef _MT #ifdef _DLL crtInfo = " (DLL CRT)"; #else crtInfo = " (static CRT)"; #endif #endif //_MT } cvf::System::sprintf( szBuf, 1024, "%s%s", STRPRODUCTVER, crtInfo.toAscii().ptr() ); return szBuf; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RiaApplication::enableDevelopmentFeatures() { QString environmentVar = QProcessEnvironment::systemEnvironment().value( "RESINSIGHT_DEVEL", QString( "0" ) ); return environmentVar.toInt() == 1; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::createMockModel() { RiaImportEclipseCaseTools::openMockModel( RiaDefines::mockModelBasic() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::createResultsMockModel() { RiaImportEclipseCaseTools::openMockModel( RiaDefines::mockModelBasicWithResults() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::createLargeResultsMockModel() { RiaImportEclipseCaseTools::openMockModel( RiaDefines::mockModelLargeWithResults() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::createMockModelCustomized() { RiaImportEclipseCaseTools::openMockModel( RiaDefines::mockModelCustomized() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::createInputMockModel() { RiaImportEclipseCaseTools::openEclipseInputCaseFromFileNames( QStringList( RiaDefines::mockModelBasicInputCase() ) ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::setActiveReservoirView( Rim3dView* rv ) { m_activeReservoirView = rv; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const Rim3dView* RiaApplication::activeReservoirView() const { return m_activeReservoirView; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- Rim3dView* RiaApplication::activeReservoirView() { return m_activeReservoirView; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimGridView* RiaApplication::activeGridView() { return dynamic_cast( m_activeReservoirView.p() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimGridView* RiaApplication::activeMainOrComparisonGridView() { RimGridView* activeView = RiaApplication::instance()->activeGridView(); RimGridView* viewOrComparisonView = activeView; if ( activeView != nullptr && activeView->viewer() && activeView->viewer()->viewerCommands()->isCurrentPickInComparisonView() ) { if ( RimGridView* compView = dynamic_cast( activeView->activeComparisonView() ) ) { viewOrComparisonView = compView; } } return viewOrComparisonView; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimProject* RiaApplication::project() { return m_project; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RiaApplication::openFile( const QString& fileName ) { if ( !caf::Utils::fileExists( fileName ) ) return false; bool loadingSucceded = false; QString lastUsedDialogTag; RiaDefines::ImportFileType fileType = RiaDefines::obtainFileTypeFromFileName( fileName ); if ( fileType == RiaDefines::RESINSIGHT_PROJECT_FILE ) { loadingSucceded = loadProject( fileName ); } else if ( fileType == RiaDefines::GEOMECH_ODB_FILE ) { loadingSucceded = openOdbCaseFromFile( fileName ); lastUsedDialogTag = "GEOMECH_MODEL"; } else if ( fileType & RiaDefines::ANY_ECLIPSE_FILE ) { loadingSucceded = RicImportGeneralDataFeature::openEclipseFilesFromFileNames( QStringList{fileName}, true ); lastUsedDialogTag = RiaDefines::defaultDirectoryLabel( fileType ); } if ( loadingSucceded ) { if ( !lastUsedDialogTag.isEmpty() ) { RiaApplication::instance()->setLastUsedDialogDirectory( lastUsedDialogTag, QFileInfo( fileName ).absolutePath() ); } onFileSuccessfullyLoaded( fileName, fileType ); } return loadingSucceded; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RiaApplication::isProjectSavedToDisc() const { if ( m_project.isNull() ) return false; return caf::Utils::fileExists( m_project->fileName() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RiaApplication::currentProjectPath() const { QString projectFolder; if ( m_project ) { QString projectFileName = m_project->fileName(); if ( !projectFileName.isEmpty() ) { QFileInfo fi( projectFileName ); projectFolder = fi.absolutePath(); } } return projectFolder; } //-------------------------------------------------------------------------------------------------- /// Create an absolute path from a path that is specified relative to the project directory /// /// If the path specified in \a projectRelativePath is already absolute, no changes will be made //-------------------------------------------------------------------------------------------------- QString RiaApplication::createAbsolutePathFromProjectRelativePath( QString projectRelativePath ) { // Check if path is already absolute if ( QDir::isAbsolutePath( projectRelativePath ) ) { return projectRelativePath; } QString absolutePath; if ( m_project && !m_project->fileName().isEmpty() ) { absolutePath = QFileInfo( m_project->fileName() ).absolutePath(); } else { absolutePath = this->lastUsedDialogDirectory( "BINARY_GRID" ); } QDir projectDir( absolutePath ); return projectDir.absoluteFilePath( projectRelativePath ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RiaApplication::loadProject( const QString& projectFileName, ProjectLoadAction loadAction, RiaProjectModifier* projectModifier ) { // First Close the current project closeProject(); onProjectBeingOpened(); RiaLogging::info( QString( "Starting to open project file : '%1'" ).arg( projectFileName ) ); // Create a absolute path file name, as this is required for update of file references in the project modifier object QString fullPathProjectFileName = caf::Utils::absoluteFileName( projectFileName ); if ( !caf::Utils::fileExists( fullPathProjectFileName ) ) { RiaLogging::info( QString( "File does not exist : '%1'" ).arg( fullPathProjectFileName ) ); return false; } m_project->fileName = fullPathProjectFileName; m_project->readFile(); // Apply any modifications to the loaded project before we go ahead and load actual data if ( projectModifier ) { projectModifier->applyModificationsToProject( m_project ); } // Propagate possible new location of project m_project->setProjectFileNameAndUpdateDependencies( fullPathProjectFileName ); // On error, delete everything, and bail out. if ( m_project->projectFileVersionString().isEmpty() ) { closeProject(); QString errMsg = QString( "Unknown project file version detected in file \n%1\n\nCould not open project." ) .arg( fullPathProjectFileName ); onProjectOpeningError( errMsg ); // Delete all object possibly generated by readFile() delete m_project; m_project = new RimProject; onProjectOpened(); return true; } /////// // Load the external data, and initialize stuff that needs specific ordering // VL check regarding specific order mentioned in comment above... m_preferences->lastUsedProjectFileName = fullPathProjectFileName; m_preferences->writePreferencesToApplicationStore(); for ( size_t oilFieldIdx = 0; oilFieldIdx < m_project->oilFields().size(); oilFieldIdx++ ) { RimOilField* oilField = m_project->oilFields[oilFieldIdx]; RimEclipseCaseCollection* analysisModels = oilField ? oilField->analysisModels() : nullptr; if ( analysisModels == nullptr ) continue; for ( size_t cgIdx = 0; cgIdx < analysisModels->caseGroups.size(); ++cgIdx ) { // Load the Main case of each IdenticalGridCaseGroup RimIdenticalGridCaseGroup* igcg = analysisModels->caseGroups[cgIdx]; igcg->loadMainCaseAndActiveCellInfo(); // VL is this supposed to be done for each RimOilField? } } // Load the formation names for ( RimOilField* oilField : m_project->oilFields ) { if ( oilField == nullptr ) continue; if ( oilField->formationNamesCollection() != nullptr ) { oilField->formationNamesCollection()->readAllFormationNames(); } } // Add well paths for each oil field for ( size_t oilFieldIdx = 0; oilFieldIdx < m_project->oilFields().size(); oilFieldIdx++ ) { RimOilField* oilField = m_project->oilFields[oilFieldIdx]; if ( oilField == nullptr ) continue; if ( oilField->wellPathCollection == nullptr ) { // printf("Create well path collection for oil field %i in loadProject.\n", oilFieldIdx); oilField->wellPathCollection = new RimWellPathCollection(); } if ( oilField->wellPathCollection ) { oilField->wellPathCollection->loadDataAndUpdate(); oilField->wellPathCollection->readWellPathFormationFiles(); } } { RimMainPlotCollection* mainPlotColl = m_project->mainPlotCollection(); mainPlotColl->ensureCalculationIdsAreAssigned(); } for ( RimOilField* oilField : m_project->oilFields ) { if ( oilField == nullptr ) continue; // Temporary if ( !oilField->summaryCaseMainCollection() ) { oilField->summaryCaseMainCollection = new RimSummaryCaseMainCollection(); } oilField->summaryCaseMainCollection()->loadAllSummaryCaseData(); if ( !oilField->observedDataCollection() ) { oilField->observedDataCollection = new RimObservedDataCollection(); } for ( RimObservedSummaryData* observedData : oilField->observedDataCollection()->allObservedSummaryData() ) { observedData->createSummaryReaderInterface(); observedData->createRftReaderInterface(); observedData->updateMetaData(); } for ( RimObservedFmuRftData* observedFmuData : oilField->observedDataCollection()->allObservedFmuRftData() ) { observedFmuData->createRftReaderInterface(); } oilField->fractureDefinitionCollection()->loadAndUpdateData(); oilField->fractureDefinitionCollection()->createAndAssignTemplateCopyForNonMatchingUnit(); { std::vector wellPathFractures; oilField->wellPathCollection->descendantsIncludingThisOfType( wellPathFractures ); for ( auto fracture : wellPathFractures ) { fracture->loadDataAndUpdate(); } } } // If load action is specified to recalculate statistics, do it now. // Apparently this needs to be done before the views are loaded, lest the number of time steps for statistics will be clamped if ( loadAction & PLA_CALCULATE_STATISTICS ) { for ( size_t oilFieldIdx = 0; oilFieldIdx < m_project->oilFields().size(); oilFieldIdx++ ) { RimOilField* oilField = m_project->oilFields[oilFieldIdx]; RimEclipseCaseCollection* analysisModels = oilField ? oilField->analysisModels() : nullptr; if ( analysisModels ) { analysisModels->recomputeStatisticsForAllCaseGroups(); } } } // Now load the ReservoirViews for the cases // Add all "native" cases in the project std::vector casesToLoad; m_project->allCases( casesToLoad ); { caf::ProgressInfo caseProgress( casesToLoad.size(), "Reading Cases" ); for ( size_t cIdx = 0; cIdx < casesToLoad.size(); ++cIdx ) { RimCase* cas = casesToLoad[cIdx]; CVF_ASSERT( cas ); caseProgress.setProgressDescription( cas->caseUserDescription() ); std::vector views = cas->views(); { // To delete the view progress before incrementing the caseProgress caf::ProgressInfo viewProgress( views.size(), "Creating Views" ); size_t j; for ( j = 0; j < views.size(); j++ ) { Rim3dView* riv = views[j]; CVF_ASSERT( riv ); viewProgress.setProgressDescription( riv->name() ); if ( m_project->isProjectFileVersionEqualOrOlderThan( "2018.1.0.103" ) ) { std::vector stimPlanColors; riv->descendantsIncludingThisOfType( stimPlanColors ); if ( stimPlanColors.size() == 1 ) { stimPlanColors[0]->updateConductivityResultName(); } } riv->loadDataAndUpdate(); if ( m_project->isProjectFileVersionEqualOrOlderThan( "2018.1.1.110" ) ) { auto* geoView = dynamic_cast( riv ); if ( geoView ) { geoView->convertCameraPositionFromOldProjectFiles(); } } this->setActiveReservoirView( riv ); RimGridView* rigv = dynamic_cast( riv ); if ( rigv ) rigv->rangeFilterCollection()->updateIconState(); viewProgress.incrementProgress(); } } caseProgress.incrementProgress(); } } if ( m_project->viewLinkerCollection() && m_project->viewLinkerCollection()->viewLinker() ) { m_project->viewLinkerCollection()->viewLinker()->updateOverrides(); } // Intersection Views: Sync from intersections in the case. for ( RimCase* cas : casesToLoad ) { cas->intersectionViewCollection()->syncFromExistingIntersections( false ); } // Init summary case groups for ( RimOilField* oilField : m_project->oilFields ) { auto sumMainCollection = oilField->summaryCaseMainCollection(); if ( !sumMainCollection ) continue; for ( auto sumCaseGroup : sumMainCollection->summaryCaseCollections() ) { sumCaseGroup->loadDataAndUpdate(); } oilField->annotationCollection()->loadDataAndUpdate(); } // Some procedures in onProjectOpened() may rely on the display model having been created // So we need to force the completion of the display model here. RiaViewRedrawScheduler::instance()->updateAndRedrawScheduledViews(); // NB! This function must be called before executing command objects, // because the tree view state is restored from project file and sets // current active view ( see restoreTreeViewState() ) // Default behavior for scripts is to use current active view for data read/write onProjectOpened(); // Loop over command objects and execute them for ( size_t i = 0; i < m_project->commandObjects.size(); i++ ) { m_commandQueue.push_back( m_project->commandObjects[i] ); } // Lock the command queue m_commandQueueLock.lock(); // Execute command objects, and release the mutex when the queue is empty executeCommandObjects(); RiaLogging::info( QString( "Completed open of project file : '%1'" ).arg( projectFileName ) ); return true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RiaApplication::loadProject( const QString& projectFileName ) { return loadProject( projectFileName, PLA_NONE, nullptr ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RiaApplication::saveProject( QString* errorMessage ) { CAF_ASSERT( errorMessage ); CAF_ASSERT( m_project.notNull() ); if ( !isProjectSavedToDisc() ) { *errorMessage = "Project hasn't already been saved and no file name has been provided"; return false; } else { return saveProjectAs( m_project->fileName(), errorMessage ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RiaApplication::saveProjectAs( const QString& fileName, QString* errorMessage ) { // Make sure we always store path with forward slash to avoid issues when opening the project file on Linux m_project->fileName = RiaFilePathTools::toInternalSeparator( fileName ); onProjectBeingSaved(); if ( !m_project->writeProjectFile() ) { CAF_ASSERT( errorMessage ); *errorMessage = QString( "Not possible to save project file. Make sure you have sufficient access " "rights.\n\nProject file location : %1" ) .arg( fileName ); return false; } m_preferences->lastUsedProjectFileName = fileName; m_preferences->writePreferencesToApplicationStore(); onProjectSaved(); return true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RiaApplication::hasValidProjectFileExtension( const QString& fileName ) { if ( fileName.contains( ".rsp", Qt::CaseInsensitive ) || fileName.contains( ".rip", Qt::CaseInsensitive ) ) { return true; } return false; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::closeProject() { onProjectBeingClosed(); terminateProcess(); m_project->close(); m_commandQueue.clear(); onProjectClosed(); caf::PdmUiModelChangeDetector::instance()->reset(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RiaApplication::lastUsedDialogDirectory( const QString& dialogName ) { QString lastUsedDirectory = m_startupDefaultDirectory; auto it = m_fileDialogDefaultDirectories.find( dialogName ); if ( it != m_fileDialogDefaultDirectories.end() ) { lastUsedDirectory = it->second; } return lastUsedDirectory; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RiaApplication::lastUsedDialogDirectoryWithFallback( const QString& dialogName, const QString& fallbackDirectory ) { QString lastUsedDirectory = m_startupDefaultDirectory; if ( !fallbackDirectory.isEmpty() ) { lastUsedDirectory = fallbackDirectory; } auto it = m_fileDialogDefaultDirectories.find( dialogName ); if ( it != m_fileDialogDefaultDirectories.end() ) { lastUsedDirectory = it->second; } return lastUsedDirectory; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RiaApplication::lastUsedDialogDirectoryWithFallbackToProjectFolder( const QString& dialogName ) { return lastUsedDialogDirectoryWithFallback( dialogName, currentProjectPath() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::setLastUsedDialogDirectory( const QString& dialogName, const QString& directory ) { m_fileDialogDefaultDirectories[dialogName] = directory; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RiaApplication::openOdbCaseFromFile( const QString& fileName, bool applyTimeStepFilter ) { if ( !caf::Utils::fileExists( fileName ) ) return false; QFileInfo gridFileName( fileName ); QString caseName = gridFileName.completeBaseName(); RimGeoMechCase* geoMechCase = new RimGeoMechCase(); geoMechCase->setFileName( fileName ); geoMechCase->caseUserDescription = caseName; geoMechCase->setApplyTimeFilter( applyTimeStepFilter ); m_project->assignCaseIdToCase( geoMechCase ); RimGeoMechModels* geoMechModelCollection = m_project->activeOilField() ? m_project->activeOilField()->geoMechModels() : nullptr; // Create the geoMech model container if it is not there already if ( geoMechModelCollection == nullptr ) { geoMechModelCollection = new RimGeoMechModels(); m_project->activeOilField()->geoMechModels = geoMechModelCollection; } RimGeoMechView* riv = geoMechCase->createAndAddReservoirView(); caf::ProgressInfo progress( 11, "Loading Case" ); progress.setNextProgressIncrement( 10 ); riv->loadDataAndUpdate(); if ( !riv->geoMechCase() ) { delete geoMechCase; return false; } geoMechModelCollection->cases.push_back( geoMechCase ); progress.incrementProgress(); progress.setProgressDescription( "Loading results information" ); m_project->updateConnectedEditors(); return true; } //-------------------------------------------------------------------------------------------------- /// Add a list of well path file paths (JSON files) to the well path collection //-------------------------------------------------------------------------------------------------- std::vector RiaApplication::addWellPathsToModel( QList wellPathFilePaths, QStringList* errorMessages ) { CAF_ASSERT( errorMessages ); if ( m_project == nullptr || m_project->oilFields.size() < 1 ) return {}; RimOilField* oilField = m_project->activeOilField(); if ( oilField == nullptr ) return {}; if ( oilField->wellPathCollection == nullptr ) { // printf("Create well path collection.\n"); oilField->wellPathCollection = new RimWellPathCollection(); m_project->updateConnectedEditors(); } std::vector wellPaths; if ( oilField->wellPathCollection ) { wellPaths = oilField->wellPathCollection->addWellPaths( wellPathFilePaths, errorMessages ); } oilField->wellPathCollection->updateConnectedEditors(); return wellPaths; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::addWellPathFormationsToModel( QList wellPathFormationsFilePaths ) { if ( m_project == nullptr || m_project->oilFields.size() < 1 ) return; RimOilField* oilField = m_project->activeOilField(); if ( oilField == nullptr ) return; if ( oilField->wellPathCollection == nullptr ) { oilField->wellPathCollection = new RimWellPathCollection(); m_project->updateConnectedEditors(); } if ( oilField->wellPathCollection ) { oilField->wellPathCollection->addWellPathFormations( wellPathFormationsFilePaths ); } oilField->wellPathCollection->updateConnectedEditors(); } //-------------------------------------------------------------------------------------------------- /// Add a list of well log file paths (LAS files) to the well path collection //-------------------------------------------------------------------------------------------------- std::vector RiaApplication::addWellLogsToModel( const QList& wellLogFilePaths, QStringList* errorMessages ) { CAF_ASSERT( errorMessages ); if ( m_project == nullptr || m_project->oilFields.size() < 1 ) return {}; RimOilField* oilField = m_project->activeOilField(); if ( oilField == nullptr ) return {}; if ( oilField->wellPathCollection == nullptr ) { oilField->wellPathCollection = new RimWellPathCollection(); m_project->updateConnectedEditors(); } std::vector wellLogFiles = oilField->wellPathCollection->addWellLogs( wellLogFilePaths, errorMessages ); oilField->wellPathCollection->updateConnectedEditors(); return wellLogFiles; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RiaApplication::scriptDirectories() const { return m_preferences->scriptDirectories(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RiaApplication::scriptEditorPath() const { return m_preferences->scriptEditorExecutable(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RiaApplication::octavePath() const { return m_preferences->octaveExecutable(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QStringList RiaApplication::octaveArguments() const { // http://www.gnu.org/software/octave/doc/interpreter/Command-Line-Options.html#Command-Line-Options // -p path // Add path to the head of the search path for function files. The value of path specified on the command line // will override any value of OCTAVE_PATH found in the environment, but not any commands in the system or // user startup files that set the internal load path through one of the path functions. QStringList arguments; arguments.append( "--path" ); arguments << QApplication::applicationDirPath(); if ( !m_preferences->octaveShowHeaderInfoWhenExecutingScripts ) { // -q // Don't print the usual greeting and version message at startup. arguments.append( "-q" ); } return arguments; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QProcessEnvironment RiaApplication::octaveProcessEnvironment() const { QProcessEnvironment penv = QProcessEnvironment::systemEnvironment(); #ifdef WIN32 // Octave plugins compiled by ResInsight are dependent on Qt (currently Qt 32-bit only) // Some Octave installations for Windows have included Qt, and some don't. To make sure these plugins always can be // executed, the path to octave_plugin_dependencies is added to global path QString pathString = penv.value( "PATH", "" ); if ( pathString == "" ) pathString = QApplication::applicationDirPath() + "\\octave_plugin_dependencies"; else pathString = QApplication::applicationDirPath() + "\\octave_plugin_dependencies" + ";" + pathString; penv.insert( "PATH", pathString ); #else // Set the LD_LIBRARY_PATH to make the octave plugins find the embedded Qt QString ldPath = penv.value( "LD_LIBRARY_PATH", "" ); if ( ldPath == "" ) ldPath = QApplication::applicationDirPath(); else ldPath = QApplication::applicationDirPath() + ":" + ldPath; penv.insert( "LD_LIBRARY_PATH", ldPath ); #endif return penv; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RiaApplication::pythonPath() const { return m_preferences->pythonExecutable(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QProcessEnvironment RiaApplication::pythonProcessEnvironment() const { QProcessEnvironment penv = QProcessEnvironment::systemEnvironment(); #ifdef ENABLE_GRPC penv.insert( "RESINSIGHT_GRPC_PORT", QString( "%1" ).arg( m_grpcServer->portNumber() ) ); penv.insert( "RESINSIGHT_EXECUTABLE", QCoreApplication::applicationFilePath() ); QStringList ripsLocations; QString separator; #ifdef WIN32 ripsLocations << QCoreApplication::applicationDirPath() + "\\Python" << QCoreApplication::applicationDirPath() + "\\..\\..\\Python"; separator = ";"; #else ripsLocations << QCoreApplication::applicationDirPath() + "/Python" << QCoreApplication::applicationDirPath() + "/../../Python"; separator = ":"; #endif penv.insert( "PYTHONPATH", QString( "%1%2%3" ).arg( penv.value( "PYTHONPATH" ) ).arg( separator ).arg( ripsLocations.join( separator ) ) ); #endif return penv; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RiaApplication::launchProcess( const QString& program, const QStringList& arguments, const QProcessEnvironment& processEnvironment ) { if ( m_workerProcess == nullptr ) { // If multiple cases are present, pop the first case ID from the list and set as current case if ( !m_currentCaseIds.empty() ) { int nextCaseId = m_currentCaseIds.front(); m_currentCaseIds.pop_front(); m_socketServer->setCurrentCaseId( nextCaseId ); } else { // Disable current case concept m_socketServer->setCurrentCaseId( -1 ); } m_runningWorkerProcess = true; m_workerProcess = new caf::UiProcess( QCoreApplication::instance() ); m_workerProcess->setProcessEnvironment( processEnvironment ); QCoreApplication::instance()->connect( m_workerProcess, SIGNAL( finished( int, QProcess::ExitStatus ) ), SLOT( slotWorkerProcessFinished( int, QProcess::ExitStatus ) ) ); startMonitoringWorkProgress( m_workerProcess ); m_workerProcess->start( program, arguments ); // The wait time is a compromise between large wait time when processing many octave runs after each other and // short wait time when starting octave processes interactively int waitTimeMilliseconds = 7 * 1000; if ( !m_workerProcess->waitForStarted( waitTimeMilliseconds ) ) { m_workerProcess->close(); m_workerProcess = nullptr; m_runningWorkerProcess = false; stopMonitoringWorkProgress(); // QMessageBox::warning(m_mainWindow, "Script execution", "Failed to start script executable located at\n" + program); return false; } return true; } else { // QMessageBox::warning(nullptr, // "Script execution", // "An Octave process is still running. Please stop this process before executing a new script."); return false; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RiaApplication::launchProcessForMultipleCases( const QString& program, const QStringList& arguments, const std::vector& caseIds, const QProcessEnvironment& processEnvironment ) { m_currentCaseIds.clear(); std::copy( caseIds.begin(), caseIds.end(), std::back_inserter( m_currentCaseIds ) ); m_currentProgram = program; m_currentArguments = arguments; return launchProcess( m_currentProgram, m_currentArguments, processEnvironment ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::terminateProcess() { if ( m_workerProcess ) { m_workerProcess->close(); } m_runningWorkerProcess = false; m_workerProcess = nullptr; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::waitForProcess() const { while ( m_runningWorkerProcess ) { #ifdef WIN32 Sleep( 100 ); #else usleep( 100000 ); #endif QCoreApplication::processEvents(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiaPreferences* RiaApplication::preferences() { return m_preferences; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::applyPreferences() { // The creation of a font is time consuming, so make sure you really need your own font // instead of using the application font std::map fontSizes = m_preferences->defaultFontSizes(); m_defaultSceneFont = RiaFontCache::getFont( fontSizes[RiaDefines::SCENE_FONT] ); m_defaultAnnotationFont = RiaFontCache::getFont( fontSizes[RiaDefines::ANNOTATION_FONT] ); m_defaultWellLabelFont = RiaFontCache::getFont( fontSizes[RiaDefines::WELL_LABEL_FONT] ); if ( this->project() ) { this->project()->setScriptDirectories( m_preferences->scriptDirectories() ); this->project()->setPlotTemplateFolders( m_preferences->plotTemplateFolders() ); this->project()->updateConnectedEditors(); } m_preferences->writePreferencesToApplicationStore(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RiaApplication::commandLineParameterHelp() { QString helpText = QString( "\n%1 v. %2\n" ).arg( RI_APPLICATION_NAME ).arg( RiaApplication::getVersionStringApp( false ) ); helpText += "Copyright Equinor ASA, Ceetron Solution AS, Ceetron AS\n\n"; helpText += m_commandLineHelpText; return helpText; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::setCacheDataObject( const QString& key, const QVariant& dataObject ) { m_sessionCache[key] = dataObject; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QVariant RiaApplication::cacheDataObject( const QString& key ) const { QMap::const_iterator it = m_sessionCache.find( key ); if ( it != m_sessionCache.end() ) { return it.value(); } return QVariant(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::executeCommandFile( const QString& commandFile ) { QFile file( commandFile ); RicfMessages messages; if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) { // TODO : Error logging? return; } QTextStream in( &file ); RicfCommandFileExecutor::instance()->executeCommands( in ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::addCommandObject( RimCommandObject* commandObject ) { m_commandQueue.push_back( commandObject ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::executeCommandObjects() { { std::list::iterator it = m_commandQueue.begin(); while ( it != m_commandQueue.end() ) { RimCommandObject* toBeRemoved = *it; if ( !toBeRemoved->isAsyncronous() ) { toBeRemoved->redo(); ++it; m_commandQueue.remove( toBeRemoved ); } else { ++it; } } } if ( !m_commandQueue.empty() ) { std::list::iterator it = m_commandQueue.begin(); RimCommandObject* first = *it; first->redo(); m_commandQueue.pop_front(); } else { // Unlock the command queue lock when the command queue is empty // Required to lock the mutex before unlocking to avoid undefined behavior m_commandQueueLock.tryLock(); m_commandQueueLock.unlock(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::waitUntilCommandObjectsHasBeenProcessed() { // Wait until all command objects have completed bool mutexLockedSuccessfully = m_commandQueueLock.tryLock(); while ( !mutexLockedSuccessfully ) { invokeProcessEvents(); mutexLockedSuccessfully = m_commandQueueLock.tryLock(); } m_commandQueueLock.unlock(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int RiaApplication::launchUnitTests() { #ifdef USE_UNIT_TESTS caf::ProgressInfoBlocker progressBlocker; cvf::Assert::setReportMode( cvf::Assert::CONSOLE ); #if QT_VERSION < 0x050000 int argc = QCoreApplication::argc(); char** argv = QCoreApplication::argv(); #else int argc = QCoreApplication::arguments().size(); QStringList arguments = QCoreApplication::arguments(); std::vector argumentsStd; for ( QString qstring : arguments ) { argumentsStd.push_back( qstring.toStdString() ); } std::vector argVector; for ( std::string& string : argumentsStd ) { argVector.push_back( &string.front() ); } char** argv = argVector.data(); #endif testing::InitGoogleTest( &argc, argv ); // Use this macro in main() to run all tests. It returns 0 if all // tests are successful, or 1 otherwise. // // RUN_ALL_TESTS() should be invoked after the command line has been // parsed by InitGoogleTest(). return RUN_ALL_TESTS(); #else return -1; #endif } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const QString RiaApplication::startDir() const { return m_startupDefaultDirectory; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::setStartDir( const QString& startDir ) { m_startupDefaultDirectory = startDir; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::setCommandLineHelpText( const QString& commandLineHelpText ) { m_commandLineHelpText = commandLineHelpText; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RiaApplication::readFileListFromTextFile( QString listFileName ) { std::vector fileList; QFile file( listFileName ); if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) { return fileList; } QTextStream in( &file ); QString line = in.readLine(); while ( !line.isNull() ) { line = line.trimmed(); if ( !line.isEmpty() ) { fileList.push_back( line ); } line = in.readLine(); } return fileList; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Font* RiaApplication::defaultSceneFont() { CVF_ASSERT( m_defaultSceneFont.notNull() ); // The creation of a font is time consuming, so make sure you really need your own font // instead of using the application font return m_defaultSceneFont.p(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Font* RiaApplication::defaultAnnotationFont() { CVF_ASSERT( m_defaultAnnotationFont.notNull() ); return m_defaultAnnotationFont.p(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Font* RiaApplication::defaultWellLabelFont() { CVF_ASSERT( m_defaultWellLabelFont.notNull() ); return m_defaultWellLabelFont.p(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RiaApplication::initializeGrpcServer( const cvf::ProgramOptions& progOpt ) { #ifdef ENABLE_GRPC if ( !m_preferences->enableGrpcServer() ) return false; int defaultPortNumber = m_preferences->defaultGrpcPortNumber(); bool fixedPort = false; if ( cvf::Option o = progOpt.option( "server" ) ) { if ( o.valueCount() == 1 ) { defaultPortNumber = o.value( 0 ).toInt( defaultPortNumber ); fixedPort = true; } } int portNumber = defaultPortNumber; if ( !fixedPort ) { portNumber = RiaGrpcServer::findAvailablePortNumber( defaultPortNumber ); } m_grpcServer.reset( new RiaGrpcServer( portNumber ) ); return true; #else return false; #endif } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiaApplication::initialize() { m_preferences = new RiaPreferences; caf::PdmSettings::readFieldsFromApplicationStore( m_preferences ); m_preferences->initAfterReadRecursively(); applyPreferences(); // Start with a project m_project = new RimProject; m_project->setScriptDirectories( m_preferences->scriptDirectories() ); m_project->setPlotTemplateFolders( m_preferences->plotTemplateFolders() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int RiaApplication::launchUnitTestsWithConsole() { return launchUnitTests(); }