Source code for gempy.API.compute_API
import dotenv
import numpy as np
import os
from typing import Optional
import gempy_engine
from gempy_engine.config import AvailableBackends
from gempy_engine.core.backend_tensor import BackendTensor
from gempy_engine.core.data import Solutions
from .grid_API import set_custom_grid
from ..core.data import StructuralGroup
from ..core.data.gempy_engine_config import GemPyEngineConfig
from ..core.data.geo_model import GeoModel
from ..modules.data_manipulation import interpolation_input_from_structural_frame
from ..modules.optimize_nuggets import nugget_optimizer
dotenv.load_dotenv()
[docs]
def compute_model(gempy_model: GeoModel, engine_config: Optional[GemPyEngineConfig] = None,
**kwargs) -> Solutions:
"""
Compute the geological model given the provided GemPy model.
Args:
gempy_model (GeoModel): The GemPy model to compute.
engine_config (Optional[GemPyEngineConfig]): Configuration for the computational engine. Defaults to None, in which case a default configuration will be used.
Raises:
ValueError: If the provided backend in the engine_config is not supported.
Returns:
Solutions: The computed geological model.
"""
engine_config: GemPyEngineConfig = engine_config or GemPyEngineConfig()
match engine_config.backend:
case AvailableBackends.numpy | AvailableBackends.PYTORCH:
try:
BackendTensor.change_backend_gempy(
engine_backend=engine_config.backend,
use_gpu=engine_config.use_gpu,
dtype=engine_config.dtype,
grads=engine_config.compute_grads
)
except RuntimeError:
if engine_config.use_gpu and os.getenv("GEMPY_GPU_FALLBACK", "False") == "True":
print("GPU requested but unavailable; falling back to CPU (GEMPY_GPU_FALLBACK=True)")
engine_config.use_gpu = False
BackendTensor.change_backend_gempy(
engine_backend=engine_config.backend,
use_gpu=False,
dtype=engine_config.dtype,
grads=engine_config.compute_grads
)
else:
raise
# TODO: To decide what to do with this.
interpolation_input = interpolation_input_from_structural_frame(gempy_model)
gempy_model.taped_interpolation_input = interpolation_input # * This is used for gradient tape
gempy_model.solutions = gempy_engine.compute_model(
interpolation_input=interpolation_input,
options=gempy_model.interpolation_options,
data_descriptor=gempy_model.input_data_descriptor,
geophysics_input=gempy_model.geophysics_input,
)
case _:
raise ValueError(f'Backend {engine_config} not supported')
validate_serialization = os.getenv("VALIDATE_SERIALIZATION", "False") == "True"
if "validate_serialization" in kwargs:
validate_serialization = kwargs["validate_serialization"]
if validate_serialization:
from ..modules.serialization.save_load import model_to_bytes, _load_model_from_bytes, _validate_serialization
binary_file = model_to_bytes(gempy_model)
model_deserialized = _load_model_from_bytes(binary_file)
_validate_serialization(gempy_model, model_deserialized)
return gempy_model.solutions
def compute_model_at(gempy_model: GeoModel, at: np.ndarray,
engine_config: Optional[GemPyEngineConfig] = None) -> np.ndarray:
"""
Compute the geological model at specific coordinates.
Note: This function sets a custom grid and computes the model so be wary of side effects.
Args:
gempy_model (GeoModel): The GemPy model to compute.
at (np.ndarray): The coordinates at which to compute the model.
engine_config (Optional[GemPyEngineConfig], optional): Configuration for the computational engine. Defaults to None, in which case a default configuration will be used.
Returns:
np.ndarray: The computed geological model at the specified coordinates.
"""
print("WARNING: This function sets a custom grid and computes the model so be wary of side effects.")
set_custom_grid(
grid=gempy_model.grid,
xyz_coord=at,
reset=True
)
sol = compute_model(gempy_model, engine_config)
return sol.raw_arrays.custom
def optimize_nuggets(geo_model: GeoModel, engine_config: GemPyEngineConfig, max_epochs: int = 10,
convergence_criteria: float = 1e5, only_groups:list[StructuralGroup] | None = None) -> GeoModel:
"""
Optimize the nuggets of the interpolation input of the provided model.
"""
if engine_config.backend != AvailableBackends.PYTORCH:
raise ValueError(f'Only PyTorch backend is supported for optimization. Received {engine_config.backend}')
geo_model = nugget_optimizer(
target_cond_num=convergence_criteria,
engine_cfg=engine_config,
model=geo_model,
max_epochs=max_epochs,
only_groups=only_groups
)
return geo_model
def optimize_and_compute(geo_model: GeoModel, engine_config: GemPyEngineConfig, max_epochs: int = 10,
convergence_criteria: float = 1e5):
optimize_nuggets(geo_model, engine_config, max_epochs, convergence_criteria)
geo_model.solutions = gempy_engine.compute_model(
interpolation_input=geo_model.taped_interpolation_input,
options=geo_model.interpolation_options,
data_descriptor=geo_model.input_data_descriptor,
geophysics_input=geo_model.geophysics_input,
)
return geo_model.solutions