Make an MTH5 from ZEN data

This notebook provides an example of how to read in ZEN (.Z3D) files into an MTH5.

[1]:
from mth5.mth5 import MTH5
from mth5.io.zen import Z3DCollection
from mth5 import read_file
2022-09-07 18:20:17,973 [line 135] mth5.setup_logger - INFO: Logging file can be found C:\Users\jpeacock\OneDrive - DOI\Documents\GitHub\mth5\logs\mth5_debug.log

Z3D Collection

We will use the Z3DCollection to assemble the .z3d files into a logical order by schedule action or run.

Note: n_samples is an estimate based on file size not the data. To get an accurate number you should read in the full file. Same with start and end. start is based on the schedule start time which is usually 2 seconds earlier than the data start because of instrument buffer while chaning sampling rates. end is based on file size and sample rate.

The Z3DCollection.get_runs() will return a two level ordered dictionary (OrderedDict). The first level is keyed by station ID. These objects are in turn ordered dictionaries by run ID. Therefore you can loop over stations and runs.

[2]:
zc = Z3DCollection(r"c:\Users\jpeacock\OneDrive - DOI\mt\example_z3d_data")
runs = zc.get_runs(sample_rates=[4096, 256])
print(f"Found {len(runs)} station with {len(runs[list(runs.keys())[0]])} runs")
Found 1 station with 2 runs
[3]:
runs["100"]["sr4096_0001"]
[3]:
survey station run start end channel_id component fn sample_rate file_size n_samples sequence_number instrument_id calibration_fn
5 100 sr4096_0001 2022-05-17 12:59:57+00:00 2022-05-17 13:09:53.349854+00:00 4 ex c:\Users\jpeacock\OneDrive - DOI\mt\example_z3... 4096.0 9641572 2442649 1 ZEN_024 None
6 100 sr4096_0001 2022-05-17 12:59:57+00:00 2022-05-17 13:09:53.351807+00:00 5 ey c:\Users\jpeacock\OneDrive - DOI\mt\example_z3... 4096.0 9641604 2442657 1 ZEN_024 None
7 100 sr4096_0001 2022-05-17 12:59:57+00:00 2022-05-17 13:09:53.348877+00:00 1 hx c:\Users\jpeacock\OneDrive - DOI\mt\example_z3... 4096.0 9644628 2442645 1 ZEN_024 None
8 100 sr4096_0001 2022-05-17 12:59:57+00:00 2022-05-17 13:09:53.351318+00:00 2 hy c:\Users\jpeacock\OneDrive - DOI\mt\example_z3... 4096.0 9644156 2442655 1 ZEN_024 None
9 100 sr4096_0001 2022-05-17 12:59:57+00:00 2022-05-17 13:09:53.351562+00:00 3 hz c:\Users\jpeacock\OneDrive - DOI\mt\example_z3... 4096.0 9644160 2442656 1 ZEN_024 None

Build MTH5

Now that we have a logical collection of files, lets load them into an MTH5. We will simply loop of the stations, runs, and channels in the ordered dictionary.

There are a few things that we need to keep track of.

  • The station metadata pulled directly from the Z3D files can be input into the station metadata, be sure to use the write_metadata method to write the metadata to the MTH5.

  • The Z3D files have the coil response and zen response embedded in the file, so we can put those into the appropriate filter container in MTH5. This is important for calibrating later.

  • Since this is a MTH5 file version 0.2.0 the filters are in the survey_group so add them there.

  • If you want to calibrate the data set calibrate to True.

[4]:
calibrate = True
m = MTH5()
if calibrate:
    m.data_level = 2
