Source code for fmu.dataio.export.rms.structure_depth_fault_surfaces

from __future__ import annotations

from pathlib import Path
from typing import Any, Final, Self

from xtgeo import TriangulatedSurface

from fmu.dataio._export import ExportConfig, export_with_metadata
from fmu.dataio._logging import null_logger
from fmu.dataio.export._base import SimpleExportBase
from fmu.dataio.export._export_result import ExportResult, ExportResultItem
from fmu.dataio.export.rms._utils import get_rms_project_units
from fmu.datamodels.common.enums import Classification
from fmu.datamodels.fmu_results.enums import (
    Content,
    DomainReference,
    VerticalDomain,
)
from fmu.datamodels.standard_results.enums import StandardResultName

_logger: Final = null_logger(__name__)


class _ExportStructureDepthFaultSurfaces(SimpleExportBase):
    def __init__(
        self: Self,
        project: Any,
        structural_model_name: str,
    ) -> None:
        super().__init__()

        _logger.debug("Process data, establish state prior to export.")

        self._unit = "m" if get_rms_project_units(project) == "metric" else "ft"

        self._surfaces = _get_fault_surfaces_from_rms(project, structural_model_name)

        _logger.debug("Process data... DONE")

    def _get_export_config(self, name: str) -> ExportConfig:
        """Export config for the standard result."""
        return (
            ExportConfig.builder()
            .content(Content.fault_surface)
            .domain(VerticalDomain.depth, DomainReference.msl)
            .unit(self._unit)
            .file_config(
                name=name,
                subfolder=StandardResultName.structure_depth_fault_surface.value,
            )
            .access(Classification.internal, rep_include=True)
            .global_config(self._config)
            .standard_result(StandardResultName.structure_depth_fault_surface)
            .build()
        )

    def _export_surface(self: Self, surf: TriangulatedSurface) -> ExportResultItem:
        export_config = self._get_export_config(name=surf.name)
        absolute_export_path = export_with_metadata(export_config, surf)
        _logger.debug("Surface exported to: %s", absolute_export_path)

        return ExportResultItem(
            absolute_path=Path(absolute_export_path),
        )

    def _export_data_as_standard_result(self) -> ExportResult:
        """Export the fault surfaces as a standard result."""
        return ExportResult(
            items=[self._export_surface(surf) for surf in self._surfaces]
        )

    def _validate_data_pre_export(self) -> None:
        """Surface validations before export."""
        # The surfaces are Pydantic models and are automatically validated


def _get_fault_surfaces_from_rms(
    project: Any,
    structural_model_name: str,
) -> list[TriangulatedSurface]:
    """
    Fetch triangulated fault surfaces as TriangulatedSurface from RMS.

    Args:
        project: the 'magic' project variable in RMS
        structural_model_name: name of the structural model

    Returns:
        List of TriangulatedSurface objects representing
        all fault surfaces in the structural model as triangulations.
    """

    if structural_model_name not in project.structural_models:
        raise ValueError(
            f"Project does not contain a structural model named: "
            f"'{structural_model_name}'."
        )

    fault_model = project.structural_models[structural_model_name].fault_model

    fault_surfaces = []
    for fault_name in fault_model.fault_names:
        fault_surface = fault_model.get_fault_triangle_surface(name=fault_name)

        tsurf = TriangulatedSurface(
            name=fault_name,
            vertices=fault_surface.get_vertices(),
            triangles=fault_surface.get_triangles(),
        )

        # To get coordinate system info in the GOCAD TSurf file
        # it must be set using metadata in the xtgeo object
        unit = "m" if get_rms_project_units(project) == "metric" else "ft"

        tsurf.metadata.freeform = {
            "tsurf_coord_sys": {
                "name": "Default",
                "axis_name": ("X", "Y", "Z"),
                "axis_unit": (unit, unit, unit),
                "zpositive": "depth",
            }
        }

        fault_surfaces.append(tsurf)

    return fault_surfaces


[docs] def export_structure_depth_fault_surfaces( project: Any, structural_model_name: str ) -> ExportResult: """ Simplified interface when exporting triangulated fault surfaces from RMS. Args: project: the 'magic' project variable in RMS structural_model_name: name of the structural model Examples: Example usage in an RMS script:: from fmu.dataio.export.rms import export_structure_depth_fault_surfaces export_results = export_structure_depth_fault_surfaces( project, "structural_model_name" ) for result in export_results.items: print(f"Output surfaces to {result.absolute_path}") """ return _ExportStructureDepthFaultSurfaces(project, structural_model_name).export()