Multi-dataset Survey

This example demonstrates the typical workflow for creating a GS file for an AEM survey in its entirety, i.e., the NetCDF file contains all related datasets together, e.g., raw data, processed data, inverted models, and derivative products. Specifically, this survey contains:

  1. Minimally processed (raw) AEM data and raw/processed magnetic data provided by SkyTEM

  2. Fully processed AEM data used as input to inversion

  3. Laterally constrained inverted resistivity models

  4. Point-data estimates of bedrock depth derived from the AEM models

  5. Interpolated magnetic and bedrock depth grids

Note: To make the size of this example more managable, some of the input datasets have been downsampled relative to the source files in the data release referenced below.

Dataset Reference: Minsley, B.J, Bloss, B.R., Hart, D.J., Fitzpatrick, W., Muldoon, M.A., Stewart, E.K., Hunt, R.J., James, S.R., Foks, N.L., and Komiskey, M.J., 2022, Airborne electromagnetic and magnetic survey data, northeast Wisconsin (ver. 1.1, June 2022): U.S. Geological Survey data release, https://doi.org/10.5066/P93SY9LI.

import matplotlib.pyplot as plt
from os.path import join
import numpy as np
import gspy
from gspy import Survey
import xarray as xr
from pprint import pprint

Convert the Skytem csv data to NetCDF

Initialize the Survey

# Path to example files
data_path = '..//data_files//skytem_csv'

# Survey metadata file
metadata = join(data_path, "data//skytem_survey.yml")

# Establish the Survey
survey = Survey.from_dict(metadata)

data_container = survey.gs.add_container('data', **dict(content = "raw and processed data",
                                                        comment = "This is a test"))

1 - Raw Data - Import raw AEM data from CSV-format. Define input data file and associated metadata file

d_data1 = join(data_path, 'data//skytem_contractor_data.csv')
d_supp1 = join(data_path, 'data//skytem_contractor_data.yml')