m.open_mth5(zc.file_path.joinpath("from_z3d.h5"))
2022-09-07 18:20:18,860 [line 663] mth5.mth5.MTH5._initialize_file - INFO: Initialized MTH5 0.2.0 file c:\Users\jpeacock\OneDrive - DOI\mt\example_z3d_data\from_z3d.h5 in mode a
[5]:
survey_group = m.add_survey("test")
[6]:
%%time
for station_id in runs.keys():
    station_group = survey_group.stations_group.add_station(station_id)
    station_group.metadata.update(zc.station_metadata_dict[station_id])
    station_group.write_metadata()
    for run_id, run_df in runs[station_id].items():
        run_group = station_group.add_run(run_id)
        for row in run_df.itertuples():
            ch_ts = read_file(row.fn)
            # NOTE: this is where the calibration occurs
            if calibrate:
                ch_ts = ch_ts.remove_instrument_response()
            run_group.from_channel_ts(ch_ts)
2022-09-07 18:20:22,178 [line 221] mt_metadata.base.metadata.frequency_response_table_filter.complex_response - WARNING: Extrapolating, use values outside calibration frequencies with caution
2022-09-07 18:20:23,720 [line 221] mt_metadata.base.metadata.frequency_response_table_filter.complex_response - WARNING: Extrapolating, use values outside calibration frequencies with caution
2022-09-07 18:20:25,140 [line 221] mt_metadata.base.metadata.frequency_response_table_filter.complex_response - WARNING: Extrapolating, use values outside calibration frequencies with caution
2022-09-07 18:20:29,176 [line 221] mt_metadata.base.metadata.frequency_response_table_filter.complex_response - WARNING: Extrapolating, use values outside calibration frequencies with caution
2022-09-07 18:20:30,853 [line 221] mt_metadata.base.metadata.frequency_response_table_filter.complex_response - WARNING: Extrapolating, use values outside calibration frequencies with caution
2022-09-07 18:20:32,481 [line 221] mt_metadata.base.metadata.frequency_response_table_filter.complex_response - WARNING: Extrapolating, use values outside calibration frequencies with caution
Wall time: 14 s
[7]:
%%time
station_group.validate_station_metadata()
station_group.write_metadata()

survey_group.update_survey_metadata()
survey_group.write_metadata()
Wall time: 5.76 s

MTH5 Structure

Have a look at the MTH5 structure and make sure it looks correct.

[8]:
m
[8]:
/:
====================
    |- Group: Experiment
    --------------------
        |- Group: Reports
        -----------------
        |- Group: Standards
        -------------------
            --> Dataset: summary
            ......................
        |- Group: Surveys
        -----------------
            |- Group: test
            --------------
                |- Group: Filters
                -----------------
                    |- Group: coefficient
                    ---------------------
                        |- Group: dipole_55.00m
                        -----------------------
                        |- Group: dipole_56.00m
                        -----------------------
                        |- Group: zen_counts2mv
                        -----------------------
                    |- Group: fap
                    -------------
                        |- Group: ant4_2314_response
                        ----------------------------
                            --> Dataset: fap_table
                            ........................
                        |- Group: ant4_2324_response
                        ----------------------------
                            --> Dataset: fap_table
                            ........................
                        |- Group: ant4_2334_response
                        ----------------------------
                            --> Dataset: fap_table
                            ........................
                    |- Group: fir
                    -------------
                    |- Group: time_delay
                    --------------------
                    |- Group: zpk
                    -------------
                |- Group: Reports
                -----------------
                |- Group: Standards
                -------------------
                    --> Dataset: summary
                    ......................
                |- Group: Stations
                ------------------
                    |- Group: 100
                    -------------
                        |- Group: Transfer_Functions
                        ----------------------------
                        |- Group: sr256_0002
                        --------------------
                            --> Dataset: ex
                            .................
                            --> Dataset: ey
                            .................
                            --> Dataset: hx
                            .................
                            --> Dataset: hy
                            .................
                            --> Dataset: hz
                            .................
                        |- Group: sr4096_0001
                        ---------------------
                            --> Dataset: ex
                            .................
                            --> Dataset: ey
                            .................
                            --> Dataset: hx
                            .................
                            --> Dataset: hy
                            .................
                            --> Dataset: hz
                            .................
        --> Dataset: channel_summary
        ..............................
        --> Dataset: tf_summary
        .........................

