5. Tie line levelling#
[1]:
%load_ext autoreload
%autoreload 2
import logging
import geopandas as gpd
import pandas as pd
import plotly.io as pio
import airbornegeo
logging.getLogger("airbornegeo").setLevel("INFO")
logging.basicConfig()
pio.renderers.default = "notebook"
/home/airbornegeo/airbornegeo/.pixi/envs/default/lib/python3.14/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
5.1. Load data#
This is a subset of the BAS AGAP survey over Antarctica’s Gamburtsev Subglacial Mountains. The file is download and subset in the notebook AGAP_magnetic_survey, and the BAS processing steps are repeated in the notebook processing_AGAP_magnetic_survey.
[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",
]
]
# for run faster, limit number of lines
# for run faster, limit number of lines
data_df = data_df[~data_df.line.between(133, 142)]
data_df = data_df[~data_df.line.between(168, 176)]
data_df = data_df[
(data_df.line.isin(data_df.line.unique()[::2])) | (data_df.line >= 143)
]
# define flight lines vs tie lines with column 'tie' which is True or False
data_df["tie"] = False
data_df.loc[data_df.line >= 142, "tie"] = True
data_df.head()
[2]:
| easting | northing | height | line | unixtime | distance_along_line | mag | tie | |
|---|---|---|---|---|---|---|---|---|
| 0 | 621099.093988 | 159056.748193 | 4110.45 | 1 | 1.229500e+09 | 27.181565 | -33.385 | False |
| 1 | 621206.517953 | 159071.301512 | 4114.50 | 1 | 1.229500e+09 | 135.587530 | -35.120 | False |
| 2 | 621313.794221 | 159085.113599 | 4117.90 | 1 | 1.229500e+09 | 243.749367 | -36.875 | False |
| 3 | 621420.722903 | 159099.184618 | 4120.80 | 1 | 1.229500e+09 | 351.600337 | -38.585 | False |
| 4 | 621527.158177 | 159114.303863 | 4123.15 | 1 | 1.229500e+09 | 459.104857 | -40.205 | False |
[3]:
airbornegeo.plotly_points(
data_df[data_df.tie],
color_col="line",
hover_cols=["distance_along_line"],
)
[4]:
airbornegeo.plotly_points(
data_df[~data_df.tie],
color_col="line",
hover_cols=["distance_along_line"],
)
5.2. Find intersections#
[5]:
# convert dataframe into geodataframe
data_df = gpd.GeoDataFrame(
data_df,
geometry=gpd.points_from_xy(data_df.easting, data_df.northing),
crs="EPSG:3031",
)
[6]:
# calculate theoretical intersection points
inters = airbornegeo.create_intersection_table(data_df)
inters
Line/tie combinations: 100%|██████████| 3630/3630 [00:00<00:00, 7796.49it/s]
Potential intersections: 100%|██████████| 670/670 [00:06<00:00, 99.87it/s]
INFO:airbornegeo:found 662 intersections
[6]:
| line | tie | geometry | max_dist | easting | northing | |
|---|---|---|---|---|---|---|
| 0 | 1 | 143 | POINT (1158153 254083) | 16.441255 | 1158153.0 | 254083.0 |
| 1 | 1 | 144 | POINT (1190820 259865) | 24.124887 | 1190820.0 | 259865.0 |
| 2 | 1 | 145 | POINT (1223524 265689) | 17.269650 | 1223524.0 | 265689.0 |
| 3 | 1 | 146 | POINT (1256193 271497) | 31.608179 | 1256193.0 | 271497.0 |
| 4 | 1 | 147 | POINT (1288901 277249) | 50.174377 | 1288901.0 | 277249.0 |
| ... | ... | ... | ... | ... | ... | ... |
| 657 | 125 | 199 | POINT (1318165 302398) | 33.689493 | 1318165.0 | 302398.0 |
| 658 | 125 | 200 | POINT (1350929 308239) | 36.343660 | 1350929.0 | 308239.0 |
| 659 | 127 | 148 | POINT (1319894 292699) | 22.093103 | 1319894.0 | 292699.0 |
| 660 | 127 | 199 | POINT (1319922 292702) | 23.297236 | 1319922.0 | 292702.0 |
| 661 | 127 | 200 | POINT (1352642 298507) | 36.743873 | 1352642.0 | 298507.0 |
662 rows × 6 columns
5.3. Add intersections as rows to the dataframe#
[7]:
data_df, inters = airbornegeo.interpolate_intersections(
data_df,
inters,
to_interp=["mag", "height"],
window_width=500,
method="cubic",
extrapolate=False,
)
Line 206: 100%|██████████| 121/121 [00:12<00:00, 9.79it/s]
[8]:
# see which lines dont have intersections
airbornegeo.lines_without_intersections(data_df, inters)
[8]:
[np.int64(107),
np.int64(109),
np.int64(129),
np.int64(131),
np.int64(188),
np.int64(189),
np.int64(190),
np.int64(192),
np.int64(193),
np.int64(194),
np.int64(203)]
5.4. Calculate initial cross-over errors#
[9]:
inters = airbornegeo.calculate_crossover_errors(
data_df,
inters,
data_col="mag",
plot_map=True,
)
[10]:
inters.head()
[10]:
| line | tie | geometry | max_dist | easting | northing | dist_along_flight_line | dist_along_flight_tie | flight_interpolation_type | tie_interpolation_type | flight_height | tie_height | mistie_0 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 143 | POINT (1158153 254083) | 16.441255 | 1158153.0 | 254083.0 | 545768.072695 | 138071.419338 | interpolated | interpolated | 4168.038983 | 4008.397691 | 100.458661 |
| 1 | 1 | 144 | POINT (1190820 259865) | 24.124887 | 1190820.0 | 259865.0 | 578952.394781 | 131585.125284 | interpolated | interpolated | 4174.500813 | 4010.840823 | 32.151483 |
| 2 | 1 | 145 | POINT (1223524 265689) | 17.269650 | 1223524.0 | 265689.0 | 612181.972720 | 147253.496664 | interpolated | interpolated | 3544.149925 | 3995.961216 | 72.936553 |
| 3 | 1 | 146 | POINT (1256193 271497) | 31.608179 | 1256193.0 | 271497.0 | 645372.035087 | 136211.666619 | interpolated | interpolated | 3564.579994 | 3578.174277 | 84.125118 |
| 4 | 1 | 147 | POINT (1288901 277249) | 50.174377 | 1288901.0 | 277249.0 | 678598.170740 | 155115.224990 | interpolated | interpolated | 3536.160719 | 3545.947314 | -7.731396 |
5.5. Level lines to ties#
Now we will level only the lines, holding the ties constant. We will just use a trend degree of 0, which allows only a DC shift of the lines. We will save the levelled data to a new column mag_levelled_lines_trend0. If you don’t want to keep track on new columns, you can just use the same name as the data column.
[11]:
data_df, inters = airbornegeo.line_levelling(
data_df,
inters,
lines_to_level=data_df[data_df.tie == False].line.unique(),
data_col="mag",
levelled_col="mag_levelled_lines_trend0",
degree=0,
)
inters.head()
[11]:
| line | tie | geometry | max_dist | easting | northing | dist_along_flight_line | dist_along_flight_tie | flight_interpolation_type | tie_interpolation_type | flight_height | tie_height | mistie_0 | mistie_1 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 143 | POINT (1158153 254083) | 16.441255 | 1158153.0 | 254083.0 | 545768.072695 | 138071.419338 | interpolated | interpolated | 4168.038983 | 4008.397691 | 100.458661 | 96.945621 |
| 1 | 1 | 144 | POINT (1190820 259865) | 24.124887 | 1190820.0 | 259865.0 | 578952.394781 | 131585.125284 | interpolated | interpolated | 4174.500813 | 4010.840823 | 32.151483 | 28.638444 |
| 2 | 1 | 145 | POINT (1223524 265689) | 17.269650 | 1223524.0 | 265689.0 | 612181.972720 | 147253.496664 | interpolated | interpolated | 3544.149925 | 3995.961216 | 72.936553 | 69.423514 |
| 3 | 1 | 146 | POINT (1256193 271497) | 31.608179 | 1256193.0 | 271497.0 | 645372.035087 | 136211.666619 | interpolated | interpolated | 3564.579994 | 3578.174277 | 84.125118 | 80.612078 |
| 4 | 1 | 147 | POINT (1288901 277249) | 50.174377 | 1288901.0 | 277249.0 | 678598.170740 | 155115.224990 | interpolated | interpolated | 3536.160719 | 3545.947314 | -7.731396 | -11.244436 |
[12]:
airbornegeo.plot_line_and_crosses(
data_df,
line=77,
x="distance_along_line",
y=["mag", "mag_levelled_lines_trend0"],
y_axes=[1, 1],
plot_inters=True,
)
[13]:
inters = airbornegeo.calculate_crossover_errors(
data_df,
inters,
data_col="mag_levelled_lines_trend0",
plot_map=True,
)
[14]:
airbornegeo.plot_levelling_convergence(inters)
From the above profile, we can see line 77 has been shifted down to try and minimize the cross-over errors. The map, histogram and levelling convergence figures show we have reduced the cross-over errors, bringing the RMSE from ~43nT to ~24nT.
5.6. Level ties to lines#
We can also level the tie lines to the flight lines. We do this be supplying the lines_to_level parameter with the names of the tie lines. We will give this levelled data a new name mag_levelled_ties_trend0
[15]:
data_df, inters = airbornegeo.line_levelling(
data_df,
inters,
lines_to_level=data_df[data_df.tie == True].line.unique(),
data_col="mag_levelled_lines_trend0",
levelled_col="mag_levelled_ties_trend0",
degree=0,
)
inters.head()
[15]:
| line | tie | geometry | max_dist | easting | northing | dist_along_flight_line | dist_along_flight_tie | flight_interpolation_type | tie_interpolation_type | flight_height | tie_height | mistie_0 | mistie_1 | mistie_2 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 143 | POINT (1158153 254083) | 16.441255 | 1158153.0 | 254083.0 | 545768.072695 | 138071.419338 | interpolated | interpolated | 4168.038983 | 4008.397691 | 100.458661 | 96.945621 | 72.958517 |
| 1 | 1 | 144 | POINT (1190820 259865) | 24.124887 | 1190820.0 | 259865.0 | 578952.394781 | 131585.125284 | interpolated | interpolated | 4174.500813 | 4010.840823 | 32.151483 | 28.638444 | 19.088634 |
| 2 | 1 | 145 | POINT (1223524 265689) | 17.269650 | 1223524.0 | 265689.0 | 612181.972720 | 147253.496664 | interpolated | interpolated | 3544.149925 | 3995.961216 | 72.936553 | 69.423514 | 49.368210 |
| 3 | 1 | 146 | POINT (1256193 271497) | 31.608179 | 1256193.0 | 271497.0 | 645372.035087 | 136211.666619 | interpolated | interpolated | 3564.579994 | 3578.174277 | 84.125118 | 80.612078 | 60.446633 |
| 4 | 1 | 147 | POINT (1288901 277249) | 50.174377 | 1288901.0 | 277249.0 | 678598.170740 | 155115.224990 | interpolated | interpolated | 3536.160719 | 3545.947314 | -7.731396 | -11.244436 | -2.791611 |
[16]:
inters = airbornegeo.calculate_crossover_errors(
data_df,
inters,
data_col="mag_levelled_ties_trend0",
plot_map=True,
)
[17]:
airbornegeo.plot_levelling_convergence(inters)
We can repeat these steps, increasing the trend order if we need more levelling, and alternating between levelling lines or ties. The next notebook shows how to automatically perform multiple iterations of levelling.