Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
3a6a4e0
Make a start on the mapping from xxx to the Bedrock DB schema
JoostGevaert May 23, 2025
094dff1
Extract horizontal and vertical components from CRS
JoostGevaert May 26, 2025
4274a21
Setup framework for Bedrock GI Database mapping
JoostGevaert May 27, 2025
7c59b1b
Setup Bedrock GI Database mapping models
JoostGevaert May 27, 2025
a381af6
Remove deprecated Bedrock GI schema JSON
JoostGevaert May 27, 2025
41679ba
Setup ags3 module
JoostGevaert May 27, 2025
e693663
Merge remote-tracking branch 'origin/dev' into xxx-to-brdb-api
JoostGevaert May 27, 2025
e47c1d8
Create BedrockGIDatabaseMapping from AGS 3
JoostGevaert May 27, 2025
58843bd
Create generic Bedrock GI mapping function
JoostGevaert May 27, 2025
c240cb8
Correct syntax error
JoostGevaert May 28, 2025
2ef1e62
Make sure notebook still works
JoostGevaert May 28, 2025
0cbe5d7
Experiment with 3D CRS transformations
JoostGevaert May 28, 2025
fc6639c
Put CRS experiments in the corresponding marimo notebook
JoostGevaert May 28, 2025
40f9518
Don't calculate the elevation_at_base when mapping to Bedrock GI DB
JoostGevaert May 28, 2025
afffca5
Compare GPKG table name sets rather than lists of tuples with table n…
JoostGevaert May 28, 2025
1777457
Implement ags_to_brgi_db_mapping
JoostGevaert May 28, 2025
3141844
Prevent circular imports and strip '?' from non-standard AGS 3 groups…
JoostGevaert May 28, 2025
f52729c
Make a start on merging Bedrock GI Databases
JoostGevaert May 28, 2025
1085d98
Follow function signature of polars.concat for merge_databases
JoostGevaert May 29, 2025
ef345f1
Update types of mapping models and BedrockGIDatabase
JoostGevaert Jun 2, 2025
3da669d
Implement ProjectID_ProjectDataB64Hash
JoostGevaert Jun 2, 2025
5380e1d
Implement database merge
JoostGevaert Jun 2, 2025
af8aa3a
Make sure the correct df is output on the BedrockGIDatabase
JoostGevaert Jun 2, 2025
7e74f19
Filter empty dataframes or None's when merging and remove duplicate c…
JoostGevaert Jun 2, 2025
3a91f70
uv sync --all-groups --upgrade
JoostGevaert Jun 2, 2025
8db1bea
Don't drop columns unnecessarily
JoostGevaert Jun 2, 2025
730f044
Fix marimo dtypes
JoostGevaert Jun 3, 2025
a0b06f7
Implement create_lon_lat_height_table
JoostGevaert Jun 3, 2025
ef22666
Access [0,0] from DataFrames with .at / .iat rather than .iloc
JoostGevaert Jun 3, 2025
142f000
Implement location_gis_geometry function
JoostGevaert Jun 3, 2025
8f9251b
Resolve mypy confusion due to type reassignment
JoostGevaert Jun 3, 2025
7f2dfd0
Implement 3D versions of LineString.interpolate and .substring and in…
JoostGevaert Jun 4, 2025
23ac273
Remove CPT data from InSituTests to prevent excessive No. geospatial …
JoostGevaert Jun 4, 2025
01812b0
Allow depth_to_top or depth_to_base + accompanying data validation & …
JoostGevaert Jun 4, 2025
a636129
Calculate all In-Situ test geospatial geometry
JoostGevaert Jun 4, 2025
ee92d75
Change InSituTestSchema check to make sure that:
JoostGevaert Jun 4, 2025
5fd4f90
New Project ✅
JoostGevaert Jun 4, 2025
0ce48c7
New Location ✅
JoostGevaert Jun 4, 2025
85a90b8
New Sample ✅
JoostGevaert Jun 4, 2025
8a4acbf
New GEOL ✅
JoostGevaert Jun 4, 2025
e232d48
New ISPT ✅
JoostGevaert Jun 4, 2025
15fb322
New WETH ✅
JoostGevaert Jun 4, 2025
299607f
Check that old and new GeoPackages pass 90% of the integration test G…
JoostGevaert Jun 5, 2025
32652d6
Make the test run on the Bedrock GI API
JoostGevaert Jun 5, 2025
af60568
Remove old functions from Kai Tak, HK notebook
JoostGevaert Jun 5, 2025
68c3fc0
Refactor AGS 4 logic from brgi.ags.read.py into brgi.gi.ags4.py & upd…
JoostGevaert Jun 5, 2025
a212882
Remove brgi.ags.__init__.py module and rename brgi.ags_parser.py to b…
JoostGevaert Jun 5, 2025
4693a28
Delete outdated notebooks
JoostGevaert Jun 5, 2025
2b71d64
Rename gdf to geodf when referring to geopandas.GeoDataFrame's
JoostGevaert Jun 5, 2025
f5dc165
Remove old non-functional BrGI DB check logic. Leave function skeletons.
JoostGevaert Jun 5, 2025
de6d5b3
Remove kaitak_gi_new.gpkg Which was added as a backup while checking …
JoostGevaert Jun 17, 2025
4c962e7
Clean up geospatial functions
JoostGevaert Jun 17, 2025
4faa62a
Remove the deprecated concatenate module
JoostGevaert Jun 17, 2025
18dfbb2
Add docstrings to all io_utils
JoostGevaert Jun 17, 2025
0cd637d
Write docstring for write.py module functions
JoostGevaert Jun 17, 2025
2ce4657
Add docstrings to geospatial functions
JoostGevaert Jun 18, 2025
433aee4
Handle non seekable streams & reset stream position after exception
JulesBlm Jun 18, 2025
bf538b8
Set seek to 0 again
JulesBlm Jun 18, 2025
7b178c4
Add docstring, no mutation flag param
JulesBlm Jun 18, 2025
d35ea7e
Typing syntax tweaks
JulesBlm Jun 18, 2025
a77a330
Fix compoundcrs import
JulesBlm Jun 18, 2025
1ed8c79
Python 3.10 minimum
JulesBlm Jun 18, 2025
6603a57
Update lockfile
JulesBlm Jun 18, 2025
d56cbb2
Use match statement for groups
JulesBlm Jun 19, 2025
92e8609
Minor typing, docstring and comment edits
JoostGevaert Jun 20, 2025
b196b3e
Upgrade marimo
JoostGevaert Jun 20, 2025
9467988
remove `from __future__ import annotations` import statement to refle…
JoostGevaert Jun 20, 2025
4b7cc58
Make the pyproject.toml classifiers reflect the Python 3.9 -> 3.10 up…
JoostGevaert Jun 20, 2025
059b699
Add an example to the map_to_brgi_db function
JoostGevaert Jun 23, 2025
a59ab9b
upgrade marimo
JoostGevaert Jun 25, 2025
3daec3f
Don't convert dtypes to nullable pandas dtypes, which causes Filter …
JoostGevaert Jun 25, 2025
d530bc3
Fix dataframe / table display issues in marimo related to its funky h…
JoostGevaert Jun 25, 2025
2c06c4a
rename (_geospatial)_database to _(geo)db
JoostGevaert Jun 25, 2025
c77abdf
Update GeoPackage, because no longer using nullable pandas dtypes
JoostGevaert Jun 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
python-version: ['3.9', '3.12']
python-version: ['3.10', '3.12']

