Improve progress info summary

Use task system to improve the progress info experience. Remove progress info for well picks to reduce number of progress bars.
This commit is contained in:
Magne Sjaastad
2025-07-20 08:28:15 +02:00
parent df09b1d84e
commit e50835c77f
2 changed files with 321 additions and 297 deletions
+321 -292
View File
@@ -467,375 +467,404 @@ QString RiaApplication::createAbsolutePathFromProjectRelativePath( QString proje
//--------------------------------------------------------------------------------------------------
bool RiaApplication::loadProject( const QString& projectFileName, ProjectLoadAction loadAction, RiaProjectModifier* projectModifier )
{
bool showDebugTiming = false;
if ( showDebugTiming )
{
QString timingText = "RiaApplication::loadProject";
RiaLogging::resetTimer( timingText );
}
// First Close the current project
caf::ProgressInfo progress( 7, "Loading Project File" );
progress.setProgressDescription( "Reading Project Structure from File" );
caf::ProgressInfo progress( 100, "Loading Project File" );
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;
}
auto task = progress.task( "Reading Project Structure from File", 10 );
m_project->setFileName( fullPathProjectFileName );
m_project->readFile();
m_project->updatesAfterProjectFileIsRead();
// Apply any modifications to the loaded project before we go ahead and load actual data
if ( projectModifier )
{
projectModifier->applyModificationsToProject( m_project.get() );
}
// 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 );
onProjectBeingOpened();
onProjectOpeningError( errMsg );
RiaLogging::info( QString( "Starting to open project file : '%1'" ).arg( projectFileName ) );
// Delete all object possibly generated by readFile()
m_project = std::make_unique<RimProject>();
onProjectOpened();
return true;
}
// At this point, all the file paths variables are replaced and all file paths updated to the new location. This will enable use of file
// paths in initAfterRead().
m_project->resolveReferencesRecursively();
m_project->initAfterReadRecursively();
if ( RimProject::current()->isProjectFileVersionEqualOrOlderThan( "2024.09.2" ) )
{
// Traverse objects recursively and add quick access fields for old projects
RimQuickAccessCollection::instance()->addQuickAccessFieldsRecursively( m_project.get() );
}
// Migrate all RimGridCases to RimFileSummaryCase
RimGridSummaryCase_obsolete::convertGridCasesToSummaryFileCases( m_project.get() );
///////
// Load the external data, and initialize stuff that needs specific ordering
// VL check regarding specific order mentioned in comment above...
m_preferences->lastUsedProjectFileName = fullPathProjectFileName;
if ( m_preferencesFileName.isEmpty() )
{
m_preferences->writePreferencesToApplicationStore();
}
progress.incrementProgress();
progress.setProgressDescription( "Loading Grid Data" );
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 )
// 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 ) )
{
// 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();
}
}
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 )
{
oilField->wellPathCollection = std::make_unique<RimWellPathCollection>();
RiaLogging::info( QString( "File does not exist : '%1'" ).arg( fullPathProjectFileName ) );
return false;
}
// Initialize well paths
if ( !oilField->wellPathCollection->loadDataAndUpdate() )
m_project->setFileName( fullPathProjectFileName );
m_project->readFile();
m_project->updatesAfterProjectFileIsRead();
// Apply any modifications to the loaded project before we go ahead and load actual data
if ( projectModifier )
{
projectModifier->applyModificationsToProject( m_project.get() );
}
// Propagate possible new location of project
m_project->setProjectFileNameAndUpdateDependencies( fullPathProjectFileName );
// On error, delete everything, and bail out.
if ( m_project->projectFileVersionString().isEmpty() )
{
// Opening well path was cancelled or failed: close project.
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()
m_project = std::make_unique<RimProject>();
onProjectOpened();
return true;
}
oilField->ensembleWellLogsCollection->loadDataAndUpdate();
oilField->vfpDataCollection->loadDataAndUpdate();
// At this point, all the file paths variables are replaced and all file paths updated to the new location. This will enable use of
// file paths in initAfterRead().
m_project->resolveReferencesRecursively();
m_project->initAfterReadRecursively();
// Initialize seismic data
auto& seisDataColl = oilField->seismicDataCollection();
for ( auto seismicData : seisDataColl->seismicData() )
if ( RimProject::current()->isProjectFileVersionEqualOrOlderThan( "2024.09.2" ) )
{
seismicData->ensureFileReaderIsInitialized();
// Traverse objects recursively and add quick access fields for old projects
RimQuickAccessCollection::instance()->addQuickAccessFieldsRecursively( m_project.get() );
}
oilField->polygonCollection()->loadData();
// Migrate all RimGridCases to RimFileSummaryCase
RimGridSummaryCase_obsolete::convertGridCasesToSummaryFileCases( m_project.get() );
///////
// Load the external data, and initialize stuff that needs specific ordering
// VL check regarding specific order mentioned in comment above...
m_preferences->lastUsedProjectFileName = fullPathProjectFileName;
if ( m_preferencesFileName.isEmpty() )
{
m_preferences->writePreferencesToApplicationStore();
}
}
progress.incrementProgress();
progress.setProgressDescription( "Loading 2D Plot Data" );
{
RimMainPlotCollection* mainPlotColl = RimMainPlotCollection::current();
mainPlotColl->ensureDefaultFlowPlotsAreCreated();
auto task = progress.task( "Loading Grid Data", 10 );
// RimVfpTable are not presisted in the project file, and are created in vfpDataCollection->loadDataAndUpdate(). Existing VFP
// plots will have references to RimVfpTables. Call resolveReferencesRecursively() to update the references to RimVfpTable objects.
mainPlotColl->vfpPlotCollection()->resolveReferencesRecursively();
}
for ( RimOilField* oilField : m_project->oilFields )
{
if ( oilField == nullptr ) continue;
// Temporary
if ( !oilField->summaryCaseMainCollection() )
{
oilField->summaryCaseMainCollection = std::make_unique<RimSummaryCaseMainCollection>();
}
oilField->summaryCaseMainCollection()->loadAllSummaryCaseData();
m_project->calculationCollection()->rebuildCaseMetaData();
if ( !oilField->observedDataCollection() )
{
oilField->observedDataCollection = std::make_unique<RimObservedDataCollection>();
}
for ( RimObservedSummaryData* observedData : oilField->observedDataCollection()->allObservedSummaryData() )
{
observedData->createSummaryReaderInterface();
observedData->createRftReaderInterface();
observedData->updateMetaData();
}
for ( RimObservedFmuRftData* observedFmuData : oilField->observedDataCollection()->allObservedFmuRftData() )
{
observedFmuData->createRftReaderInterface();
}
oilField->completionTemplateCollection()->loadAndUpdateData();
oilField->fractureDefinitionCollection()->createAndAssignTemplateCopyForNonMatchingUnit();
{
std::vector<RimWellPathFracture*> wellPathFractures =
oilField->wellPathCollection->descendantsIncludingThisOfType<RimWellPathFracture>();
for ( auto fracture : wellPathFractures )
{
fracture->loadDataAndUpdate();
}
}
oilField->surfaceCollection()->loadData();
}
progress.incrementProgress();
progress.setProgressDescription( "Calculation Grid Statistics" );
// 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 == ProjectLoadAction::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 )
if ( analysisModels == nullptr ) continue;
for ( size_t cgIdx = 0; cgIdx < analysisModels->caseGroups.size(); ++cgIdx )
{
analysisModels->recomputeStatisticsForAllCaseGroups();
// Load the Main case of each IdenticalGridCaseGroup
RimIdenticalGridCaseGroup* igcg = analysisModels->caseGroups[cgIdx];
igcg->loadMainCaseAndActiveCellInfo(); // VL is this supposed to be done for each RimOilField?
}
}
}
progress.incrementProgress();
progress.setProgressDescription( "Create 3D Views" );
// Load the formation names
// Now load the ReservoirViews for the cases
// Add all "native" cases in the project
std::vector<RimCase*> casesToLoad = m_project->allGridCases();
{
caf::ProgressInfo caseProgress( casesToLoad.size(), "Reading Cases" );
for ( size_t cIdx = 0; cIdx < casesToLoad.size(); ++cIdx )
for ( RimOilField* oilField : m_project->oilFields )
{
RimCase* cas = casesToLoad[cIdx];
CVF_ASSERT( cas );
if ( oilField == nullptr ) continue;
if ( oilField->formationNamesCollection() != nullptr )
{
oilField->formationNamesCollection()->readAllFormationNames();
}
}
// Make sure case name is updated. It can be out-of-sync if the
// user has updated the project file manually.
cas->updateAutoShortName();
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 )
{
oilField->wellPathCollection = std::make_unique<RimWellPathCollection>();
}
caseProgress.setProgressDescription( cas->caseUserDescription() );
std::vector<Rim3dView*> views = cas->views();
{ // To delete the view progress before incrementing the caseProgress
caf::ProgressInfo viewProgress( views.size(), "Creating Views" );
// Initialize well paths
if ( !oilField->wellPathCollection->loadDataAndUpdate() )
{
// Opening well path was cancelled or failed: close project.
closeProject();
m_project = std::make_unique<RimProject>();
onProjectOpened();
return true;
}
size_t j;
for ( j = 0; j < views.size(); j++ )
oilField->ensembleWellLogsCollection->loadDataAndUpdate();
oilField->vfpDataCollection->loadDataAndUpdate();
// Initialize seismic data
auto& seisDataColl = oilField->seismicDataCollection();
for ( auto seismicData : seisDataColl->seismicData() )
{
seismicData->ensureFileReaderIsInitialized();
}
oilField->polygonCollection()->loadData();
}
}
{
auto task = progress.task( "Loading 2D Plot Data", 10 );
{
RimMainPlotCollection* mainPlotColl = RimMainPlotCollection::current();
mainPlotColl->ensureDefaultFlowPlotsAreCreated();
// RimVfpTable are not presisted in the project file, and are created in vfpDataCollection->loadDataAndUpdate(). Existing VFP
// plots will have references to RimVfpTables. Call resolveReferencesRecursively() to update the references to RimVfpTable objects.
mainPlotColl->vfpPlotCollection()->resolveReferencesRecursively();
}
for ( RimOilField* oilField : m_project->oilFields )
{
if ( oilField == nullptr ) continue;
// Temporary
if ( !oilField->summaryCaseMainCollection() )
{
oilField->summaryCaseMainCollection = std::make_unique<RimSummaryCaseMainCollection>();
}
oilField->summaryCaseMainCollection()->loadAllSummaryCaseData();
m_project->calculationCollection()->rebuildCaseMetaData();
if ( !oilField->observedDataCollection() )
{
oilField->observedDataCollection = std::make_unique<RimObservedDataCollection>();
}
for ( RimObservedSummaryData* observedData : oilField->observedDataCollection()->allObservedSummaryData() )
{
observedData->createSummaryReaderInterface();
observedData->createRftReaderInterface();
observedData->updateMetaData();
}
for ( RimObservedFmuRftData* observedFmuData : oilField->observedDataCollection()->allObservedFmuRftData() )
{
observedFmuData->createRftReaderInterface();
}
oilField->completionTemplateCollection()->loadAndUpdateData();
oilField->fractureDefinitionCollection()->createAndAssignTemplateCopyForNonMatchingUnit();
{
std::vector<RimWellPathFracture*> wellPathFractures =
oilField->wellPathCollection->descendantsIncludingThisOfType<RimWellPathFracture>();
for ( auto fracture : wellPathFractures )
{
Rim3dView* riv = views[j];
CVF_ASSERT( riv );
viewProgress.setProgressDescription( riv->name() );
if ( m_project->isProjectFileVersionEqualOrOlderThan( "2018.1.0.103" ) )
{
std::vector<RimStimPlanColors*> stimPlanColors = riv->descendantsIncludingThisOfType<RimStimPlanColors>();
if ( stimPlanColors.size() == 1 )
{
stimPlanColors[0]->updateConductivityResultName();
}
}
riv->loadDataAndUpdate();
if ( m_project->isProjectFileVersionEqualOrOlderThan( "2018.1.1.110" ) )
{
auto* geoView = dynamic_cast<RimGeoMechView*>( riv );
if ( geoView )
{
geoView->convertCameraPositionFromOldProjectFiles();
}
}
if ( riv->showWindow() )
{
setActiveReservoirView( riv );
}
RimGridView* rigv = dynamic_cast<RimGridView*>( riv );
if ( rigv ) rigv->cellFilterCollection()->updateIconState();
viewProgress.incrementProgress();
fracture->loadDataAndUpdate();
}
}
caseProgress.incrementProgress();
oilField->surfaceCollection()->loadData();
}
}
// Load all grid ensemble views
{
auto gridCaseEnsembles = m_project->activeOilField()->analysisModels()->caseEnsembles.childrenByType();
auto task = progress.task( "Calculation Grid Statistics", 10 );
for ( auto gridCaseEnsemble : gridCaseEnsembles )
// 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 == ProjectLoadAction::PLA_CALCULATE_STATISTICS )
{
auto views = gridCaseEnsemble->viewCollection()->views();
for ( auto view : views )
for ( size_t oilFieldIdx = 0; oilFieldIdx < m_project->oilFields().size(); oilFieldIdx++ )
{
view->loadDataAndUpdate();
RimOilField* oilField = m_project->oilFields[oilFieldIdx];
RimEclipseCaseCollection* analysisModels = oilField ? oilField->analysisModels() : nullptr;
if ( analysisModels )
{
analysisModels->recomputeStatisticsForAllCaseGroups();
}
}
}
}
if ( m_project->viewLinkerCollection() && m_project->viewLinkerCollection()->viewLinker() )
{
m_project->viewLinkerCollection()->viewLinker()->updateOverrides();
}
auto task = progress.task( "Creating 3D Views", 10 );
// Intersection Views: Sync from intersections in the case.
for ( RimCase* cas : casesToLoad )
{
cas->intersectionViewCollection()->syncFromExistingIntersections( false );
}
{
for ( auto view : m_project->allViews() )
// Now load the ReservoirViews for the cases
// Add all "native" cases in the project
std::vector<RimCase*> casesToLoad = m_project->allGridCases();
{
if ( auto eclipseView = dynamic_cast<RimEclipseView*>( view ) )
caf::ProgressInfo caseProgress( casesToLoad.size(), "Reading Cases" );
for ( size_t cIdx = 0; cIdx < casesToLoad.size(); ++cIdx )
{
eclipseView->faultReactivationModelCollection()->loadDataAndUpdate();
RimCase* cas = casesToLoad[cIdx];
CVF_ASSERT( cas );
// Make sure case name is updated. It can be out-of-sync if the
// user has updated the project file manually.
cas->updateAutoShortName();
caseProgress.setProgressDescription( cas->caseUserDescription() );
std::vector<Rim3dView*> 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<RimStimPlanColors*> stimPlanColors = riv->descendantsIncludingThisOfType<RimStimPlanColors>();
if ( stimPlanColors.size() == 1 )
{
stimPlanColors[0]->updateConductivityResultName();
}
}
riv->loadDataAndUpdate();
if ( m_project->isProjectFileVersionEqualOrOlderThan( "2018.1.1.110" ) )
{
auto* geoView = dynamic_cast<RimGeoMechView*>( riv );
if ( geoView )
{
geoView->convertCameraPositionFromOldProjectFiles();
}
}
if ( riv->showWindow() )
{
setActiveReservoirView( riv );
}
RimGridView* rigv = dynamic_cast<RimGridView*>( riv );
if ( rigv ) rigv->cellFilterCollection()->updateIconState();
viewProgress.incrementProgress();
}
}
caseProgress.incrementProgress();
}
}
// Load all grid ensemble views
{
auto gridCaseEnsembles = m_project->activeOilField()->analysisModels()->caseEnsembles.childrenByType();
for ( auto gridCaseEnsemble : gridCaseEnsembles )
{
auto views = gridCaseEnsemble->viewCollection()->views();
for ( auto view : views )
{
view->loadDataAndUpdate();
}
}
}
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 );
}
{
for ( auto view : m_project->allViews() )
{
if ( auto eclipseView = dynamic_cast<RimEclipseView*>( view ) )
{
eclipseView->faultReactivationModelCollection()->loadDataAndUpdate();
}
}
}
for ( RimOilField* oilField : m_project->oilFields )
{
for ( auto seisView : oilField->seismicViewCollection()->views() )
{
seisView->loadDataAndUpdate();
}
}
}
for ( RimOilField* oilField : m_project->oilFields )
{
for ( auto seisView : oilField->seismicViewCollection()->views() )
const int taskSteps = 30;
// Init summary case groups
for ( RimOilField* oilField : m_project->oilFields )
{
seisView->loadDataAndUpdate();
auto sumMainCollection = oilField->summaryCaseMainCollection();
if ( !sumMainCollection ) continue;
sumMainCollection->updateAutoShortName();
int stepSize = 1;
if ( sumMainCollection->summaryEnsembles().size() > 0 )
{
stepSize = std::max( 1, int( taskSteps / sumMainCollection->summaryEnsembles().size() ) );
}
for ( auto ensemble : sumMainCollection->summaryEnsembles() )
{
auto ensembleTask = progress.task( QString( "Loading Summary Ensemble '%1'" ).arg( ensemble->name() ), stepSize );
ensemble->loadDataAndUpdate();
RiaLogging::info( QString( "Loaded ensemble : '%1'" ).arg( ensemble->name() ) );
}
sumMainCollection->updateEnsembleNames();
for ( auto well : oilField->wellPathCollection()->allWellPaths() )
{
for ( auto stimPlan : well->stimPlanModelCollection()->allStimPlanModels() )
stimPlan->resetAnchorPositionAndThicknessDirection();
}
}
// 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();
}
progress.incrementProgress();
progress.setProgressDescription( "Load Summary Data" );
// Init summary case groups
for ( RimOilField* oilField : m_project->oilFields )
{
auto sumMainCollection = oilField->summaryCaseMainCollection();
if ( !sumMainCollection ) continue;
auto task = progress.task( "Performing Grid Calculations", 10 );
sumMainCollection->updateAutoShortName();
for ( auto ensemble : sumMainCollection->summaryEnsembles() )
// Recalculate the results from grid property calculations.
// Has to be done late since the results are filtered by view cell visibility
for ( auto gridCalculation : m_project->gridCalculationCollection()->sortedGridCalculations() )
{
ensemble->loadDataAndUpdate();
gridCalculation->calculate();
gridCalculation->updateDependentObjects();
}
sumMainCollection->updateEnsembleNames();
for ( auto well : oilField->wellPathCollection()->allWellPaths() )
{
for ( auto stimPlan : well->stimPlanModelCollection()->allStimPlanModels() )
stimPlan->resetAnchorPositionAndThicknessDirection();
}
RiaPlotWindowRedrawScheduler::instance()->performScheduledUpdates();
RiaLogging::info( QString( "Completed open of project file : '%1'" ).arg( projectFileName ) );
}
// 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();
progress.incrementProgress();
progress.setProgressDescription( "Performing Grid Calculations" );
// Recalculate the results from grid property calculations.
// Has to be done late since the results are filtered by view cell visibility
for ( auto gridCalculation : m_project->gridCalculationCollection()->sortedGridCalculations() )
if ( showDebugTiming )
{
gridCalculation->calculate();
gridCalculation->updateDependentObjects();
RiaLogging::logTimeElapsed( "" );
}
RiaPlotWindowRedrawScheduler::instance()->performScheduledUpdates();
RiaLogging::info( QString( "Completed open of project file : '%1'" ).arg( projectFileName ) );
return true;
}