mirror of
https://github.com/OPM/ResInsight.git
synced 2026-08-27 05:37:21 -05:00
Replace the monolithic RigNonUniformRefinement class with a proper polymorphic hierarchy: RigRefinement (abstract base), RigNoRefinement (identity), RigUniformRefinement (O(1) uniform), and RigNonUniformRefinement (per-cell custom fractions). Ownership uses std::unique_ptr<RigRefinement>, consumers receive const RigRefinement&. This eliminates the misleading class name, removes effectiveRefinement() indirection, and gives each refinement mode an appropriately optimized implementation.
192 lines
8.1 KiB
C++
192 lines
8.1 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2026- Equinor ASA
|
|
//
|
|
// ResInsight is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
|
// for more details.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "RigNonUniformRefinement.h"
|
|
|
|
#include <algorithm>
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RigNonUniformRefinement::RigNonUniformRefinement( const cvf::Vec3st& sectorSize )
|
|
: m_sectorSize( sectorSize )
|
|
{
|
|
// Initialize each cell with default {1.0} (no refinement)
|
|
for ( auto dim : { DimI, DimJ, DimK } )
|
|
{
|
|
m_fractions[dim].resize( m_sectorSize[dim], std::vector<double>{ 1.0 } );
|
|
rebuildOffsets( dim );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::unique_ptr<RigRefinement> RigNonUniformRefinement::clone() const
|
|
{
|
|
return std::make_unique<RigNonUniformRefinement>( *this );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigNonUniformRefinement::setCumulativeFractions( Dimension dim, size_t origIndex, const std::vector<double>& cumulativeFractions )
|
|
{
|
|
if ( origIndex >= m_sectorSize[dim] ) return;
|
|
|
|
m_fractions[dim][origIndex] = cumulativeFractions;
|
|
rebuildOffsets( dim );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
size_t RigNonUniformRefinement::subcellCount( Dimension dim, size_t origIndex ) const
|
|
{
|
|
if ( origIndex >= m_sectorSize[dim] ) return 1;
|
|
return m_fractions[dim][origIndex].size();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
size_t RigNonUniformRefinement::cumulativeOffset( Dimension dim, size_t origIndex ) const
|
|
{
|
|
// Allow origIndex == m_sectorSize[dim] to get the total count (end sentinel)
|
|
if ( origIndex > m_sectorSize[dim] ) return 0;
|
|
return m_offsets[dim][origIndex];
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
size_t RigNonUniformRefinement::totalRefinedCount( Dimension dim ) const
|
|
{
|
|
if ( m_sectorSize[dim] == 0 ) return 0;
|
|
return m_offsets[dim][m_sectorSize[dim]];
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Maps a refined index back to {originalIndex, subIndex} using binary search on the offset table
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::pair<size_t, size_t> RigNonUniformRefinement::mapRefinedToOriginal( Dimension dim, size_t refinedIndex ) const
|
|
{
|
|
if ( m_sectorSize[dim] == 0 ) return { 0, 0 };
|
|
|
|
// Binary search: find the largest origIndex such that m_offsets[dim][origIndex] <= refinedIndex
|
|
// m_offsets[dim] has size m_sectorSize[dim]+1
|
|
// We want upper_bound - 1
|
|
auto it = std::upper_bound( m_offsets[dim].begin(), m_offsets[dim].end(), refinedIndex );
|
|
size_t origIndex = static_cast<size_t>( std::distance( m_offsets[dim].begin(), it ) ) - 1;
|
|
|
|
size_t subIndex = refinedIndex - m_offsets[dim][origIndex];
|
|
return { origIndex, subIndex };
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const std::vector<double>& RigNonUniformRefinement::cumulativeFractions( Dimension dim, size_t origIndex ) const
|
|
{
|
|
static const std::vector<double> defaultFraction = { 1.0 };
|
|
if ( origIndex >= m_sectorSize[dim] ) return defaultFraction;
|
|
return m_fractions[dim][origIndex];
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
size_t RigNonUniformRefinement::sectorSize( Dimension dim ) const
|
|
{
|
|
return m_sectorSize[dim];
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Distribute fractional widths across a range of cells.
|
|
///
|
|
/// The widths define subdivision boundaries in the combined range of cells [startIndex, endIndex].
|
|
/// Each original cell occupies 1/numCells of the global range (in index space).
|
|
/// Global subdivision boundaries that fall within a cell are converted to cell-local fractions.
|
|
///
|
|
/// Example: 3 cells, widths [0.2, 0.3, 0.5] -> cumulative [0.2, 0.5, 1.0]
|
|
/// Cell 0 [0, 0.333]: boundary 0.2 falls here -> local fracs [0.6, 1.0] -> 2 subcells
|
|
/// Cell 1 [0.333, 0.667]: boundary 0.5 falls here -> local fracs [0.5, 1.0] -> 2 subcells
|
|
/// Cell 2 [0.667, 1.0]: no interior boundaries -> local fracs [1.0] -> 1 subcell
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigNonUniformRefinement::distributeWidthsAcrossCells( Dimension dim, size_t startIndex, size_t endIndex, const std::vector<double>& widths )
|
|
{
|
|
if ( startIndex > endIndex || endIndex >= m_sectorSize[dim] || widths.empty() ) return;
|
|
|
|
// Convert widths to global cumulative fractions
|
|
auto globalFractions = widthsToCumulativeFractions( widths );
|
|
|
|
size_t numCells = endIndex - startIndex + 1;
|
|
|
|
for ( size_t c = 0; c < numCells; ++c )
|
|
{
|
|
double cellStart = static_cast<double>( c ) / static_cast<double>( numCells );
|
|
double cellEnd = static_cast<double>( c + 1 ) / static_cast<double>( numCells );
|
|
double cellWidth = cellEnd - cellStart;
|
|
|
|
std::vector<double> localFractions;
|
|
|
|
// Find global boundaries that fall strictly within this cell
|
|
for ( double gf : globalFractions )
|
|
{
|
|
if ( gf > cellStart && gf < cellEnd )
|
|
{
|
|
// Convert to cell-local fraction
|
|
localFractions.push_back( ( gf - cellStart ) / cellWidth );
|
|
}
|
|
}
|
|
|
|
// Always add 1.0 as the final boundary (the cell end)
|
|
localFractions.push_back( 1.0 );
|
|
|
|
m_fractions[dim][startIndex + c] = localFractions;
|
|
}
|
|
|
|
rebuildOffsets( dim );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RigNonUniformRefinement::hasRefinement() const
|
|
{
|
|
for ( auto dim : { DimI, DimJ, DimK } )
|
|
{
|
|
if ( totalRefinedCount( dim ) != m_sectorSize[dim] ) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RigNonUniformRefinement::rebuildOffsets( Dimension dim )
|
|
{
|
|
m_offsets[dim].resize( m_sectorSize[dim] + 1 );
|
|
m_offsets[dim][0] = 0;
|
|
|
|
for ( size_t i = 0; i < m_sectorSize[dim]; ++i )
|
|
{
|
|
m_offsets[dim][i + 1] = m_offsets[dim][i] + m_fractions[dim][i].size();
|
|
}
|
|
}
|