steps:
- name: Checkout code
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ __marimo__/
**/log
**/tmp
**/temp
examples/**/raw/
examples/**/cleaned/

# SQLite Databases
*.sqlite
Expand Down
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.10
5,491 changes: 0 additions & 5,491 deletions examples/hk_kaitak_ags3/hk_kaitak_ags3_to_brgi_geodb.ipynb

This file was deleted.

276 changes: 124 additions & 152 deletions examples/hk_kaitak_ags3/hk_kaitak_ags3_to_brgi_geodb.py

Large diffs are not rendered by default.

Binary file modified examples/hk_kaitak_ags3/kaitak_ags3.zip
Binary file not shown.
Binary file modified examples/hk_kaitak_ags3/kaitak_gi.gpkg
Binary file not shown.
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ authors = [
]
license = {text = "Apache Software License (Apache 2.0)"}
readme = "README.md"
requires-python = ">=3.9"
requires-python = ">=3.10"
dependencies = [
"geopandas~=1.0",
"openpyxl~=3.0",
Expand Down Expand Up @@ -55,7 +55,6 @@ classifiers = [
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: GIS",
"Programming Language :: Python",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand Down
3,407 changes: 0 additions & 3,407 deletions sandbox/ags3_to_gis.ipynb

This file was deleted.

121 changes: 0 additions & 121 deletions sandbox/bedrock_gi_to_speckle.ipynb

This file was deleted.

100 changes: 100 additions & 0 deletions sandbox/pyproj_3d_transformations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import marimo

__generated_with = "0.13.11"
app = marimo.App(width="medium")


@app.cell
def _():
import marimo as mo
from pyproj import CRS, Transformer
from pyproj.crs.crs import CompoundCRS
return CRS, CompoundCRS, Transformer


@app.cell
def _(CRS, Transformer):
# https://pyproj4.github.io/pyproj/stable/advanced_examples.html#promote-crs-to-3d
wgs84 = CRS("EPSG:4326")
swiss_proj = CRS("EPSG:2056")
transformer = Transformer.from_crs(wgs84, swiss_proj, always_xy=True)
# 2D Transformation
print(f"2D transform of point {(8.37909, 47.01987, 1000)} from {wgs84} to {swiss_proj} gives:")
print(transformer.transform(8.37909, 47.01987, 1000))

wgs84_3d = wgs84.to_3d()
swiss_proj_ellipsoidal_3d = swiss_proj.to_3d()
transformer_ellipsoidal_3d = Transformer.from_crs(
wgs84_3d,
swiss_proj_ellipsoidal_3d,
always_xy=True,
)
# 3D Transformation
print(f"3D transform of point {(8.37909, 47.01987, 1000)} from {wgs84_3d.to_string()} to {swiss_proj_ellipsoidal_3d} gives:")
print(transformer_ellipsoidal_3d.transform(8.37909, 47.01987, 1000))

return swiss_proj, transformer_ellipsoidal_3d, wgs84_3d


@app.cell
def _(
CRS,
CompoundCRS,
Transformer,
swiss_proj,
transformer_ellipsoidal_3d,
wgs84_3d,
):
# https://pyproj4.github.io/pyproj/stable/build_crs.html#compound-crs
swiss_lhn95_height = CRS("EPSG:5729")
swiss_compound = CompoundCRS(
name="CH1903+ / LV95 + LHN95 height",
components=[swiss_proj, swiss_lhn95_height]
)
transformer_wgs84_3d_to_swiss_compound = Transformer.from_crs(
wgs84_3d,
swiss_compound,
always_xy=True,
)
print(transformer_ellipsoidal_3d.transform(8.37909, 47.01987, 1000))
return


@app.cell
def _(CRS):
uk_grid_27700 = CRS(27700)
uk_3d = uk_grid_27700.to_3d()
swiss_2056 = CRS("EPSG:2056")
swiss_3d = swiss_2056.to_3d()
egm2008_3855 = CRS(3855)
rdnew_nap_7415 = CRS(7415)
wgs84_egm2008_9518 = CRS(9518)
crs_components = extract_crs_components(swiss_3d)
crs_components
return


@app.function
def extract_crs_components(compound_crs):
"""Extract horizontal and vertical CRS from a compound CRS"""
if not compound_crs.is_compound:
return compound_crs, None

horizontal_crs = None
vertical_crs = None

for sub_crs in compound_crs.sub_crs_list:
if sub_crs.is_projected or sub_crs.is_geographic:
print(f"Horizontal CRS {sub_crs.name} is a {sub_crs.type_name} and has EPSG:{sub_crs.to_epsg()}.")
horizontal_crs = sub_crs
elif sub_crs.is_vertical:
print(f"Vertical CRS {sub_crs.name} has EPSG:{sub_crs.to_epsg()}.")
vertical_crs = sub_crs
else:
print(f"This CRS is not horizontal (projected or geographic) nor vertical: {sub_crs.type_name}")

return horizontal_crs, vertical_crs


if __name__ == "__main__":
app.run()
103 changes: 103 additions & 0 deletions src/bedrock_ge/gi/ags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
from pathlib import Path
from typing import IO

from pyproj import CRS

from bedrock_ge.gi.ags3 import ags3_to_brgi_db_mapping
from bedrock_ge.gi.io_utils import detect_encoding, open_text_data_source
from bedrock_ge.gi.mapping_models import BedrockGIMapping


def ags_to_brgi_db_mapping(
source: str | Path | IO[str] | IO[bytes] | bytes,
projected_crs: CRS,
vertical_crs: CRS = CRS(3855),
encoding: str | None = None,
) -> BedrockGIMapping:
"""Map AGS 3 or AGS 4 data to the Bedrock GI data model.

Args:
source (str | Path | IO[str] | IO[bytes] | bytes): The AGS file (str or Path)
or a file-like object that represents the AGS file.
projected_crs (CRS): Projected Coordinate Reference System (CRS). For example:
- OSGB36 / British National Grid: `pyproj.CRS("EPSG:27700")`
- Hong Kong 1980 Grid System: `pyproj.CRS("EPSG:2326")`
vertical_crs (CRS, optional): Vertical CRS. Defaults to EGM2008 height, EPSG:3855
which measures the orthometric height w.r.t. the Earth Gravitational Model 2008.
- Ordnance Datum Newlyn (ODN) Height: `pyproj.CRS("EPSG:5701")`
- Hong Kong Principle Datum (HKPD) Height: `pyproj.CRS("EPSG:5738")`
encoding (str | None, optional): Encoding of the text file or bytes stream.
Defaults to None. An attempt at detecting the encoding will be made if None.

Raises:
ValueError: If the data does not match AGS 3 or AGS 4 format.

Returns:
BedrockGIDatabaseMapping: Object that maps AGS 3 or AGS 4 data to Bedrock GI data model.
"""
if not encoding:
encoding = detect_encoding(source)

# Get first non-blank line, None if all lines are blank
with open_text_data_source(source, encoding=encoding) as f:
first_line = next((line.strip() for line in f if line.strip()), None)

if first_line:
if first_line.startswith('"**'):
ags_version = 3
brgi_db_mapping = ags3_to_brgi_db_mapping(
source, projected_crs, vertical_crs, encoding
)
elif first_line.startswith('"GROUP"'):
ags_version = 4
# brgi_db_mapping = ags4_to_brgi_db_mapping(
# source, projected_crs, vertical_crs, encoding
# )
else:
# If first non-empty line doesn't match AGS 3 or AGS 4 format
raise ValueError("The data provided is not valid AGS 3 or AGS 4 data.")
else:
raise ValueError("The file provided has only blank lines")

# Put CPT data into brgi_db.Other table, because CPT data has too many rows
# that would generate geospatial geometry.
# "STCN" and "SCPT" are the group names for CPT data in AGS 3 and AGS 3 respectively.
# TODO: implement a warning when interpolating GI geospatial geometry when
# TODO: a single GI location has waaay too many rows in a certain In-Situ test,
# TODO: rather than removing specific groups here.
insitu_test_names = {
insitu_test.table_name: i
for i, insitu_test in enumerate(brgi_db_mapping.InSitu)
}
cpt_key = (
"STCN"
if "STCN" in insitu_test_names
else "SCPT"
if "SCPT" in insitu_test_names
else None
)
if cpt_key is not None:
cpt_data_mapping = brgi_db_mapping.InSitu.pop(insitu_test_names[cpt_key])
del insitu_test_names[cpt_key]
brgi_db_mapping.Other.append(cpt_data_mapping)

# Log information about the mapped AGS 3 or AGS 4 data
project_id = brgi_db_mapping.Project.project_id
n_gi_locations = len(brgi_db_mapping.Location.data)
n_samples = len(brgi_db_mapping.Sample.data) if brgi_db_mapping.Sample else 0
print_args = [
f"AGS {ags_version} data was read for Project {project_id}",
f"This GI data contains {n_gi_locations} GI locations, {n_samples} samples and:",
f" - In-Situ Tests: {list(insitu_test_names.keys())}",
]
if brgi_db_mapping.Lab:
print_args.append(
f" - Lab Tests: {[lab_test.table_name for lab_test in brgi_db_mapping.Lab]}"
)
if brgi_db_mapping.Other:
print_args.append(
f" - Other Tables: {[other_table.table_name for other_table in brgi_db_mapping.Other]}"
)
print(*print_args, sep="\n", end="\n\n")

return brgi_db_mapping
Empty file removed src/bedrock_ge/gi/ags/__init__.py
Empty file.
Loading