# Copyright (c) 2023 Mira Geoscience Ltd.
#
# This file is part of geoh5py.
#
# geoh5py is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# geoh5py 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with geoh5py. If not, see <https://www.gnu.org/licenses/>.
from __future__ import annotations
import uuid
from geoh5py.objects.curve import Curve
from geoh5py.objects.object_base import ObjectType
from .base import BaseTEMSurvey
[docs]class BaseAirborneTEM(BaseTEMSurvey, Curve): # pylint: disable=too-many-ancestors
__INPUT_TYPE = ["Rx", "Tx", "Tx and Rx"]
_PROPERTY_MAP = {
"crossline_offset": "Crossline offset",
"inline_offset": "Inline offset",
"pitch": "Pitch",
"roll": "Roll",
"vertical_offset": "Vertical offset",
"yaw": "Yaw",
}
@property
def crossline_offset(self) -> float | uuid.UUID | None:
"""
Numeric value or property UUID for the crossline offset between receiver and transmitter.
"""
return self.fetch_metadata("crossline_offset")
@crossline_offset.setter
def crossline_offset(self, value: float | uuid.UUID | None):
self.set_metadata("crossline_offset", value)
@property
def default_metadata(self) -> dict:
"""
Default dictionary of metadata for AirborneTEM entities.
"""
return {
"EM Dataset": {
"Channels": [],
"Input type": "Rx",
"Property groups": [],
"Receivers": None,
"Survey type": "Airborne TEM",
"Transmitters": None,
"Unit": "Milliseconds (ms)",
"Waveform": {"Timing mark": 0.0},
}
}
@property
def default_input_types(self) -> list[str]:
"""Choice of survey creation types."""
return self.__INPUT_TYPE
@property
def default_receiver_type(self):
"""
:return: Transmitter class
"""
return AirborneTEMReceivers
@property
def default_transmitter_type(self):
"""
:return: Transmitter class
"""
return AirborneTEMTransmitters
@property
def inline_offset(self) -> float | uuid.UUID | None:
"""
Numeric value or property UUID for the inline offset between receiver and transmitter.
"""
return self.fetch_metadata("inline_offset")
@inline_offset.setter
def inline_offset(self, value: float | uuid.UUID):
self.set_metadata("inline_offset", value)
@property
def loop_radius(self) -> float | None:
"""Transmitter loop radius"""
return self.metadata["EM Dataset"].get("Loop radius", None)
@loop_radius.setter
def loop_radius(self, value: float | None):
if not isinstance(value, (float, type(None))):
raise TypeError("Input 'loop_radius' must be of type 'float'")
self.edit_metadata({"Loop radius": value})
@property
def pitch(self) -> float | uuid.UUID | None:
"""
Numeric value or property UUID for the pitch angle of the transmitter loop.
"""
return self.fetch_metadata("pitch")
@pitch.setter
def pitch(self, value: float | uuid.UUID | None):
self.set_metadata("pitch", value)
@property
def relative_to_bearing(self) -> bool | None:
"""Data relative_to_bearing"""
return self.metadata["EM Dataset"].get("Angles relative to bearing", None)
@relative_to_bearing.setter
def relative_to_bearing(self, value: bool | None):
if not isinstance(value, (bool, type(None))):
raise TypeError("Input 'relative_to_bearing' must be one of type 'bool'")
self.edit_metadata({"Angles relative to bearing": value})
@property
def roll(self) -> float | uuid.UUID | None:
"""
Numeric value or property UUID for the roll angle of the transmitter loop.
"""
return self.fetch_metadata("roll")
@roll.setter
def roll(self, value: float | uuid.UUID | None):
self.set_metadata("roll", value)
@property
def vertical_offset(self) -> float | uuid.UUID | None:
"""
Numeric value or property UUID for the vertical offset between receiver and transmitter.
"""
return self.fetch_metadata("vertical_offset")
@vertical_offset.setter
def vertical_offset(self, value: float | uuid.UUID | None):
self.set_metadata("vertical_offset", value)
@property
def yaw(self) -> float | uuid.UUID | None:
"""
Numeric value or property UUID for the yaw angle of the transmitter loop.
"""
return self.fetch_metadata("yaw")
@yaw.setter
def yaw(self, value: float | uuid.UUID):
self.set_metadata("yaw", value)
[docs]class AirborneTEMReceivers(BaseAirborneTEM): # pylint: disable=too-many-ancestors
"""
Airborne time-domain electromagnetic receivers class.
"""
__TYPE_UID = uuid.UUID("{19730589-fd28-4649-9de0-ad47249d9aba}")
__TYPE = "Receivers"
def __init__(self, object_type: ObjectType, name="Airborne TEM Rx", **kwargs):
super().__init__(object_type, name=name, **kwargs)
[docs] @classmethod
def default_type_uid(cls) -> uuid.UUID:
"""
:return: Default unique identifier
"""
return cls.__TYPE_UID
@property
def type(self):
"""Survey element type"""
return self.__TYPE
[docs]class AirborneTEMTransmitters(BaseAirborneTEM): # pylint: disable=too-many-ancestors
"""
Airborne time-domain electromagnetic transmitters class.
"""
__TYPE_UID = uuid.UUID("{58c4849f-41e2-4e09-b69b-01cf4286cded}")
__TYPE = "Transmitters"
def __init__(self, object_type: ObjectType, name="Airborne TEM Tx", **kwargs):
super().__init__(object_type, name=name, **kwargs)
[docs] @classmethod
def default_type_uid(cls) -> uuid.UUID:
"""
:return: Default unique identifier
"""
return cls.__TYPE_UID
@property
def type(self):
"""Survey element type"""
return self.__TYPE