# Add the raw AEM data as a tabular dataset
data_container.gs.add(key='raw_data', data_filename=d_data1, metadata_file=d_supp1, system=survey.nominal_system)
<xarray.DataTree 'raw_data'>
Group: /survey/data/raw_data
│   Dimensions:          (index: 2000, hm_gate_times: 32, lm_gate_times: 28)
│   Coordinates:
│     * index            (index) int32 8kB 0 1 2 3 4 5 ... 1995 1996 1997 1998 1999
│     * hm_gate_times    (hm_gate_times) float64 256B 2.886e-05 ... 0.003544
│     * lm_gate_times    (lm_gate_times) float64 224B -1.135e-06 ... 0.001394
│       spatial_ref      float64 8B 0.0
│       x                (index) float64 16kB 7.243e+05 7.239e+05 ... 6.952e+05
│       y                (index) float64 16kB 4.916e+05 4.917e+05 ... 4.522e+05
│       z                (index) float64 16kB 176.8 217.3 231.6 ... 240.8 250.0
│       t                (index) float64 16kB 4.422e+04 4.422e+04 ... 4.422e+04
│   Data variables: (12/34)
│       _60hz_intensity  (index) float64 16kB -5.744e-08 -4.722e-08 ... 1.251e-07
│       alt              (index) float64 16kB 276.3 270.1 274.2 ... 283.5 285.1
│       anglex           (index) float64 16kB 3.284 1.052 2.916 ... 0.9546 3.211
│       angley           (index) float64 16kB -0.9891 -1.999 ... -1.946 0.1495
│       base_mag         (index) float64 16kB -1e+04 -1e+04 -1e+04 ... -1e+04 -1e+04
│       curr_hm          (index) float64 16kB 111.6 111.6 111.5 ... 114.2 114.2
│       ...               ...
│       mag_raw          (index) float64 16kB 5.481e+04 5.481e+04 ... 5.487e+04
│       n_nad83          (index) float64 16kB 4.916e+05 4.917e+05 ... 4.522e+05
│       n_wgs84          (index) float64 16kB 4.968e+06 4.969e+06 ... 4.93e+06
│       rmf              (index) float64 16kB 210.6 210.6 197.3 ... 330.8 386.6
│       time             (index) object 16kB '17:14:42' '17:15:02' ... '19:00:43'
│       tmi              (index) float64 16kB 5.482e+04 5.482e+04 ... 5.487e+04
│   Attributes:
│       uuid:        9584e8b0-2120-479b-b9ce-1d823ff86920
│       content:     raw data
│       comment:     This dataset includes minimally processed (raw) AEM and raw/...
│       type:        data
│       structure:   tabular
│       mode:        airborne
│       method:      electromagnetic
│       submethod:   time domain
│       instrument:  skytem
│       property:
└── Group: /survey/data/raw_data/nominal_system
        Dimensions:                                      (gate_times: 22, nv: 2,
                                                          lm_gate_times: 28,
                                                          hm_gate_times: 32,
                                                          n_loop_vertices: 8, xyz: 3,
                                                          n_transmitter: 2,
                                                          transmitter_lm_waveform_time: 21,
                                                          transmitter_hm_waveform_time: 36,
                                                          n_receiver: 2, n_component: 4)
        Coordinates:
          * gate_times                                   (gate_times) float64 176B 5....
          * nv                                           (nv) int64 16B 0 1
          * n_loop_vertices                              (n_loop_vertices) int64 64B ...
          * xyz                                          (xyz) int64 24B 0 1 2
          * n_transmitter                                (n_transmitter) int64 16B 0 1
          * transmitter_lm_waveform_time                 (transmitter_lm_waveform_time) float64 168B ...
          * transmitter_hm_waveform_time                 (transmitter_hm_waveform_time) float64 288B ...
          * n_receiver                                   (n_receiver) int64 16B 0 1
          * n_component                                  (n_component) int64 32B 0 1 2 3
        Data variables: (12/31)
            gate_times_bnds                              (gate_times, nv) float64 352B ...
            lm_gate_times_bnds                           (lm_gate_times, nv) float64 448B ...
            hm_gate_times_bnds                           (hm_gate_times, nv) float64 512B ...
            n_loop_vertices_bnds                         (n_loop_vertices, nv) float64 128B ...
            xyz_bnds                                     (xyz, nv) float64 48B -0.5 ....
            transmitter_label                            (n_transmitter) <U2 16B 'LM'...
            ...                                           ...
            component_receivers                          (n_component) <U1 16B 'z' .....
            component_txrx_dx                            (n_component) float64 32B -1...
            component_txrx_dy                            (n_component) float64 32B 0....
            component_txrx_dz                            (n_component) float64 32B -2...
            component_data_type                          (n_component) <U4 64B 'dBdt'...
            component_gate_times                         (n_component) <U13 208B 'lm_...
        Attributes:
            type:                      system
            mode:                      airborne
            method:                    electromagnetic
            submethod:                 time domain
            instrument:                skytem 304M
            uuid:                      df49f8a4-c5d3-48da-965e-d36f7d219104
            name:                      nominal_system
            data_normalized:           True
            skytem_skb_gex_available:  True
            reference_frame:           right-handed positive down
            coil_orientations:         X, Z


2 - Processed Data - Import processed AEM data from CSV-format. Define input data file and associated metadata file

d_data2 = join(data_path, 'data//skytem_processed_data.csv')
d_supp2 = join(data_path, 'data//skytem_processed_data.yml')

system = {"skytem_system" : survey["nominal_system"].isel(lm_gate_times=np.s_[1:], hm_gate_times=np.s_[10:]),
          "magnetic_system" : survey["magnetic_system"]}

# Add the processed AEM data as a tabular dataset
pd = data_container.gs.add(key='processed_data', data_filename=d_data2, metadata_file=d_supp2, system=system)

3 - Inverted Models -

# Create a new container for models
model_container = survey.gs.add_container('models', **dict(content = "Inverted models",
                                                          comment = "This is a test"))

# pprint(survey.gs.get_all_attr('standard_name'))
print(survey.gs.tree)

# Import inverted AEM models from CSV-format.
# Define input data file and associated metadata file
m_data3 = join(data_path, 'model//skytem_inverted_models.csv')
m_supp3 = join(data_path, 'model//skytem_inverted_models.yml')

