Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 102 additions & 90 deletions LoopStructural/modelling/core/_model_feature_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,30 @@

from __future__ import annotations

from typing import TYPE_CHECKING, Callable

import numpy as np
import pandas as pd

from LoopStructural import LoopStructuralConfig

from ...modelling.features import FeatureType, UnconformityFeature
from ...modelling.features import FeatureType, GeologicalFeature, UnconformityFeature
from ...modelling.features.builders import (
FaultBuilder,
FoldedFeatureBuilder,
GeologicalFeatureBuilder,
StructuralFrameBuilder,
)
from ...modelling.features.fault import FaultSegment
from ...modelling.features.fold import FoldEvent, FoldFrame
from ...modelling.intrusions import IntrusionBuilder, IntrusionFrameBuilder
from ...modelling.intrusions import IntrusionBuilder, IntrusionFeature, IntrusionFrameBuilder
from ...utils import getLogger

if TYPE_CHECKING:
from numpy.typing import ArrayLike

from .geological_model import GeologicalModel

logger = getLogger(__name__)

# interpolator types that implement fold constraints
Expand All @@ -38,18 +46,19 @@
class ModelFeatureFactory:
@staticmethod
def build_foliation(
model,
model: GeologicalModel,
series_surface_name: str,
*,
index: int | None = None,
data: pd.DataFrame | None = None,
interpolatortype: str = "FDI",
nelements: int = LoopStructuralConfig.nelements,
tol=None,
faults=None,
**kwargs,
):
"""
tol: float | None = None,
faults: list[GeologicalFeature | str] | None = None,
**kwargs: object,
) -> GeologicalFeature | None:
"""Build a foliation feature from model data.

