@@ -1404,5 +1404,110 @@ convert_to_hybrid_grid(const Grid &grid_cpp,
14041404 logger.debug (" Hybrid grid conversion completed" );
14051405 return std::make_tuple (zcorn_hyb, actnum_hyb);
14061406}
1407+
1408+ // Fix zero in Z value pillars to avoid tolerance violations and assure "verticality".
1409+ void
1410+ Grid::fix_zero_pillars () const
1411+ {
1412+ auto &logger = xtgeo::logging::LoggerManager::get (" Grid::fix_zero_pillars" );
1413+ logger.debug (" Fixing zero pillars for grid ({}, {}, {})" , m_ncol, m_nrow, m_nlay);
1414+
1415+ constexpr double MIN_Z_SEPARATION = 1e-5 ; // Must be > TOLERANCE (1e-6)
1416+
1417+ // Get mutable access to the coordinate arrays
1418+ auto coordsv_mut =
1419+ const_cast <py::array_t <double > &>(m_coordsv).mutable_unchecked <3 >();
1420+ auto zcornsv_mut =
1421+ const_cast <py::array_t <float > &>(m_zcornsv).mutable_unchecked <4 >();
1422+
1423+ // First pass: count zero pillars and compute average X,Y,Z from non-zero pillars
1424+ size_t zero_count = 0 ;
1425+ double sum_x = 0.0 ;
1426+ double sum_y = 0.0 ;
1427+ double sum_z_top = 0.0 ;
1428+ double sum_z_bot = 0.0 ;
1429+ size_t non_zero_count = 0 ;
1430+
1431+ for (size_t i = 0 ; i <= m_ncol; i++) {
1432+ for (size_t j = 0 ; j <= m_nrow; j++) {
1433+ bool is_zero = true ;
1434+ for (size_t coord = 0 ; coord < 6 ; coord++) {
1435+ if (std::abs (coordsv_mut (i, j, coord)) > numerics::EPSILON) {
1436+ is_zero = false ;
1437+ break ;
1438+ }
1439+ }
1440+
1441+ if (is_zero) {
1442+ zero_count++;
1443+ } else {
1444+ // Accumulate X,Y,Z from non-zero pillars
1445+ sum_x += coordsv_mut (i, j, 0 ); // x_top
1446+ sum_y += coordsv_mut (i, j, 1 ); // y_top
1447+ sum_z_top += coordsv_mut (i, j, 2 ); // z_top
1448+ sum_z_bot += coordsv_mut (i, j, 5 ); // z_bot
1449+ non_zero_count++;
1450+ }
1451+ }
1452+ }
1453+
1454+ if (zero_count == 0 ) {
1455+ return ; // No zero pillars to fix
1456+ }
1457+
1458+ // Compute average X,Y,Z from non-zero pillars
1459+ double avg_x = (non_zero_count > 0 ) ? (sum_x / non_zero_count) : 0.0 ;
1460+ double avg_y = (non_zero_count > 0 ) ? (sum_y / non_zero_count) : 0.0 ;
1461+ double avg_z_top = (non_zero_count > 0 ) ? (sum_z_top / non_zero_count) : 0.0 ;
1462+ double avg_z_bot =
1463+ (non_zero_count > 0 ) ? (sum_z_bot / non_zero_count) : MIN_Z_SEPARATION;
1464+
1465+ // Ensure minimum separation between top and bottom
1466+ if (std::abs (avg_z_bot - avg_z_top) < MIN_Z_SEPARATION) {
1467+ avg_z_bot = avg_z_top + MIN_Z_SEPARATION;
1468+ }
1469+
1470+ logger.debug (
1471+ " Found {} zero pillars, avg coordinates from grid: ({}, {}, z_top={}, z_bot={})" ,
1472+ zero_count, avg_x, avg_y, avg_z_top, avg_z_bot);
1473+
1474+ // Second pass: fix zero pillars with average X,Y and proper Z separation
1475+ for (size_t i = 0 ; i <= m_ncol; i++) {
1476+ for (size_t j = 0 ; j <= m_nrow; j++) {
1477+ // Check if pillar is all zeros
1478+ bool is_zero = true ;
1479+ for (size_t coord = 0 ; coord < 6 ; coord++) {
1480+ if (std::abs (coordsv_mut (i, j, coord)) > numerics::EPSILON) {
1481+ is_zero = false ;
1482+ break ;
1483+ }
1484+ }
1485+
1486+ if (is_zero) {
1487+ // Fix coordsv: set average X,Y,Z with proper separation
1488+ coordsv_mut (i, j, 0 ) = avg_x; // x_top
1489+ coordsv_mut (i, j, 1 ) = avg_y; // y_top
1490+ coordsv_mut (i, j, 2 ) = avg_z_top; // z_top
1491+ coordsv_mut (i, j, 3 ) = avg_x; // x_bot (vertical pillar)
1492+ coordsv_mut (i, j, 4 ) = avg_y; // y_bot (vertical pillar)
1493+ coordsv_mut (i, j, 5 ) = avg_z_bot; // z_bot
1494+
1495+ // Fix zcornsv: set progressive depth for each layer
1496+ // Use linear interpolation between avg_z_top and avg_z_bot
1497+ double layer_thickness =
1498+ (avg_z_bot - avg_z_top) / static_cast <double >(m_nlay);
1499+ for (size_t k = 0 ; k <= m_nlay; k++) {
1500+ float depth = static_cast <float >(avg_z_top + k * layer_thickness);
1501+ for (size_t corner = 0 ; corner < 4 ; corner++) {
1502+ zcornsv_mut (i, j, k, corner) = depth;
1503+ }
1504+ }
1505+ }
1506+ }
1507+ }
1508+
1509+ logger.debug (" Fixed {} zero pillars with average coordinates" , zero_count);
1510+ }
1511+
14071512// ===================
14081513} // xtgeo::grid3d
0 commit comments