Cross-over levelling: trend vs wavelength based

Cross-over levelling: trend vs wavelength based#

[1]:
%load_ext autoreload
%autoreload 2


import logging

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import plotly.io as pio
import verde as vd

import airbornegeo

# setup logging to get some additional info from the airbornegeo functions
logging.getLogger("airbornegeo").setLevel("INFO")
logging.basicConfig()
pio.renderers.default = "notebook"

Load data#

This notebook uses the data and intersections dataframes from the previous notebook Cross-over-errors.

[2]:
data_df = pd.read_csv("data/AGAP_magnetic_survey_processed_blocked.csv")
data_df = data_df[
    [
        "easting",
        "northing",
        "height",
        "line",
        "unixtime",
        "distance_along_line",
        "mag",
    ]
]

# define flight lines vs tie lines
data_df["line_type"] = np.where(data_df.line >= 142, 1, 0)

data_df = data_df.rename(columns={"distance_along_line": "along_line_distance"})

# keep a subset of tie lines and just 1 flight line
line = 77
lines_to_keep = [
    150,
    151,
    152,
    153,
    154,
    155,
    156,
    157,
    158,
    159,
    160,
    161,
    162,
    164,
    165,
    166,
    167,
]
lines_to_keep = np.append(lines_to_keep, line)

data_df = data_df[(data_df.line.isin(lines_to_keep))]

data_df.head()
[2]:
easting northing height line unixtime along_line_distance mag line_type
155245 613796.184341 108259.149034 3793.1 77 1.230970e+09 72.986528 35.54 0
155246 614014.105815 108288.966298 3791.7 77 1.230970e+09 292.943124 35.18 0
155247 614232.757811 108315.269624 3791.9 77 1.230970e+09 513.172378 34.43 0
155248 614414.514181 108337.253486 3793.5 77 1.230970e+09 696.255616 33.60 0
155249 614594.969358 108363.481597 3794.7 77 1.230970e+09 878.614978 32.61 0
[3]:
vmin, vmax = vd.minmax(data_df.mag, min_percentile=5, max_percentile=95)
ax = data_df[::10].plot.scatter(
    "easting",
    "northing",
    c="mag",
    s=1,
    cmap="viridis",
    vmin=vmin,
    vmax=vmax,
    title="Unlevelled data",
)
ax.set_aspect("equal")
_images/levelling_05_crossover_levelling_trend_vs_wavelength_4_0.png
[ ]:
# Create Survey object with data and column bindings
survey = airbornegeo.Survey(
    data_df,
    line_column="line",
    line_type_column="line_type",
    distance_column="along_line_distance",
)

# calculate theoretical intersection points
survey.create_intersection_table(method="groups")

# interpolate mag data at intersections
survey.interpolate_intersections(
    to_interp="mag",
    window_width=500,
    method="cubic",
    extrapolate=False,
)

# calculate cross-over errors
survey.calculate_crossover_errors(data_col="mag")

# Capture baseline inters for branching (forked intersection pattern)
inters = survey.intersections
[ ]:
survey.plot_line_and_crosses(
    y=["mag"], x="along_line_distance", line=line, y_axes=[1], plot_inters=True
)
[ ]:
survey.intersections.plot.scatter(
    "dist_along_line1",
    "crossover_error_0",
    marker="^",
    s=30,
    c="r",
    # ax=axs,
    label="mistie values",
)

Level with fitting a trend to the cross-overs#

By fitting a trend to the mistie values, we can create levelling correction values to add to the entire line. For this, we can choose the order of the trend. A trend order of 0 results in a vertical shift, a trend order of 1 results in tilting line, and a trend of order 2 gives a polynomial.

[ ]:
# Level with trend degree 0 - reset to baseline for independent branch
survey.intersections = inters
survey.crossover_pair_levelling(
    lines_to_level=[line],
    data_col="mag",
    levelled_col="mag_levelled_trend0",
    degree=0,
)

# calculate levelling correction
survey.data["levelling_correction_trend0"] = (
    survey.data.mag - survey.data.mag_levelled_trend0
)
[ ]:
# Level with trend degree 1 - reset to baseline for independent branch
survey.intersections = inters
survey.crossover_pair_levelling(
    lines_to_level=[line],
    data_col="mag",
    levelled_col="mag_levelled_trend1",
    degree=1,
)