# Add the inverted AEM models as a tabular dataset
model_container.gs.add(key='inverted_models', data_filename=m_data3, metadata_file=m_supp3)
b8468fbb-3e5b-4b88-b268-2dd8d80798fa /survey
df49f8a4-c5d3-48da-965e-d36f7d219104 /survey/nominal_system
06ce1c1c-c25c-42e3-9179-924bf2e7a7d8 /survey/magnetic_system
9584e8b0-2120-479b-b9ce-1d823ff86920 /survey/data/raw_data
b9987735-d1a4-420b-a695-d79385997cf3 /survey/data/processed_data
df49f8a4-c5d3-48da-965e-d36f7d219104 /survey/data/raw_data/nominal_system
df49f8a4-c5d3-48da-965e-d36f7d219104 /survey/data/processed_data/skytem_system
06ce1c1c-c25c-42e3-9179-924bf2e7a7d8 /survey/data/processed_data/magnetic_system
<xarray.DataTree 'inverted_models'>
Group: /survey/models/inverted_models
    Dimensions:           (index: 2000, layer_depth: 40, nv: 2)
    Coordinates:
      * index             (index) int32 8kB 0 1 2 3 4 5 ... 1995 1996 1997 1998 1999
      * layer_depth       (layer_depth) float64 320B 0.375 1.16 2.02 ... 262.6 343.8
      * nv                (nv) int64 16B 0 1
        spatial_ref       float64 8B 0.0
        x                 (index) float64 16kB 7.243e+05 7.241e+05 ... 7.144e+05
        y                 (index) float64 16kB 4.916e+05 4.916e+05 ... 4.678e+05
        z                 (index) float64 16kB 177.1 190.4 208.5 ... 203.9 204.6
        t                 (index) float64 16kB 4.422e+04 4.422e+04 ... 4.422e+04
    Data variables: (12/22)
        layer_depth_bnds  (layer_depth, nv) float64 640B 0.0 0.75 ... 275.0 412.5
        pindex            (index) int64 16kB 0 10 20 30 ... 21086 21096 21106 21116
        sline_no          (index) int64 16kB 100100 100100 100100 ... 103300 103300
        e_n83wtm          (index) float64 16kB 7.243e+05 7.241e+05 ... 7.144e+05
        n_n83wtm          (index) float64 16kB 4.916e+05 4.916e+05 ... 4.678e+05
        timestamp         (index) float64 16kB 4.422e+04 4.422e+04 ... 4.422e+04
        ...                ...
        RHO_I_STD         (index, layer_depth) float64 640kB 3.78 2.32 ... 1.32 1.42
        DEP_TOP           (index, layer_depth) float64 640kB 0.0 0.75 ... 275.0
        DEP_BOT           (index, layer_depth) float64 640kB 0.75 1.57 ... 412.5
        doi_conservative  (index) float64 16kB 168.7 190.7 189.8 ... 225.5 216.1
        doi_standard      (index) float64 16kB 186.8 212.1 208.0 ... 256.1 248.1
        line_no           (index) int64 16kB 100101 100101 100101 ... 103301 103301
    Attributes:
        uuid:        eb9e16e0-bf2d-4470-8473-b0f4ebfcb4cd
        content:     inverted resistivity models
        comment:     This dataset includes inverted resistivity models derived fr...
        type:        model
        structure:   tabular
        mode:        airborne
        method:      electromagnetic
        submethod:   time domain
        instrument:  skytem
        property:    electrical resistivity


4 - Bedrock Picks - Import AEM-based estimated of depth to bedrock from CSV-format. Define input data file and associated metadata file

d_data4 = join(data_path, 'data//top_dolomite_blocky_lidar.csv')
d_supp4 = join(data_path, 'data//bedrock_picks.yml')