Parameters
----------
series_surface_name : string
Expand All @@ -72,7 +81,7 @@ def build_foliation(
the created geological feature

Notes
------
-----
This function creates an instance of a
:class:`LoopStructural.modelling.features.builders.GeologicalFeatureBuilder` and will return
a :class:`LoopStructural.modelling.features.builders.GeologicalFeature`
Expand All @@ -83,7 +92,6 @@ def build_foliation(
An interpolator will be chosen by calling :meth:`LoopStructural.GeologicalModel.get_interpolator`

"""

# if tol is not specified use the model default
if tol is None:
tol = model.tol
Expand All @@ -103,7 +111,9 @@ def build_foliation(
if data.shape[0] == 0:
logger.warning("No data for {series_surface_data}, skipping")
return
series_builder.add_data_from_data_frame(model.prepare_data(data, include_feature_name=False))
series_builder.add_data_from_data_frame(
model.prepare_data(data, include_feature_name=False)
)
model._add_faults(series_builder, features=faults)

# build feature
Expand All @@ -118,18 +128,19 @@ def build_foliation(

@staticmethod
def build_fold_frame(
model,
model: GeologicalModel,
fold_frame_name: str,
*,
index: int | None = None,
data=None,
interpolatortype="FDI",
nelements=LoopStructuralConfig.nelements,
tol=None,
buffer=0.1,
**kwargs,
):
"""
data: pd.DataFrame | None = None,
interpolatortype: str = "FDI",
nelements: int = LoopStructuralConfig.nelements,
tol: float | None = None,
buffer: float = 0.1,
**kwargs: object,
) -> FoldFrame | None:
"""Build a fold frame from model data.

Parameters
----------
fold_frame_name : string
Expand All @@ -156,7 +167,6 @@ def build_fold_frame(
fold_frame : FoldFrame
the created fold frame
"""

if tol is None:
tol = model.tol

Expand Down Expand Up @@ -195,22 +205,22 @@ def build_fold_frame(

@staticmethod
def build_folded_foliation(
model,
foliation_name,
model: GeologicalModel,
foliation_name: str,
*,
index: int | None = None,
data=None,
interpolatortype="DFI",
nelements=LoopStructuralConfig.nelements,
buffer=0.1,
fold_frame=None,
svario=True,
tol=None,
invert_fold_norm=False,
**kwargs,
):
data: pd.DataFrame | None = None,
interpolatortype: str = "DFI",
nelements: int = LoopStructuralConfig.nelements,
buffer: float = 0.1,
fold_frame: FoldFrame | None = None,
svario: bool = True,
tol: float | None = None,
invert_fold_norm: bool = False,
**kwargs: object,
) -> GeologicalFeature | None:
"""
Create a folded foliation field from data and a fold frame
Create a folded foliation field from data and a fold frame.

Parameters
----------
Expand All @@ -236,15 +246,13 @@ def build_folded_foliation(

Notes
-----

- The P2 mesh is larger than the model box because of ``buffer``.
- Building a folded foliation uses the fold interpolation code from Laurent et al., 2016
and fold profile fitting from Grose et al., 2017. For more information about the fold modelling
see :class:`LoopStructural.modelling.features.fold.FoldEvent`,
:class:`LoopStructural.modelling.features.builders.FoldedFeatureBuilder`

"""

if tol is None:
tol = model.tol

Expand Down Expand Up @@ -277,7 +285,9 @@ def build_folded_foliation(
if data.shape[0] == 0:
logger.warning(f"No data for {foliation_name}, skipping")
return
series_builder.add_data_from_data_frame(model.prepare_data(data, include_feature_name=False))
series_builder.add_data_from_data_frame(
model.prepare_data(data, include_feature_name=False)
)

model._add_faults(series_builder)
# build feature
Expand All @@ -294,18 +304,18 @@ def build_folded_foliation(

@staticmethod
def build_folded_fold_frame(
model,
model: GeologicalModel,
fold_frame_name: str,
*,
index: int | None = None,
data: pd.DataFrame | None = None,
interpolatortype="FDI",
nelements=LoopStructuralConfig.nelements,
fold_frame=None,
tol=None,
**kwargs,
):
"""
interpolatortype: str = "FDI",
nelements: int = LoopStructuralConfig.nelements,
fold_frame: FoldFrame | None = None,
tol: float | None = None,
**kwargs: object,
) -> FoldFrame:
"""Build a folded fold frame from model data.

Parameters
----------
Expand Down Expand Up @@ -348,7 +358,6 @@ def build_folded_fold_frame(
see :class:`LoopStructural.modelling.features.fold.FoldEvent`,
:class:`LoopStructural.modelling.features.builders.FoldedFeatureBuilder`
"""

if tol is None:
tol = model.tol

Expand Down Expand Up @@ -398,14 +407,15 @@ def build_folded_fold_frame(

@staticmethod
def validate_intrusion_inputs(
intrusion_name,
intrusion_frame_name,
intrusion_data,
intrusion_frame_data,
intrusion_frame_parameters,
):
"""Fail fast, at the `create_and_add_intrusion` boundary, with a clear
message naming the missing piece -- instead of a bare `KeyError`
intrusion_name: str,
intrusion_frame_name: str,
intrusion_data: pd.DataFrame,
intrusion_frame_data: pd.DataFrame,
intrusion_frame_parameters: dict[str, object],
) -> None:
"""Fail fast at the intrusion creation boundary with a clear error.

This names the missing piece instead of raising a bare `KeyError`
several calls deep inside `IntrusionFrameBuilder`/`IntrusionBuilder`
once building has already started. See ``INTRUSIONS.md`` finding 4.
"""
Expand Down Expand Up @@ -442,17 +452,17 @@ def validate_intrusion_inputs(

@staticmethod
def build_intrusion(
model,
intrusion_name,
intrusion_frame_name,
model: GeologicalModel,
intrusion_name: str,
intrusion_frame_name: str,
*,
intrusion_frame_parameters=None,
intrusion_lateral_extent_model=None,
intrusion_vertical_extent_model=None,
geometric_scaling_parameters=None,
**kwargs,
):
"""
intrusion_frame_parameters: dict[str, object] | None = None,
intrusion_lateral_extent_model: Callable[..., object] | None = None,
intrusion_vertical_extent_model: Callable[..., object] | None = None,
geometric_scaling_parameters: dict[str, object] | None = None,
**kwargs: object,
) -> IntrusionFeature:
"""Build an intrusion feature from model data.

Note
-----
Expand Down Expand Up @@ -570,15 +580,16 @@ def build_intrusion(

@staticmethod
def build_domain_fault(
model,
fault_surface_data,
model: GeologicalModel,
fault_surface_data: pd.DataFrame | str,
*,
nelements=LoopStructuralConfig.nelements,
interpolatortype="FDI",
nelements: int = LoopStructuralConfig.nelements,
interpolatortype: str = "FDI",
index: int | None = None,
**kwargs,
):
"""
**kwargs: object,
) -> UnconformityFeature:
"""Build a domain fault from model data.

Parameters
----------
fault_surface_data : string
Expand Down Expand Up @@ -626,32 +637,33 @@ def build_domain_fault(

@staticmethod
def build_fault(
model,
model: GeologicalModel,
fault_name: str,
displacement: float,
*,
index: int | None = None,
data: pd.DataFrame | None = None,
interpolatortype="FDI",
tol=None,
fault_slip_vector=None,
fault_normal_vector=None,
fault_center=None,
major_axis=None,
minor_axis=None,
intermediate_axis=None,
faultfunction="BaseFault",
faults=None,
interpolatortype: str = "FDI",
tol: float | None = None,
fault_slip_vector: ArrayLike | None = None,
fault_normal_vector: ArrayLike | None = None,
fault_center: ArrayLike | None = None,
major_axis: float | None = None,
minor_axis: float | None = None,
intermediate_axis: float | None = None,
faultfunction: str = "BaseFault",
faults: list[GeologicalFeature | str] | None = None,
force_mesh_geometry: bool = False,
points: bool = False,
fault_buffer=0.2,
fault_trace_anisotropy=0.0,
fault_dip=90,
fault_dip_anisotropy=0.0,
fault_pitch=None,
**kwargs,
):
"""
fault_buffer: float = 0.2,
fault_trace_anisotropy: float = 0.0,
fault_dip: float = 90,
fault_dip_anisotropy: float = 0.0,
fault_pitch: float | None = None,
**kwargs: object,
) -> FaultSegment:
"""Build a fault from model data.

Parameters
----------
fault_name : string
Expand Down
Loading
Loading