///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2023 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 "RimFaultReactivationDataAccess.h" #include "RiaDefines.h" #include "RiaPorosityModel.h" #include "RigCaseCellResultsData.h" #include "RigCaseToCaseCellMapperTools.h" #include "RigEclipseCaseData.h" #include "RigEclipseResultAddress.h" #include "RigFault.h" #include "RigFaultReactivationModel.h" #include "RigGriddedPart3d.h" #include "RigMainGrid.h" #include "RigResultAccessorFactory.h" #include "RimEclipseCase.h" #include "RimFaultReactivationDataAccessor.h" #include "RimFaultReactivationDataAccessorGeoMech.h" #include "RimFaultReactivationDataAccessorPorePressure.h" #include "RimFaultReactivationDataAccessorStress.h" #include "RimFaultReactivationDataAccessorTemperature.h" #include "RimFaultReactivationDataAccessorVoidRatio.h" #include "RimFaultReactivationEnums.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimFaultReactivationDataAccess::RimFaultReactivationDataAccess( RimEclipseCase* thecase, RimGeoMechCase* geoMechCase, const std::vector& timeSteps ) : m_timeSteps( timeSteps ) { // TODO: correct default pore pressure gradient? m_accessors.push_back( std::make_shared( thecase, 1.0 ) ); m_accessors.push_back( std::make_shared( thecase, 0.0001 ) ); m_accessors.push_back( std::make_shared( thecase ) ); if ( geoMechCase ) { std::vector properties = { RimFaultReactivation::Property::YoungsModulus, RimFaultReactivation::Property::PoissonsRatio, RimFaultReactivation::Property::Density }; for ( auto property : properties ) { m_accessors.push_back( std::make_shared( geoMechCase, property ) ); } std::vector stressProperties = { RimFaultReactivation::Property::StressTop, RimFaultReactivation::Property::DepthTop, RimFaultReactivation::Property::StressBottom, RimFaultReactivation::Property::DepthBottom, RimFaultReactivation::Property::LateralStressComponentX, RimFaultReactivation::Property::LateralStressComponentY }; for ( auto property : stressProperties ) { m_accessors.push_back( std::make_shared( geoMechCase, property, 0.003 ) ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimFaultReactivationDataAccess::~RimFaultReactivationDataAccess() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimFaultReactivationDataAccess::propertyValues( RimFaultReactivation::GridPart gridPart, RimFaultReactivation::Property property, size_t outputTimeStep ) const { const auto it = m_propertyValues.find( { gridPart, property } ); if ( it == m_propertyValues.end() || outputTimeStep >= it->second.size() ) return {}; return it->second[outputTimeStep]; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationDataAccess::clearModelData() { m_accessors.clear(); m_propertyValues.clear(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimFaultReactivationDataAccess::extractModelData( const RigFaultReactivationModel& model, RimFaultReactivation::GridPart gridPart, RimFaultReactivation::Property property, size_t timeStep ) { std::set nodeProperties = { RimFaultReactivation::Property::PorePressure, RimFaultReactivation::Property::VoidRatio, RimFaultReactivation::Property::Temperature }; auto computeAverageDepth = []( const std::vector& positions, const std::vector& indices ) { double sum = 0.0; for ( size_t idx : indices ) sum += positions[idx].z(); return sum / indices.size(); }; std::shared_ptr accessor = getAccessor( property ); if ( accessor ) { accessor->setModelAndTimeStep( model, timeStep ); auto grid = model.grid( gridPart ); const std::map>& borderSurfaceElements = grid->borderSurfaceElements(); auto it = borderSurfaceElements.find( RimFaultReactivation::BorderSurface::Seabed ); CAF_ASSERT( it != borderSurfaceElements.end() && "Sea bed border surface does not exist" ); std::set seabedElements( it->second.begin(), it->second.end() ); std::vector values; if ( nodeProperties.contains( property ) ) { for ( auto& node : grid->globalNodes() ) { double value = accessor->valueAtPosition( node, model, gridPart ); values.push_back( value ); } } else { size_t numElements = grid->elementIndices().size(); for ( size_t elementIndex = 0; elementIndex < numElements; elementIndex++ ) { std::vector corners = grid->elementCorners( elementIndex ); // Move top of sea bed element down to end up inside top element bool isTopElement = seabedElements.contains( static_cast( elementIndex ) ); double topDepthAdjust = isTopElement ? 0.1 : 0.0; double topDepth = computeAverageDepth( corners, { 0, 1, 2, 3 } ) - topDepthAdjust; double bottomDepth = computeAverageDepth( corners, { 4, 5, 6, 7 } ); cvf::Vec3d position = RigCaseToCaseCellMapperTools::calculateCellCenter( corners.data() ); double value = accessor->valueAtPosition( position, model, gridPart, topDepth, bottomDepth, elementIndex ); values.push_back( value ); } } return values; } return {}; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimFaultReactivationDataAccess::extractModelData( const RigFaultReactivationModel& model ) { auto properties = { RimFaultReactivation::Property::PorePressure, RimFaultReactivation::Property::VoidRatio, RimFaultReactivation::Property::Temperature, RimFaultReactivation::Property::YoungsModulus, RimFaultReactivation::Property::PoissonsRatio, RimFaultReactivation::Property::Density, RimFaultReactivation::Property::StressTop, RimFaultReactivation::Property::DepthTop, RimFaultReactivation::Property::StressBottom, RimFaultReactivation::Property::DepthBottom, RimFaultReactivation::Property::LateralStressComponentX, RimFaultReactivation::Property::LateralStressComponentY }; for ( auto property : properties ) { for ( auto part : model.allGridParts() ) { std::vector> dataForAllTimeSteps; for ( size_t timeStep : m_timeSteps ) { dataForAllTimeSteps.push_back( extractModelData( model, part, property, timeStep ) ); } m_propertyValues[{ part, property }] = dataForAllTimeSteps; } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::shared_ptr RimFaultReactivationDataAccess::getAccessor( RimFaultReactivation::Property property ) const { for ( auto accessor : m_accessors ) if ( accessor->isMatching( property ) ) return accessor; return nullptr; }