# Add the AEM-based estimated of depth to bedrock as a tabular dataset
data_container.gs.add(key='depth_to_bedrock', data_filename=d_data4, metadata_file=d_supp4)
<xarray.DataTree 'depth_to_bedrock'>
Group: /survey/data/depth_to_bedrock
    Dimensions:       (index: 82864)
    Coordinates:
      * index         (index) int32 331kB 0 1 2 3 4 ... 82860 82861 82862 82863
        spatial_ref   float64 8B 0.0
        x             (index) float64 663kB 7.243e+05 7.243e+05 ... 6.594e+05
        y             (index) float64 663kB 4.916e+05 4.916e+05 ... 4e+05 4e+05
    Data variables:
        id            (index) int64 663kB 1 2 3 4 5 ... 102684 102685 102686 102687
        e_n83wtm      (index) float64 663kB 7.243e+05 7.243e+05 ... 6.594e+05
        n_n83wtm      (index) float64 663kB 4.916e+05 4.916e+05 ... 4e+05 4e+05
        br_elevation  (index) float64 663kB 167.8 178.3 180.2 ... 291.3 291.3 292.7
        zstd          (index) float64 663kB 1.01 1.01 1.01 1.01 ... 1.11 1.11 1.11
        origintype    (index) int64 663kB 3 3 3 3 3 3 3 3 3 3 ... 0 0 0 0 0 0 0 0 0
        editdate      (index) object 663kB '6/6/2021 21:46' ... '7/23/2021 23:22'
    Attributes:
        uuid:        ec0cee42-b500-4882-845a-ba43d78df136
        content:     bedrock elevation points
        comment:     This dataset includes AEM-derived point estimates of the ele...
        type:        data
        structure:   tabular
        mode:
        method:
        submethod:
        instrument:
        property:    


5 - Derivative Maps -

# We can add arbitrarily named containers to the survey
derived_products = survey.gs.add_container('derived_products', **dict(content = "products derived from other data and models"))

# Import interpolated bedrock and magnetic maps from TIF-format.
# Define input metadata file (which contains the TIF filenames linked to variable names)
m_supp5 = join(data_path, 'data//magnetics_bedrock_picks.yml')

# Add the interpolated maps as a raster dataset
derived_products.gs.add(key='maps', metadata_file=m_supp5)

print(survey.gs.tree)
b8468fbb-3e5b-4b88-b268-2dd8d80798fa /survey
df49f8a4-c5d3-48da-965e-d36f7d219104 /survey/nominal_system
06ce1c1c-c25c-42e3-9179-924bf2e7a7d8 /survey/magnetic_system
9584e8b0-2120-479b-b9ce-1d823ff86920 /survey/data/raw_data
b9987735-d1a4-420b-a695-d79385997cf3 /survey/data/processed_data
ec0cee42-b500-4882-845a-ba43d78df136 /survey/data/depth_to_bedrock
eb9e16e0-bf2d-4470-8473-b0f4ebfcb4cd /survey/models/inverted_models
dbfb5f8c-bd97-4e75-89ba-6c9e633f210d /survey/derived_products/maps
df49f8a4-c5d3-48da-965e-d36f7d219104 /survey/data/raw_data/nominal_system
df49f8a4-c5d3-48da-965e-d36f7d219104 /survey/data/processed_data/skytem_system
06ce1c1c-c25c-42e3-9179-924bf2e7a7d8 /survey/data/processed_data/magnetic_system

Save to NetCDF file

d_out = join(data_path, 'skytem.nc')
survey.gs.to_netcdf(d_out)

The gspy goal is to have the complete survey in a single file. However, we can also save containers or datasets separately.

data_container.gs.to_netcdf(join(data_path, 'test_datacontainer.nc'))

Reading back in

new_survey = gspy.open_datatree(d_out)['survey']

# print(new_survey)

# #%%
# # Plotting
# plt.figure()
# new_survey['data']['raw_data']['height'].plot()
# plt.tight_layout()

# pd = new_survey['data']['processed_data']
# plt.figure()
# pd['elevation'].plot()
# plt.tight_layout()

# m = new_survey['derived_products']['maps']
# plt.figure()
# m['magnetic_tmi'].plot(cmap='jet')
# plt.tight_layout()

# plt.show()

Total running time of the script: (0 minutes 1.067 seconds)

Gallery generated by Sphinx-Gallery