mt_metadata.transfer_functions.io.edi.metadata ============================================== .. py:module:: mt_metadata.transfer_functions.io.edi.metadata Submodules ---------- .. toctree:: :maxdepth: 1 /source/api/mt_metadata/transfer_functions/io/edi/metadata/data_section/index /source/api/mt_metadata/transfer_functions/io/edi/metadata/define_measurement/index /source/api/mt_metadata/transfer_functions/io/edi/metadata/emeasurement/index /source/api/mt_metadata/transfer_functions/io/edi/metadata/header/index /source/api/mt_metadata/transfer_functions/io/edi/metadata/hmeasurement/index /source/api/mt_metadata/transfer_functions/io/edi/metadata/information/index Classes ------- .. autoapisummary:: mt_metadata.transfer_functions.io.edi.metadata.EMeasurement mt_metadata.transfer_functions.io.edi.metadata.HMeasurement mt_metadata.transfer_functions.io.edi.metadata.Information mt_metadata.transfer_functions.io.edi.metadata.DataSection mt_metadata.transfer_functions.io.edi.metadata.DefineMeasurement mt_metadata.transfer_functions.io.edi.metadata.Header Package Contents ---------------- .. py:class:: EMeasurement(**data) Bases: :py:obj:`mt_metadata.base.MetadataBase` Base 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. .. attribute:: _skip_equals Private attribute listing fields to skip in equality comparisons :type: list[str] .. attribute:: _fields Private attribute caching field information :type: dict[str, Any] .. rubric:: 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 .. py:attribute:: id :type: 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']})] .. py:attribute:: chtype :type: 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']})] .. py:attribute:: x :type: 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']})] .. py:attribute:: x2 :type: 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']})] .. py:attribute:: y :type: 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']})] .. py:attribute:: y2 :type: 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']})] .. py:attribute:: z :type: 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']})] .. py:attribute:: z2 :type: 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']})] .. py:attribute:: azm :type: 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']})] .. py:attribute:: acqchan :type: Annotated[str, Field(default='', description='description of acquired channel', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['100.0']})] .. py:method:: validate_id(value) :classmethod: Ensure id is a float or None, convert if necessary .. py:method:: update_azimuth_from_coords() Update azm based on coordinates after validation .. py:property:: dipole_length :type: float dipole length based on x, y, z coordinates .. py:property:: azimuth :type: float aximuth based on x, y coordinates .. py:property:: channel_number :type: int Extract channel number from acqchan. .. py:method:: write_meas_line() write string :return: DESCRIPTION :rtype: TYPE .. py:class:: HMeasurement(**data) Bases: :py:obj:`mt_metadata.base.MetadataBase` Base 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. .. attribute:: _skip_equals Private attribute listing fields to skip in equality comparisons :type: list[str] .. attribute:: _fields Private attribute caching field information :type: dict[str, Any] .. rubric:: 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 .. py:attribute:: id :type: 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']})] .. py:attribute:: chtype :type: 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']})] .. py:attribute:: x :type: 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']})] .. py:attribute:: y :type: 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']})] .. py:attribute:: z :type: 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']})] .. py:attribute:: azm :type: 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']})] .. py:attribute:: dip :type: 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']})] .. py:attribute:: acqchan :type: Annotated[str, Field(default='', description='description of acquired channel', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['100.0']})] .. py:method:: validate_id(value) :classmethod: Ensure id is a float or None, convert if necessary .. py:property:: channel_number :type: int Extract channel number from acqchan. .. py:method:: write_meas_line() write string :return: DESCRIPTION :rtype: TYPE .. py:class:: Information(**data) Bases: :py:obj:`mt_metadata.base.MetadataBase` Contain, 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. .. py:attribute:: info_dict :type: dict[str, str | list | None] :value: None .. py:method:: read_info(edi_lines) Read information section and parse directly to info_dict. :param edi_lines: List of lines from the EDI file. :type edi_lines: list[str] .. py:method:: write_info() write out information .. py:class:: DataSection(**data) Bases: :py:obj:`mt_metadata.base.MetadataBase` DataSection 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 :param fn: full path to .edi file to read in. :type fn: string ================= ==================================== ======== =========== 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 [1]_ no ================= ==================================== ======== =========== .. [1] Changes these values to change what is written to edi file .. py:attribute:: nfreq :type: Annotated[int, Field(default=0, description='Number of frequencies', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': [16, 1]})] .. py:attribute:: sectid :type: 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']})] .. py:attribute:: nchan :type: Annotated[int, Field(default=0, description='Number of channels in the transfer function', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': [7]})] .. py:attribute:: maxblocks :type: Annotated[int, Field(default=999, description='Maximum number of data blocks', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': [999]})] .. py:attribute:: ex :type: Annotated[str | None, Field(default=None, description='Measurement ID for EX', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['1']})] .. py:attribute:: ey :type: Annotated[str | None, Field(default=None, description='Measurement ID for EY', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['2']})] .. py:attribute:: hx :type: Annotated[str | None, Field(default=None, description='Measurement ID for HX', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['3']})] .. py:attribute:: hy :type: Annotated[str | None, Field(default=None, description='Measurement ID for HY', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['4']})] .. py:attribute:: hz :type: Annotated[str | None, Field(default=None, description='Measurement ID for HZ', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['5']})] .. py:attribute:: rrhx :type: Annotated[str | None, Field(default=None, description='Measurement ID for RRHX', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['6']})] .. py:attribute:: rrhy :type: Annotated[str | None, Field(default=None, description='Measurement ID for RRHY', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['7']})] .. py:method:: get_data(edi_lines) Read in the data of the file, will detect if reading spectra or impedance. .. py:method:: read_data(edi_lines) Read data section .. py:method:: write_data(data_list = None, over_dict = None) Write the data section to a list of strings. .. py:method:: 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. .. py:class:: DefineMeasurement(**data) Bases: :py:obj:`mt_metadata.base.MetadataBase` DefineMeasurement 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 :param fn: full path to .edi file to read in. :type fn: string ================= ==================================== ======== =========== 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 None yes defining the measurement made [1]__ 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 [3]__ no section. ================= ==================================== ======== =========== .. [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 .. py:attribute:: maxchan :type: Annotated[int, Field(default=999, description='maximum number of channels', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['16']})] .. py:attribute:: maxrun :type: Annotated[int, Field(default=999, description='maximum number of runs', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['999']})] .. py:attribute:: maxmeas :type: Annotated[int, Field(default=7, description='maximum number of measurements', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['999']})] .. py:attribute:: reftype :type: 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']})] .. py:attribute:: refloc :type: Annotated[str | None, Field(default=None, description='Description of location reference center point.', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['here']})] .. py:attribute:: reflat :type: Annotated[float, Field(default=0, description='Latitude of reference center point.', alias=None, json_schema_extra={'units': 'degrees', 'required': False, 'examples': ['0']})] .. py:attribute:: reflon :type: Annotated[float, Field(default=0, description='Longitude reference center point.', alias=None, json_schema_extra={'units': 'degrees', 'required': False, 'examples': ['0']})] .. py:attribute:: refelev :type: Annotated[float, Field(default=0, description='Elevation reference center point.', alias=None, json_schema_extra={'units': 'meters', 'required': False, 'examples': ['0']})] .. py:attribute:: units :type: 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']})] .. py:attribute:: measurements :type: 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(...)}"]})] .. py:method:: validate_units(value) :classmethod: .. py:method:: validate_position(value, info) :classmethod: .. py:property:: channel_ids :type: dict[str, str] .. py:method:: get_measurement_lists(edi_lines) get measurement list including measurement setup .. attribute:: edi_lines lines from the edi file to parse :type: str .. py:method:: 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 .. py:method:: write_measurement(longitude_format = 'LON', latlon_format = 'degrees') write_measurement writes the define measurement section of the edi file. :param longitude_format: longitude format [ "LONG" | "LON" ] , by default "LON" :type longitude_format: str, optional :param latlon_format: 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. :type latlon_format: str, optional :returns: list of lines for the define measurement section or an empty list if no measurements are defined. :rtype: list[str] :raises ValueError: If a value cannot be converted to a float or if the longitude format is not recognized. .. py:method:: from_metadata(channel) from_metadata converts a channel object into a measurement object and sets the attributes for the measurement object. :param channel: The channel object to convert into a measurement object. :type channel: Electric | Magnetic | Auxiliary .. py:property:: channels_recorded :type: list[str] Get the channels recorded .. py:class:: Header(**data) Bases: :py:obj:`mt_metadata.common.BasicLocation`, :py:obj:`mt_metadata.common.GeographicLocation` A partial location class that only includes the latitude, longitude, and elevation. This is used to avoid circular imports. .. py:attribute:: acqby :type: 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']})] .. py:attribute:: acqdate :type: 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']})] .. py:attribute:: coordinate_system :type: 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']})] .. py:attribute:: dataid :type: Annotated[str, Field(default='', description='station ID.', alias=None, json_schema_extra={'units': None, 'required': True, 'examples': ['mt001']})] .. py:attribute:: enddate :type: 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']})] .. py:attribute:: empty :type: 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']})] .. py:attribute:: fileby :type: 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']})] .. py:attribute:: filedate :type: 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']})] .. py:attribute:: progdate :type: 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']})] .. py:attribute:: progname :type: 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']})] .. py:attribute:: progvers :type: 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']})] .. py:attribute:: project :type: 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']})] .. py:attribute:: prospect :type: 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']})] .. py:attribute:: loc :type: 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']})] .. py:attribute:: declination :type: 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)']})] .. py:attribute:: stdvers :type: 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']})] .. py:attribute:: survey :type: Annotated[str | None, Field(default=None, description='Name of the survey', alias=None, json_schema_extra={'units': None, 'required': False, 'examples': ['CONUS']})] .. py:attribute:: units :type: 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']})] .. py:method:: validate_acqdate(field_value) :classmethod: .. py:method:: validate_units(value) :classmethod: .. py:method:: 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. :param edi_lines: List of lines from an EDI file to parse for header information. :type edi_lines: list of str :returns: List of header key-value pairs in the format 'key=value'. :rtype: list of str .. rubric:: Examples >>> header = Header() >>> edi_lines = ['>HEAD', 'DATAID=MT001', 'LAT=45.5', '>'] >>> header.get_header_list(edi_lines) ['DATAID=MT001', 'LAT=45.5'] .. py:method:: 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. :param edi_lines: List of lines from an EDI file containing header information. :type edi_lines: list of str :returns: Updates the object's attributes in place. :rtype: None .. rubric:: 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 .. rubric:: 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 .. py:method:: 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. :param longitude_format: Format for longitude field name in output. :type longitude_format: {'LON', 'LONG'}, default 'LON' :param latlon_format: Format for latitude/longitude values. - 'dms': degrees:minutes:seconds (e.g., '45:30:00') - 'dd': decimal degrees (e.g., '45.500000') :type latlon_format: {'dms', 'dd'}, default 'dms' :param required: If True, only include required fields in output. :type required: bool, default False :returns: List of formatted header lines starting with '>HEAD' and ending with a blank line. Each data line follows the format 'KEY=value'. :rtype: list of str .. rubric:: 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 .. rubric:: 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