mt_metadata.transfer_functions.io.edi.metadata
Submodules
- mt_metadata.transfer_functions.io.edi.metadata.data_section
- mt_metadata.transfer_functions.io.edi.metadata.define_measurement
- mt_metadata.transfer_functions.io.edi.metadata.emeasurement
- mt_metadata.transfer_functions.io.edi.metadata.header
- mt_metadata.transfer_functions.io.edi.metadata.hmeasurement
- mt_metadata.transfer_functions.io.edi.metadata.information
Classes
Base class for all metadata objects with Pydantic validation. |
|
Base class for all metadata objects with Pydantic validation. |
|
Contain, read, and write info section of .edi file |
|
DataSection contains the small metadata block that describes which channel |
|
DefineMeasurement class holds information about the measurement. This |
|
A partial location class that only includes the latitude, longitude, and elevation. |
Package Contents
- class mt_metadata.transfer_functions.io.edi.metadata.EMeasurement(**data)
Bases:
mt_metadata.base.MetadataBaseBase class for all metadata objects with Pydantic validation.
MetadataBase extends DotNotationBaseModel (which inherits from Pydantic’s BaseModel) to provide automatic validation according to metadata standards. It adds functionality beyond dictionaries, supporting JSON, XML, pandas Series, and other formats for metadata interchange.
- _skip_equals
Private attribute listing fields to skip in equality comparisons
- Type:
list[str]
- _fields
Private attribute caching field information
- Type:
dict[str, Any]
Notes
All field assignments are validated automatically via Pydantic
None values are converted to appropriate defaults (empty string or 0.0)
Supports nested attribute access via dot notation
Thread-safe for read operations after initialization
- id: Annotated[float | None, Field(default=0.0, description='Channel number, could be location.channel_number.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['1']})]
- chtype: Annotated[str, Field(default='', description="channel type, should start with an 'e'", alias=None, pattern='^(RR|rr|[eE])[a-zA-Z0-9_]+$', json_schema_extra={'units': None, 'required': True, 'examples': ['ex']})]
- x: Annotated[float, Field(default=0.0, description='location of negative sensor relative center point in north direction', alias=None, json_schema_extra={'units': 'meters', 'required': True, 'examples': ['100.0']})]
- x2: Annotated[float, Field(default=0.0, description='location of positive sensor relative center point in north direction', alias=None, json_schema_extra={'units': 'meters', 'required': True, 'examples': ['100.0']})]
- y: Annotated[float, Field(default=0.0, description='location of negative sensor relative center point in east direction', alias=None, json_schema_extra={'units': 'meters', 'required': True, 'examples': ['100.0']})]
- y2: Annotated[float, Field(default=0.0, description='location of positive sensor relative center point in east direction', alias=None, json_schema_extra={'units': 'meters', 'required': True, 'examples': ['100.0']})]
- z: Annotated[float, Field(default=0.0, description='location of negative sensor relative center point in depth', alias=None, json_schema_extra={'units': 'meters', 'required': True, 'examples': ['100.0']})]
- z2: Annotated[float, Field(default=0.0, description='location of positive sensor relative center point in depth', alias=None, json_schema_extra={'units': 'meters', 'required': True, 'examples': ['100.0']})]
- azm: Annotated[float, Field(default=0.0, description='orientation of the sensor relative to coordinate system, clockwise positive.', alias=None, json_schema_extra={'units': 'degrees', 'required': True, 'examples': ['100.0']})]
- acqchan: Annotated[str, Field(default='', description='description of acquired channel', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['100.0']})]
- classmethod validate_id(value)
Ensure id is a float or None, convert if necessary
- update_azimuth_from_coords()
Update azm based on coordinates after validation
- property dipole_length: float
dipole length based on x, y, z coordinates
- property azimuth: float
aximuth based on x, y coordinates
- property channel_number: int
Extract channel number from acqchan.
- write_meas_line()
write string :return: DESCRIPTION :rtype: TYPE
- class mt_metadata.transfer_functions.io.edi.metadata.HMeasurement(**data)
Bases:
mt_metadata.base.MetadataBaseBase class for all metadata objects with Pydantic validation.
MetadataBase extends DotNotationBaseModel (which inherits from Pydantic’s BaseModel) to provide automatic validation according to metadata standards. It adds functionality beyond dictionaries, supporting JSON, XML, pandas Series, and other formats for metadata interchange.
- _skip_equals
Private attribute listing fields to skip in equality comparisons
- Type:
list[str]
- _fields
Private attribute caching field information
- Type:
dict[str, Any]
Notes
All field assignments are validated automatically via Pydantic
None values are converted to appropriate defaults (empty string or 0.0)
Supports nested attribute access via dot notation
Thread-safe for read operations after initialization
- id: Annotated[float | str | None, Field(default=0.0, description='Channel number, could be location.channel_number.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['1']})]
- chtype: Annotated[str, Field(default='', description="channel type, should start with an 'h' or 'b'", alias=None, pattern='^(R|r|RR|rr|[hHbB])[a-zA-Z0-9_]+$', json_schema_extra={'units': None, 'required': True, 'examples': ['hx']})]
- x: Annotated[float, Field(default=0.0, description='location of sensor relative center point in north direction', alias=None, json_schema_extra={'units': 'meters', 'required': True, 'examples': ['100.0']})]
- y: Annotated[float, Field(default=0.0, description='location of sensor relative center point in east direction', alias=None, json_schema_extra={'units': 'meters', 'required': True, 'examples': ['100.0']})]
- z: Annotated[float, Field(default=0.0, description='location of sensor relative center point in depth', alias=None, json_schema_extra={'units': 'meters', 'required': True, 'examples': ['100.0']})]
- azm: Annotated[float, Field(default=0.0, description='orientation of the sensor relative to coordinate system, clockwise positive.', alias=None, json_schema_extra={'units': 'degrees', 'required': True, 'examples': ['100.0']})]
- dip: Annotated[float, Field(default=0.0, description='orientation of the sensor relative to horizontal = 0', alias=None, json_schema_extra={'units': 'degrees', 'required': True, 'examples': ['100.0']})]
- acqchan: Annotated[str, Field(default='', description='description of acquired channel', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['100.0']})]
- classmethod validate_id(value)
Ensure id is a float or None, convert if necessary
- property channel_number: int
Extract channel number from acqchan.
- write_meas_line()
write string :return: DESCRIPTION :rtype: TYPE
- class mt_metadata.transfer_functions.io.edi.metadata.Information(**data)
Bases:
mt_metadata.base.MetadataBaseContain, read, and write info section of .edi file
not much to really do here, but just keep it in the same format that it is read in as, except if it is in phoenix format then split the two paragraphs up so they are sequential.
- info_dict: dict[str, str | list | None] = None
- read_info(edi_lines)
Read information section and parse directly to info_dict.
- Parameters:
edi_lines (list[str]) – List of lines from the EDI file.
- write_info()
write out information
- class mt_metadata.transfer_functions.io.edi.metadata.DataSection(**data)
Bases:
mt_metadata.base.MetadataBaseDataSection contains the small metadata block that describes which channel is which. A typical block looks like:
>=MTSECT ex=1004.001 ey=1005.001 hx=1001.001 hy=1002.001 hz=1003.001 nfreq=14 sectid=par28ew nchan=None maxblks=None
- Parameters:
fn (string) – full path to .edi file to read in.
Attributes
Description
Default
In .edi
ex
ex channel id number
None
yes
ey
ey channel id number
None
yes
hx
hx channel id number
None
yes
hy
hy channel id number
None
yes
hz
hz channel id number
None
yes
nfreq
number of frequencies
None
yes
sectid
section id, should be the same as the station name -> Header.dataid
None
yes
maxblks
maximum number of data blocks
None
yes
nchan
number of channels
None
yes
_kw_list
list of key words to put in metadata
no
- nfreq: Annotated[int, Field(default=0, description='Number of frequencies', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': [16, 1]})]
- sectid: Annotated[str, Field(default='', description='ID of the station that the data is from. This is important if you have more than one station per file.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['mt001']})]
- nchan: Annotated[int, Field(default=0, description='Number of channels in the transfer function', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': [7]})]
- maxblocks: Annotated[int, Field(default=999, description='Maximum number of data blocks', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': [999]})]
- ex: Annotated[str | None, Field(default=None, description='Measurement ID for EX', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['1']})]
- ey: Annotated[str | None, Field(default=None, description='Measurement ID for EY', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['2']})]
- hx: Annotated[str | None, Field(default=None, description='Measurement ID for HX', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['3']})]
- hy: Annotated[str | None, Field(default=None, description='Measurement ID for HY', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['4']})]
- hz: Annotated[str | None, Field(default=None, description='Measurement ID for HZ', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['5']})]
- rrhx: Annotated[str | None, Field(default=None, description='Measurement ID for RRHX', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['6']})]
- rrhy: Annotated[str | None, Field(default=None, description='Measurement ID for RRHY', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['7']})]
- get_data(edi_lines)
Read in the data of the file, will detect if reading spectra or impedance.
- read_data(edi_lines)
Read data section
- write_data(data_list=None, over_dict=None)
Write the data section to a list of strings.
- match_channels(ch_ids)
Match the channels in the data section with the provided channel IDs. This method updates the channel IDs based on the provided list.
- class mt_metadata.transfer_functions.io.edi.metadata.DefineMeasurement(**data)
Bases:
mt_metadata.base.MetadataBaseDefineMeasurement class holds information about the measurement. This includes how each channel was setup. The main block contains information on the reference location for the station. This is a bit of an archaic part and was meant for a multiple station .edi file. This section is also important if you did any forward modeling with Winglink cause it only gives the station location in this section. The other parts are how each channel was collected. An example define measurement section looks like:
>=DEFINEMEAS MAXCHAN=7 MAXRUN=999 MAXMEAS=9999 UNITS=M REFTYPE=CART REFLAT=-30:12:49.4693 REFLONG=139:47:50.87 REFELEV=0 >HMEAS ID=1001.001 CHTYPE=HX X=0.0 Y=0.0 Z=0.0 AZM=0.0 >HMEAS ID=1002.001 CHTYPE=HY X=0.0 Y=0.0 Z=0.0 AZM=90.0 >HMEAS ID=1003.001 CHTYPE=HZ X=0.0 Y=0.0 Z=0.0 AZM=0.0 >EMEAS ID=1004.001 CHTYPE=EX X=0.0 Y=0.0 Z=0.0 X2=0.0 Y2=0.0 >EMEAS ID=1005.001 CHTYPE=EY X=0.0 Y=0.0 Z=0.0 X2=0.0 Y2=0.0 >HMEAS ID=1006.001 CHTYPE=HX X=0.0 Y=0.0 Z=0.0 AZM=0.0 >HMEAS ID=1007.001 CHTYPE=HY X=0.0 Y=0.0 Z=0.0 AZM=90.0
- Parameters:
fn (string) – full path to .edi file to read in.
Attributes
Description
Default
In .edi
fn
Full path to edi file read in
None
no
maxchan
Maximum number of channels measured
None
yes
maxmeas
Maximum number of measurements
9999
yes
maxrun
Maximum number of measurement runs
999
yes
meas_####
HMeasurement or EMEasurment object defining the measurement made [1]__
None
yes
refelev
Reference elevation (m)
None
yes
reflat
Reference latitude [2]
None
yes
refloc
Reference location
None
yes
reflon
Reference longituted [2]__
None
yes
reftype
Reference coordinate system
‘cart’
yes
units
Units of length
m
yes
_define_meas_keys
Keys to include in define_measurment section.
[3]__
no
[1] Each channel with have its own define measurement and depending on whether it is an E or H channel the metadata will be different. the #### correspond to the channel number.
[2] Internally everything is converted to decimal degrees. Output is written as HH:MM:SS.ss so Winglink can read them in.
[3] If you want to change what metadata is written into the .edi file change the items in _header_keys. Default attributes are:
maxchan
maxrun
maxmeas
reflat
reflon
refelev
reftype
units
- maxchan: Annotated[int, Field(default=999, description='maximum number of channels', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['16']})]
- maxrun: Annotated[int, Field(default=999, description='maximum number of runs', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['999']})]
- maxmeas: Annotated[int, Field(default=7, description='maximum number of measurements', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['999']})]
- reftype: Annotated[str | None, Field(default='cartesian', description='Type of offset from reference center point.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['cartesian', 'cart']})]
- refloc: Annotated[str | None, Field(default=None, description='Description of location reference center point.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['here']})]
- reflat: Annotated[float, Field(default=0, description='Latitude of reference center point.', alias=None, json_schema_extra={'units': 'degrees', 'required': False, 'examples': ['0']})]
- reflon: Annotated[float, Field(default=0, description='Longitude reference center point.', alias=None, json_schema_extra={'units': 'degrees', 'required': False, 'examples': ['0']})]
- refelev: Annotated[float, Field(default=0, description='Elevation reference center point.', alias=None, json_schema_extra={'units': 'meters', 'required': False, 'examples': ['0']})]
- units: Annotated[str | None, Field(default='m', description='In the EDI standards this is the elevation units.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['m']})]
- measurements: Annotated[dict[str, mt_metadata.transfer_functions.io.edi.metadata.EMeasurement | mt_metadata.transfer_functions.io.edi.metadata.HMeasurement], Field(default_factory=dict, description="Dictionary of measurements with keys as channel types (e.g., 'hx', 'hy', 'ex', 'ey', etc.) and values as EMeasurement or HMeasurement objects.", alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ["{'hx': EMeasurement(...), 'hy': HMeasurement(...)}"]})]
- classmethod validate_units(value)
- classmethod validate_position(value, info)
- property channel_ids: dict[str, str]
- get_measurement_lists(edi_lines)
get measurement list including measurement setup
- edi_lines
lines from the edi file to parse
- Type:
str
- read_measurement(edi_lines)
read the define measurment section of the edi file
should be a list with lines for:
maxchan
maxmeas
maxrun
refloc
refelev
reflat
reflon
reftype
units
dictionaries for >XMEAS with keys:
id
chtype
x
y
axm
acqchn
- write_measurement(longitude_format='LON', latlon_format='degrees')
write_measurement writes the define measurement section of the edi file.
- Parameters:
longitude_format (str, optional) – longitude format [ “LONG” | “LON” ] , by default “LON”
latlon_format (str, optional) – position format [ “dd” | “ degrees” ], by default “degrees” for decimal degrees If you want to write the position in degrees, use “ degrees” for the latlon_format. This will write the position in the format of HH:MM:SS.ss for the latitude and longitude. If you want to write the position in decimal degrees, use “dd” for the latlon_format.
- Returns:
list of lines for the define measurement section or an empty list if no measurements are defined.
- Return type:
list[str]
- Raises:
ValueError – If a value cannot be converted to a float or if the longitude format is not recognized.
- from_metadata(channel)
from_metadata converts a channel object into a measurement object and sets the attributes for the measurement object.
- property channels_recorded: list[str]
Get the channels recorded
- class mt_metadata.transfer_functions.io.edi.metadata.Header(**data)
Bases:
mt_metadata.common.BasicLocation,mt_metadata.common.GeographicLocationA partial location class that only includes the latitude, longitude, and elevation. This is used to avoid circular imports.
- acqby: Annotated[str | None, Field(default=None, description='person, group, company, university that collected the data', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['mt experts']})]
- acqdate: Annotated[mt_metadata.common.mttime.MTime | str | float | int | numpy.datetime64 | pandas.Timestamp, Field(default_factory=lambda: MTime(time_stamp=None), description='Start date the time series data were collected', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['2020-01-01']})]
- coordinate_system: Annotated[mt_metadata.common.GeographicReferenceFrameEnum, Field(default='geographic', description='coordinate system the transfer function is currently in. Its preferred the transfer function be in a geographic coordinate system for archiving and sharing.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['geopgraphic']})]
- dataid: Annotated[str, Field(default='', description='station ID.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['mt001']})]
- enddate: Annotated[mt_metadata.common.mttime.MTime | str | float | int | numpy.datetime64 | pandas.Timestamp | None, Field(default_factory=lambda: MTime(time_stamp=None), description='End date the time series data were collected', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['2020-01-01']})]
- empty: Annotated[float, Field(default=1e+32, description='null data values, usually a large number', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['1E+32']})]
- fileby: Annotated[str, Field(default='', description='person, group, company, university that made the file', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['mt experts']})]
- filedate: Annotated[mt_metadata.common.mttime.MTime | str | float | int | numpy.datetime64 | pandas.Timestamp, Field(default_factory=lambda: MTime(time_stamp=None), description='Date the file was made', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['2020-01-01']})]
- progdate: Annotated[mt_metadata.common.mttime.MTime | str | float | int | numpy.datetime64 | pandas.Timestamp, Field(default_factory=lambda: MTime(time_stamp=None), description='Date of the most recent update of the program used to make the file', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['2020-01-01']})]
- progname: Annotated[str, Field(default='mt_metadata', description='Name of the program used to make the file.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['mt_metadata']})]
- progvers: Annotated[str, Field(default='0.1.6', description='Version of the program used to make the file.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['0.1.6']})]
- project: Annotated[str | None, Field(default=None, description='Name of the project the data was collected for, usually a short description or acronym of the project name.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['iMUSH']})]
- prospect: Annotated[str | None, Field(default=None, description='Name of the prospect the data was collected for, usually a short description of the location', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['Benton']})]
- loc: Annotated[str | None, Field(default=None, description='Usually a short description of the location', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['Benton, CA']})]
- declination: Annotated[mt_metadata.common.Declination, Field(default_factory=lambda: Declination(value=0.0), description='Declination of the station in degrees', alias=None, json_schema_extra={'units': 'degrees', 'required': True, 'examples': ['Declination(10.0)']})]
- stdvers: Annotated[mt_metadata.common.StdEDIversionsEnum, Field(default='SEG 1.0', description='EDI standards version SEG 1.0', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['SEG 1.0']})]
- survey: Annotated[str | None, Field(default=None, description='Name of the survey', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['CONUS']})]
- units: Annotated[str | None, Field(default='milliVolt per kilometer per nanoTesla', description='In the EDI standards this is the elevation units, in newer versions this should be units of the transfer function.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['milliVolt per kilometer per nanoTesla']})]
- classmethod validate_acqdate(field_value)
- classmethod validate_units(value)
- get_header_list(edi_lines)
Get the header information from the .edi file in the form of a list.
Extracts header lines from an EDI file, returning each key-value pair as a formatted string.
- Parameters:
edi_lines (list of str) – List of lines from an EDI file to parse for header information.
- Returns:
List of header key-value pairs in the format ‘key=value’.
- Return type:
list of str
Examples
>>> header = Header() >>> edi_lines = ['>HEAD', 'DATAID=MT001', 'LAT=45.5', '>'] >>> header.get_header_list(edi_lines) ['DATAID=MT001', 'LAT=45.5']
- read_header(edi_lines)
Read and parse header information from EDI file lines.
Parses header lines from an EDI file and populates the Header object attributes with the corresponding values. Handles special cases like Phoenix-formatted EDI files and coordinate system normalization.
- Parameters:
edi_lines (list of str) – List of lines from an EDI file containing header information.
- Returns:
Updates the object’s attributes in place.
- Return type:
None
Examples
>>> header = Header() >>> edi_lines = ['>HEAD', 'DATAID=MT001', 'LAT=45:30:00', 'LON=-122:30:00', '>'] >>> header.read_header(edi_lines) >>> header.dataid 'mt001' >>> header.latitude 45.5
Notes
Station IDs are automatically validated and normalized to lowercase
Coordinate systems are normalized to ‘geographic’, ‘geomagnetic’, or ‘station’
Phoenix MT-Editor format is automatically detected
- write_header(longitude_format='LON', latlon_format='dms', required=False)
Write header information to a list of formatted lines for EDI output.
Formats all header attributes as EDI-compliant key-value pairs. Automatically updates file metadata (filedate, progvers, progname) to current values.
- Parameters:
longitude_format ({'LON', 'LONG'}, default 'LON') – Format for longitude field name in output.
latlon_format ({'dms', 'dd'}, default 'dms') – Format for latitude/longitude values. - ‘dms’: degrees:minutes:seconds (e.g., ‘45:30:00’) - ‘dd’: decimal degrees (e.g., ‘45.500000’)
required (bool, default False) – If True, only include required fields in output.
- Returns:
List of formatted header lines starting with ‘>HEAD’ and ending with a blank line. Each data line follows the format ‘KEY=value’.
- Return type:
list of str
Examples
>>> header = Header(dataid='mt001', latitude=45.5, longitude=-122.5) >>> lines = header.write_header(latlon_format='dd') >>> print(lines[0]) >HEAD >>> print(lines[1]) DATAID=mt001
>>> # Write with degrees-minutes-seconds format >>> lines_dms = header.write_header(latlon_format='dms') >>> # Latitude will be formatted as 45:30:00
Notes
filedate is automatically set to current UTC time
progvers is set to mt_metadata version
Zero declination values are omitted from output
None values are skipped