This project sets up a scalable geospatial data pipeline using PostgreSQL + PostGIS + TimescaleDB , SQLAlchemy, and Podman Compose. It facilitates efficient ingestion, validation, and querying of high-frequency satellite data from the GRACE mission.
See the CITATION.cff file for proper citation format.
- Temporal resolution: 5-second intervals
- Spatial attributes: Latitude, longitude, altitude for GRACE A & B
- Target queries: Time-span filtering, spatial bounding, and signal-based statistical analysis
This setup involves the following key steps:
- Install Prerequisites (Podman, Poetry, etc.)
- Initialize Podman Machine (macOS/Windows only)
- Clone Repository and configure environment
- Start Database Containers with Podman Compose
- Install Python Dependencies and run setup scripts
This project targets Unix-based systems. If you're on Windows, install WSL2 and proceed as if on Ubuntu.
Install the following tools:
- Podman & Podman Compose
- Python 3.10+
- pip
- Poetry 2.x
π Security Note: Podman is recommended over Docker for production due to rootless container support.
π Docker Compatibility: You can also use Docker for development or local testing if it's already installed on your system. Podman supports Docker CLI syntax, so most
dockeranddocker-composecommands are interchangeable withpodmanandpodman-compose.
π₯οΈ Platform Notes:
- macOS/Windows: Requires Podman machine (VM) - see setup instructions below
- Linux: Runs natively without VM requirement
NB: These instructions were written after the fact. YMMV
Install prerequisites:
sudo apt install podman pipx postgresql-client-common postgresql-client
pip3 install podman-composeCheck:
podman-compose -v
pipx ensurepathInstall and check poetry:
pipx install poetry
poetry -VImportant: On macOS and Windows, Podman requires a virtual machine to run containers. Follow these steps to initialize and start the Podman machine: On Linux: Podman runs natively without a machine, so you can skip the machine initialization steps below.
# Initialize a new Podman machine (only needed once)
podman machine init
# Alternative: Initialize with custom settings
# podman machine init --memory 4096 --cpus 2 --disk-size 50# Start the Podman machine
podman machine start
# Verify the machine is running
podman machine listYou should see output similar to:
NAME VM TYPE CREATED LAST UP CPUS MEMORY DISK SIZE
podman-machine-default* qemu 2 weeks ago Currently running 2 2.147GB 107.4GB
# Test that Podman is working
podman --version
podman info
# Test that you can run containers
podman run hello-worldgit clone https://github.com/SpaceGravimetryTUD/GRACE-Orbit-Residuals-db
cd GRACE-Orbit-Residuals-dbMake sure to have a data directory where you store your data.
β οΈ Security Note on Pickle Files Warning: This application loads data using pandas.read_pickle(), which internally uses Python's pickle module. While this format is convenient for fast internal data loading, it is not secure against untrusted input. Never upload or load.pklfiles from unverified or external sources, as they can execute arbitrary code on your system.
Create a .env file at the project root:
# .env
TABLE_NAME=kbr_gravimetry_v2
EXTERNAL_PORT=XXXX #Replace XXXX with available external port; in grace-cube.lr.tudelft.nl, port 3306 is open
DATABASE_NAME=geospatial_db
DATABASE_URL="postgresql://user:password@localhost:5432/${DATABASE_NAME}"
DATA_PATH=/mnt/GRACEcube/Data/L1B_res/CSR_latlon_data/flat-data/v2/flat-data-2003.v2.pklTo load environmental variables in .env run:
source .env(THIS SHOULD GO INTO TROUBLE SHOOTING)
If error is triggered when running timescaledb image, add the following line to /etc/containers/registries.conf:
unqualified-search-registries=["docker.io"]
echo "$USER:100000:65536" >> /etc/subuid
echo "$USER:100000:65536" >> /etc/subgidIf needed, you can manually enable PostGIS (only once):
podman exec -it postgis_container psql -U user -d $DATABASE_NAME -c "CREATE EXTENSION postgis;"Prerequisites: Ensure your Podman machine is running (see Podman Machine Setup section above).
# Verify Podman machine is running (macOS/Windows)
podman machine list
# Start the database containers
podman-compose -f docker-compose.yml up -dExpected output:
[+] Running 2/2
β Container postgis_container Started
β Container timescaledb_container Started
# Check container status
podman ps
# You should see containers similar to:
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# abc123def456 postgis/postgis:latest postgres 2 mins ago Up 2 mins 0.0.0.0:5432->5432/tcp postgis_container# Test connection to the database
podman exec -it postgis_container psql -U user -d $DATABASE_NAME -c "SELECT version();"If containers fail to start:
# Check logs
podman-compose logs
# Stop and remove containers
podman-compose down
# Restart with verbose output
podman-compose -f docker-compose.yml up -d --force-recreateIf you see permission errors:
# Ensure proper subuid/subgid setup (Linux)
echo "$USER:100000:65536" | sudo tee -a /etc/subuid
echo "$USER:100000:65536" | sudo tee -a /etc/subgid
# Restart Podman machine (macOS/Windows)
podman machine stop
podman machine startpodman pspoetry installIf you get the error:
Installing psycopg2 (2.9.10): Failed PEP517 build of a dependency failed Backend subprocess exited when trying to invoke get_requires_for_build_wheelThen:
sudo apt install libpq-dev gcc
From now on, run all Python commands via:
poetry run <your-command>
β οΈ ISSUE: Poetry doesn't like pyenv: removing it from PATH works
There are two ways to set up the database schema:
For a fresh install (new database, no existing data):
poetry run python scripts/init_db.py --use_batches --filepath <path to flat data file>Important: Alembic is only meant for schema migrations. Do not use Alembic for initial setup β it is only useful if you already have a running database with data and you want to change the schema without losing that data.
Workflow for maintainers:
# Generate migration from model changes
poetry run alembic revision --autogenerate -m "Describe schema change"
# β οΈ IMPORTANT: Edit the generated migration file
# Alembic may try to drop PostGIS system tables.
# Remove or comment out any lines like:
# - op.drop_table('spatial_ref_sys')
# - op.drop_table('geometry_columns')
# - op.drop_table('geography_columns')
# Apply the migration
poetry run alembic upgrade headThis will create the tables and load initial data:
poetry run python scripts/init_db.py --use_batches --filepath data/flat-data-test.pklIf you get the error:
Failed to initialize database: No module named 'src'
then you are in the wrong directory.
Optional: verify schema from inside the container:
podman exec -it postgis_container psql -U user -d $DATABASE_NAME -c "\d $TABLE_NAME;"The variables $DATABASE_NAME and $TABLE_NAME are defined in .env.
Ensure data/flat-data-test.pkl exists:
ls data/flat-data-test.pklRun a sample query:
poetry run pythonThen in Python:
from scripts.first_query import run_firstquery
run_firstquery()To completely uninstall:
podman-compose down
podman volume rm grace-orbit-residuals-db_postgres_data
β οΈ Warning: This will permanently delete all data inside the database.
Tests rely on a running local database and valid .env configuration. The PostGIS Extension should also be enabled (to get no failed tests).
poetry run pytestβ Ensure:
$DATABASE_NAMEis running (defined in.env).$TABLE_NAMEtable exists (defined in.env).- Sample data is loaded.
.
βββ alembic/ # Migration files along with env.py
βββ scripts/ # Scripts to init DB, ingest data, and run spatial/temporal queries
βββ src/ # Source code including SQLAlchemy models and utility functions
βββ tests/ # Unit tests for ingestion, queries, and extension validation
βββ docker-compose.yml
βββ pyproject.toml # Poetry project config
βββ .env # Local environment variables (not committed)
βββ postgresql.conf # Custom DB configuration (optional)
βββ LICENSE
βββ README.md
# Stop all containers
podman-compose down
# Stop containers and remove volumes (β οΈ destroys data)
podman-compose down -v# Stop Podman machine (will stop all containers)
podman machine stop
# Start Podman machine
podman machine start
# Check machine status
podman machine list
# View machine details
podman machine info# View logs for all services
podman-compose logs
# View logs for specific service
podman-compose logs postgis_container
# Follow logs in real-time
podman-compose logs -f
# Check container resource usage
podman stats# Remove stopped containers
podman container prune
# Remove unused images
podman image prune
# Remove unused volumes (β οΈ may delete data)
podman volume prune
# Complete cleanup (β οΈ removes everything)
podman system prune -aProblem: Error: cannot connect to Podman socket
# Solution: Start Podman machine
podman machine startProblem: Error: VM already exists
# Solution: Remove and recreate machine
podman machine rm podman-machine-default
podman machine init
podman machine startProblem: Container ports not accessible
# Solution: Check port forwarding and firewall
podman machine ssh
# Inside VM, check if ports are bound:
ss -tlnp | grep 5432Problem: Connection refused to database
# Check container is running
podman ps
# Check database logs
podman logs postgis_container
# Test internal connectivity
podman exec postgis_container pg_isready -U userProblem: Permission denied errors
# Linux: Update subuid/subgid
echo "$USER:100000:65536" | sudo tee -a /etc/subuid
echo "$USER:100000:65536" | sudo tee -a /etc/subgid
# macOS/Windows: Restart machine
podman machine stop && podman machine startProblem: Error: unable to pull image
# Add to /etc/containers/registries.conf (Linux):
echo 'unqualified-search-registries=["docker.io"]' | sudo tee -a /etc/containers/registries.conf
# Or use fully qualified image names:
podman pull docker.io/postgis/postgis:latestProblem: Slow database performance
# Increase machine resources
podman machine rm podman-machine-default
podman machine init --memory 8192 --cpus 4 --disk-size 100
podman machine start# Create database backup
podman exec postgis_container pg_dump -U user $DATABASE_NAME > backup.sql
# Restore from backup
podman exec -i postgis_container psql -U user $DATABASE_NAME < backup.sqlThis project was developed by the Space Gravimetry research group at Delft University of Technology:
- Jose Carlos Urra Llanusa - Research Software Engineer
- Joao De Teixeira da Encarnacao - Research Scientist
- Selin Kubilay - Research Engineer
- JoΓ£o GuimarΓ£es - Software Developer
Licensed under the MIT License.
Technische Universiteit Delft hereby disclaims all copyright interest in the program "GRACE Geospatial Data Processing Stack" written by the Author(s).
β Prof. H.G.C. (Henri) Werij, Dean of Aerospace Engineering at TU Delft