Channel Summary

Have a look at the channel summary and make sure everything looks good.

[9]:
m.channel_summary.summarize()
m.channel_summary.to_dataframe()
[9]:
survey station run latitude longitude elevation component start end n_samples sample_rate measurement_type azimuth tilt units hdf5_reference run_hdf5_reference station_hdf5_reference
0 test 100 sr256_0002 40.497576 -116.821188 1456.7 ex 2022-05-17 13:09:58+00:00 2022-05-17 15:54:42+00:00 2530304 256.0 electric 0.0 0.0 count <HDF5 object reference> <HDF5 object reference> <HDF5 object reference>
1 test 100 sr256_0002 40.497576 -116.821188 1456.7 ey 2022-05-17 13:09:58+00:00 2022-05-17 15:54:42+00:00 2530304 256.0 electric 0.0 0.0 count <HDF5 object reference> <HDF5 object reference> <HDF5 object reference>
2 test 100 sr256_0002 40.497576 -116.821188 1456.7 hx 2022-05-17 13:09:58+00:00 2022-05-17 15:54:42+00:00 2530304 256.0 magnetic 0.0 0.0 count <HDF5 object reference> <HDF5 object reference> <HDF5 object reference>
3 test 100 sr256_0002 40.497576 -116.821188 1456.7 hy 2022-05-17 13:09:58+00:00 2022-05-17 15:54:42+00:00 2530304 256.0 magnetic 90.0 0.0 count <HDF5 object reference> <HDF5 object reference> <HDF5 object reference>
4 test 100 sr256_0002 40.497576 -116.821188 1456.7 hz 2022-05-17 13:09:58+00:00 2022-05-17 15:54:42+00:00 2530304 256.0 magnetic 0.0 0.0 count <HDF5 object reference> <HDF5 object reference> <HDF5 object reference>
5 test 100 sr4096_0001 40.497576 -116.821188 1456.7 ex 2022-05-17 12:59:58+00:00 2022-05-17 13:09:41.997559+00:00 2392054 4096.0 electric 0.0 0.0 count <HDF5 object reference> <HDF5 object reference> <HDF5 object reference>
6 test 100 sr4096_0001 40.497576 -116.821188 1456.7 ey 2022-05-17 12:59:58+00:00 2022-05-17 13:09:41.999023+00:00 2392060 4096.0 electric 0.0 0.0 count <HDF5 object reference> <HDF5 object reference> <HDF5 object reference>
7 test 100 sr4096_0001 40.497576 -116.821188 1456.7 hx 2022-05-17 12:59:58+00:00 2022-05-17 13:09:41.996094+00:00 2392048 4096.0 magnetic 0.0 0.0 count <HDF5 object reference> <HDF5 object reference> <HDF5 object reference>
8 test 100 sr4096_0001 40.497576 -116.821188 1456.7 hy 2022-05-17 12:59:58+00:00 2022-05-17 13:09:41.997070+00:00 2392052 4096.0 magnetic 90.0 0.0 count <HDF5 object reference> <HDF5 object reference> <HDF5 object reference>
9 test 100 sr4096_0001 40.497576 -116.821188 1456.7 hz 2022-05-17 12:59:58+00:00 2022-05-17 13:09:41.998779+00:00 2392059 4096.0 magnetic 0.0 0.0 count <HDF5 object reference> <HDF5 object reference> <HDF5 object reference>

Close the MTH5

This is important, you should close the file after you are done using it. Otherwise bad things can happen if you try to open it with another program or Python interpreter.

[10]:
m.close_mth5()
2022-09-07 18:20:39,445 [line 744] mth5.mth5.MTH5.close_mth5 - INFO: Flushing and closing c:\Users\jpeacock\OneDrive - DOI\mt\example_z3d_data\from_z3d.h5