# calculate levelling correction
survey.data["levelling_correction_trend1"] = (
    survey.data.mag - survey.data.mag_levelled_trend1
)
[ ]:
# Level with trend degree 2 - reset to baseline for independent branch
survey.intersections = inters
survey.crossover_pair_levelling(
    lines_to_level=[line],
    data_col="mag",
    levelled_col="mag_levelled_trend2",
    degree=2,
)

# calculate levelling correction
survey.data["levelling_correction_trend2"] = (
    survey.data.mag - survey.data.mag_levelled_trend2
)
[ ]:
fig, axs = plt.subplots(1, 1, figsize=(10, 5))

ax = survey.intersections.plot.scatter(
    "dist_along_line1",
    "crossover_error_0",
    marker="^",
    s=30,
    c="r",
    ax=axs,
    label="mistie values",
)

ax = survey.data[survey.data.line == line].plot.scatter(
    "along_line_distance",
    "levelling_correction_trend0",
    s=0.2,
    c="g",
    ax=axs,
    label="Levelling correction trend 0",
)
ax = survey.data[survey.data.line == line].plot.scatter(
    "along_line_distance",
    "levelling_correction_trend1",
    s=0.2,
    c="purple",
    ax=axs,
    label="Levelling correction trend 1",
)
ax = survey.data[survey.data.line == line].plot.scatter(
    "along_line_distance",
    "levelling_correction_trend2",
    s=0.2,
    c="b",
    ax=axs,
    label="Levelling correction trend 2",
)
ax.set_ylabel("nT")
ax.legend(markerscale=2)
plt.show()

Wavelength-based levelling#

In the above cells, we calculate cross-over errors, and fit trends of specified orders to these values, yielding a levelling correction.

An alternative method is to interpolate these cross-over errors along the entire line and low-pass filter the results. This means we can choose the wavelength of our levelling correction, and our levelling corrections are independent of line length.

[ ]:
# Wavelength-based levelling with 100km filter - reset to baseline for independent branch
survey.intersections = inters
survey.crossover_pair_levelling(
    lines_to_level=[line],
    data_col="mag",
    levelled_col="mag_levelled_filter",
    filter_type="g100000",
)

# calculate levelling correction
survey.data["levelling_correction_100km_filter"] = (
    survey.data.mag - survey.data.mag_levelled_filter
)
[ ]:
# Wavelength-based levelling with 500km filter - reset to baseline for independent branch
survey.intersections = inters
survey.crossover_pair_levelling(
    lines_to_level=[line],
    data_col="mag",
    levelled_col="mag_levelled_filter",
    filter_type="g500000",
)

# calculate levelling correction
survey.data["levelling_correction_500km_filter"] = (
    survey.data.mag - survey.data.mag_levelled_filter
)
[ ]:
# Wavelength-based levelling with 500km filter (repeated) - reset to baseline for independent branch
survey.intersections = inters
survey.crossover_pair_levelling(
    lines_to_level=[line],
    data_col="mag",
    levelled_col="mag_levelled_filter",
    filter_type="g500000",
)

# calculate levelling correction
survey.data["levelling_correction_500km_filter"] = (
    survey.data.mag - survey.data.mag_levelled_filter
)
[ ]:
# Wavelength-based levelling with 1000km filter - reset to baseline for independent branch
survey.intersections = inters
survey.crossover_pair_levelling(
    lines_to_level=[line],
    data_col="mag",
    levelled_col="mag_levelled_filter",
    filter_type="g1000000",
)

# calculate levelling correction
survey.data["levelling_correction_1000km_filter"] = (
    survey.data.mag - survey.data.mag_levelled_filter
)
[ ]:
fig, axs = plt.subplots(1, 1, figsize=(10, 5))


ax = survey.intersections.plot.scatter(
    "dist_along_line1",
    "crossover_error_0",
    marker="^",
    s=30,
    c="r",
    ax=axs,
    label="mistie values",
)
ax = survey.data[survey.data.line == line].plot.scatter(
    "along_line_distance",
    "levelling_correction_100km_filter",
    s=0.2,
    c="g",
    ax=axs,
    label="Levelling correction 100 km filter",
)
ax = survey.data[survey.data.line == line].plot.scatter(
    "along_line_distance",
    "levelling_correction_500km_filter",
    s=0.2,
    c="purple",
    ax=axs,
    label="Levelling correction 500 km filter",
)
ax = survey.data[survey.data.line == line].plot.scatter(
    "along_line_distance",
    "levelling_correction_1000km_filter",
    s=0.2,
    c="b",
    ax=axs,
    label="Levelling correction 1000 km filter",
)
ax.set_ylabel("nT")
ax.legend(markerscale=2)
plt.show()
[ ]: