Note: This is the open-source reference release (v0.1.5). It is a fully functional self-hosted tool — not a SaaS product. You bring your own weather credentials, your own noon reports, and run it locally or on your own server. Do not use for actual voyage planning or navigation.
A weather routing and performance analytics platform for merchant ships. Optimizes fuel consumption through weather-aware A* and Dijkstra routing, physics-based vessel modeling, engine log analytics, and real-time sensor fusion. Ships with a default MR Product Tanker configuration; all vessel parameters are fully configurable.
Documentation: windmar-nav.github.io
Run Windmar on your machine in under 2 minutes. No git clone, no build step, no credentials required.
- Docker Desktop (Windows, Mac, or Linux)
-
Download two files into the same folder:
mkdir windmar && cd windmar curl -LO https://raw.githubusercontent.com/windmar-nav/windmar/main/docker-compose.standalone.yml curl -L -o .env https://raw.githubusercontent.com/windmar-nav/windmar/main/.env.standalone
-
Start everything:
docker compose -f docker-compose.standalone.yml up -d
-
Open your browser:
Service URL Frontend http://localhost:3000 API http://localhost:8000 API Docs http://localhost:8000/api/docs
The system ships with demo engine log data and noon reports pre-loaded. Wind data (GFS) loads automatically on first start — no credentials needed.
Download the noon report Excel template and fill in your operational data:
curl -O http://localhost:8000/api/vessel/noon-reports/templateOr open http://localhost:8000/api/vessel/noon-reports/template in your browser. Upload via the Vessel page in the UI, or:
curl -X POST http://localhost:8000/api/vessel/noon-reports/upload-excel \
-F file=@your_noon_reports.xlsxWind data works immediately — no sign-up needed. GFS wind fields are downloaded from NOAA automatically on startup.
Wave, current, SST, and ice data require a free Copernicus Marine account:
- Go to marine.copernicus.eu and click Register
- Fill in the form (name, email, password) — approval is instant
- Open your
.envfile and uncomment + fill in your credentials:COPERNICUSMARINE_SERVICE_USERNAME=your_email@example.com COPERNICUSMARINE_SERVICE_PASSWORD=your_password - Restart:
docker compose -f docker-compose.standalone.yml restart api
Without CMEMS credentials everything still works — wave and current overlays will show synthetic placeholder data instead of live observations.
| Issue | Solution |
|---|---|
| Port 3000 or 8000 in use | Change ports in .env: add API_PORT=8001 and update CORS_ORIGINS |
| API not ready yet | First startup takes ~60s (database migrations + weather download). Check docker logs windmar-api |
| No wave/current data | Expected without CMEMS credentials. Wind visualization works without any credentials |
| Container won't start | Run docker compose -f docker-compose.standalone.yml logs to see errors |
# Stop
docker compose -f docker-compose.standalone.yml down
# Stop and delete all data (fresh start)
docker compose -f docker-compose.standalone.yml down -v- Holtrop-Mennen resistance prediction — calm water resistance with frictional, wave-making, and appendage components
- Two wave resistance methods — STAWAVE-1 (ISO 15016, default) and Kwon's method (speed-loss percentage, per TN001)
- SFOC curves at variable engine loads with calibration factor support
- Performance predictor — dual-mode inverse solver: find achievable speed at a given engine load, or find required power for a target calm-water speed in weather
- Hull fouling calibration from operational noon reports and engine log data
- Laden and ballast condition support with 20 configurable vessel parameters
- Vessel specifications persisted in PostgreSQL across restarts
- Engine log ingestion — upload CSV/Excel operational data with automatic column mapping
- Performance dashboard — 5 KPIs (avg speed, avg fuel, efficiency, distance, operating hours) + 6 interactive engine charts
- Analytics tab — fuel consumption distributions, speed-power scatter, voyage statistics
- Engine-log calibration bridge — calibrate vessel model directly from engine log data
- Batch management — upload, browse, filter, and delete engine log batches
- A* grid search (primary engine) with weather-aware cost function and 9 pre-validated strait shortcuts
- Dijkstra (time-expanded graph) — voluntary speed reduction in heavy weather, node-budget capped
- 3 safety-weight variants per engine (fuel-optimal / balanced / safety-first) with progressive UI updates
- A* grid at 0.2 deg (~12nm) resolution; Dijkstra at 0.25 deg (~15nm) — aligned with professional routing software
- GSHHS coastline polygons — sub-km vector land boundaries with cached shapefile loading
- Strait visibility graph — 9 pre-validated commercial straits (Gibraltar EB/WB, Dover, Malacca, Hormuz, Bab el-Mandeb, Bosporus, Suez approach, Messina) with direct vertex-to-vertex edges
- Multi-objective Pareto front — fuel vs. time tradeoff curve with interactive chart and smart default selection
- Course-change penalty — graduated heading penalty (0-20% per edge) discourages zigzag paths from grid artifacts
- Safety fallback — when severe weather blocks departure, automatic retry with relaxed hard limits (10x cost penalty instead of rejection); structured error diagnostics on complete failure
- Hard avoidance limits — Hs >= 6m and wind >= 70 kts are instant rejection (no motion calculation)
- Seakeeping safety constraints — graduated roll, pitch, acceleration limits with motion-based cost multipliers
- Variable speed voyage calculation — per-leg speed optimization (fuel ~ speed³) with configurable time penalty
- Variable speed optimization (10-16 knots per leg, 0.5 kt steps)
- Turn-angle path smoothing to eliminate grid staircase artifacts
- SOG profile analysis — estimated speed-over-ground per waypoint accounting for weather and current
- RTZ file import/export (IEC 61174 ECDIS standard)
- NOAA GFS (0.25 deg) for near-real-time wind fields via NOMADS GRIB filter
- 5-day wind forecast timeline (f000-f120, 3-hourly steps) with Windy-style animation
- Copernicus Marine Service (CMEMS) for wave and ocean current data
- Climatology fallback for beyond-forecast-horizon voyages
- Unified provider that blends forecast and climatology with smooth transitions
- Pre-ingested weather database — grids compressed (zlib/float32) in PostgreSQL, served in milliseconds
- Redis shared cache across all API workers (replaces per-worker in-memory dict)
- User-triggered overlay model — no background loops; per-layer resync with viewport-aware CMEMS downloads
- Server-side grid subsampling (<=500 pts/axis) prevents browser OOM on large viewports
- Synthetic data generator for testing and demos
- Parametric Monte Carlo with temporally correlated perturbations
- Divides voyage into up to 100 time slices (~1 per 1.2 hours)
- Cholesky decomposition of exponential temporal correlation matrix
- Log-normal perturbation model: wind sigma=0.35, wave sigma=0.20 (70% correlated with wind), current sigma=0.15
- P10/P50/P90 confidence intervals for ETA, fuel consumption, and voyage time
- Pre-fetches multi-timestep wave forecast grids from database (0-120h)
- 100 simulations complete in <500ms
- IMO CII (Carbon Intensity Indicator) calculations with annual tightening
- FuelEU Maritime — GHG intensity (Well-to-Wake), compliance balance, pooling scenarios, penalty estimator
- Emission Control Areas (ECA/SECA) with fuel switching requirements
- High Risk Areas (HRA), Traffic Separation Schemes (TSS)
- Charter Party weather clause tools — good weather day counter, warranted speed/consumption verification, off-hire detection
- Custom zone creation with penalty/exclusion/mandatory interactions
- GeoJSON export for frontend visualization
- SBG Electronics IMU sensor integration (roll, pitch, heave)
- FFT-based wave spectrum estimation from ship motion
- Multi-source sensor fusion engine
- Continuous model recalibration from live data
- ECDIS-style map-centric layout with full-width chart and header dropdowns
- Interactive Leaflet maps with weather overlays, coastline rendering, and route visualization
- Wind particle animation layer (leaflet-velocity)
- Windy-style wave crest rendering with click-to-inspect polar diagram popup
- Forecast timeline with play/pause, speed control, and 5-day scrubbing
- Optimized routes displayed simultaneously with per-route color coding and toggleable visibility
- Interactive Pareto front chart (fuel vs. time tradeoff) in analysis panel
- Unified comparison table with fuel, distance, time, and waypoint counts for every route variant
- Sequential optimization with progressive map updates (routes appear one by one)
- Session persistence — waypoints, optimization results, viewport, and settings survive page navigation and full reloads (sessionStorage-backed React Context)
- Settings page — dedicated optimization engine configuration with educational content on Pareto analysis, variable speed, and startup procedure
- Voyage calculation with per-leg fuel, speed, and ETA breakdown
- Consolidated vessel configuration, calibration, fuel analysis, and performance prediction page
- Engine log upload, entries browser, and analytics dashboard
- CII compliance tracking and projections
- FuelEU Maritime compliance page (4 tabs)
- Charter party weather clause analysis
- Dark maritime theme, responsive design
This release uses GFS forecast data only (5-day horizon, 3-hourly steps). There is no ERA5 reanalysis ingestion — if GFS data is unavailable, the system falls back to synthetic data for wind.
| Constraint | Detail |
|---|---|
| Forecast horizon | 5 days (GFS f000-f120). No historical reanalysis. |
| Wind source | NOAA GFS (0.25 deg). Free, no credentials needed. |
| Wave / current source | CMEMS. Requires a free Copernicus Marine account. |
| ERA5 | Not included in this release. CDS credentials are accepted but ERA5 ingestion is not active. |
| Coverage | North Atlantic / NW Europe (ADRS 1+2). Configurable via area selection. |
| Data refresh | Manual — user triggers resync per layer. No background scheduler. |
For voyages beyond the 5-day forecast window, the system uses climatological fallback values (monthly averages).
windmar/
├── api/ # FastAPI backend
│ ├── main.py # Application factory + startup
│ ├── routers/ # Domain routers (12 modules)
│ │ ├── weather.py # 31 weather endpoints, forecast layers, cache mgmt
│ │ ├── vessel.py # Vessel specs, calibration, noon reports, prediction
│ │ ├── voyage.py # Voyage calculation, Monte Carlo, weather-along-route
│ │ ├── voyage_history.py # Voyage history and reporting
│ │ ├── optimization.py # A* / Dijkstra route optimization with safety fallback
│ │ ├── engine_log.py # Engine log upload, entries, summary, calibration
│ │ ├── zones.py # Regulatory zone CRUD and spatial queries
│ │ ├── cii.py # CII compliance calculations and projections
│ │ ├── fueleu.py # FuelEU Maritime GHG intensity and compliance
│ │ ├── charter_party.py # Weather clause tools (good weather days, warranted speed)
│ │ ├── routes.py # RTZ parsing, waypoint route creation
│ │ └── system.py # Health, metrics, status, data sources
│ ├── schemas/ # Pydantic request/response models (11 modules)
│ │ ├── common.py, weather.py, vessel.py, voyage.py, optimization.py
│ │ ├── engine_log.py, zones.py, cii.py, fueleu.py, charter_party.py
│ │ └── ...
│ ├── reports/ # PDF report generation (noon, departure, arrival)
│ ├── state.py # Thread-safe application state (singleton)
│ ├── weather_service.py # Weather field accessors (wind, wave, current, SST, ice)
│ ├── forecast_layer_manager.py # Forecast dedup, progress tracking, frame serving
│ ├── auth.py # API key authentication (bcrypt, demo licensing)
│ ├── config.py # API configuration (pydantic-settings)
│ ├── middleware.py # Security headers, structured logging, metrics
│ ├── rate_limit.py # Token bucket rate limiter (Redis-backed)
│ ├── database.py # SQLAlchemy ORM setup
│ ├── models.py # Database models (weather, engine log, vessel specs)
│ ├── health.py, cache.py, resilience.py, demo.py, cli.py, live.py
│ └── ...
├── src/
│ ├── optimization/
│ │ ├── vessel_model.py # Holtrop-Mennen + Kwon resistance, SFOC, performance predictor
│ │ ├── base_optimizer.py # Abstract base class for route optimizers
│ │ ├── route_optimizer.py # A* grid search with strait shortcuts + course-change penalty
│ │ ├── dijkstra_optimizer.py # Dijkstra time-expanded graph with node budget cap
│ │ ├── routing_graph.py # Shared routing graph utilities
│ │ ├── router.py # Engine dispatcher (A*/VISIR selection)
│ │ ├── voyage.py # Per-leg voyage calculator (LegWeather, VoyageResult)
│ │ ├── monte_carlo.py # Temporal MC simulation with Cholesky correlation
│ │ ├── seakeeping.py # Ship motion safety assessment + safety fallback
│ │ ├── grid_weather_provider.py # Bilinear interpolation from pre-fetched grids
│ │ ├── temporal_weather_provider.py # Trilinear interpolation (lat, lon, time)
│ │ ├── weather_assessment.py # Route weather assessment + DB provisioning
│ │ └── vessel_calibration.py # Noon report + engine log calibration (scipy)
│ ├── data/
│ │ ├── copernicus.py # GFS, ERA5, CMEMS providers + forecast prefetch
│ │ ├── copernicus_client.py # CMEMS client wrapper
│ │ ├── db_weather_provider.py # DB-backed weather (compressed grids from PostgreSQL)
│ │ ├── weather_ingestion.py # Scheduled weather grid ingestion service
│ │ ├── strait_waypoints.py # 9 commercial strait definitions with waypoint coordinates
│ │ ├── tss_zones.py # Traffic Separation Scheme zone definitions
│ │ ├── regulatory_zones.py # Zone management and point-in-polygon (Shapely)
│ │ ├── eca_zones.py # ECA zone definitions
│ │ └── land_mask.py # GSHHS coastline + ocean/land detection
│ ├── compliance/
│ │ ├── cii.py # IMO CII rating calculations
│ │ ├── fueleu.py # FuelEU Maritime GHG intensity
│ │ └── charter_party.py # Weather clause analysis
│ ├── calibration/ # Calibration loop and utilities
│ ├── database/ # Engine log parser, Excel parser
│ ├── sensors/ # SBG IMU, wave estimator, timeseries
│ ├── fusion/ # Multi-source data fusion
│ ├── routes/ # RTZ XML route file parser
│ ├── visualization/ # Plotting utilities
│ ├── validation.py, config.py, metrics.py
│ └── ...
├── frontend/ # Next.js 15 + TypeScript
│ ├── app/ # Pages (route planner, vessel, CII, FuelEU, charter party, live)
│ ├── components/ # 42 React components (maps, charts, weather, Pareto, analysis)
│ └── lib/ # API client, utilities
├── tests/ # 713 tests (531 unit + 182 integration)
│ ├── unit/ # Vessel model, routing, safety, straits, zones, CII, FuelEU...
│ ├── integration/ # API endpoints, optimization flow
│ └── test_e2e_*.py # End-to-end sensor integration
├── examples/ # Demo scripts (simple, ARA-MED, calibration)
├── docker/ # init-db.sql, migrations/
├── docker-compose.yml # Full stack (API + frontend + PostgreSQL + Redis)
├── Dockerfile # Multi-stage production build
└── pyproject.toml # Poetry project definition
| Layer | Technology |
|---|---|
| Backend | FastAPI, Uvicorn, Python 3.10+ |
| Frontend | Next.js 15, TypeScript, React, Tailwind CSS |
| Maps | React Leaflet |
| Charts | Recharts |
| Database | PostgreSQL 16, SQLAlchemy |
| Cache | Redis 7 |
| Scientific | NumPy, SciPy, Pandas |
| Auth | API keys, bcrypt |
| Containerization | Docker, Docker Compose |
git clone https://github.com/windmar-nav/windmar.git
cd windmar
cp .env.example .env # Edit with your settings
docker compose up -d --buildServices start on:
| Service | URL |
|---|---|
| Frontend | http://localhost:3003 |
| API | http://localhost:8003 |
| API Docs (Swagger) | http://localhost:8003/api/docs |
| PostgreSQL | localhost:5434 |
| Redis | localhost:6380 |
Important: The frontend requires the backend API to be running. Start the backend first, then the frontend in a separate terminal.
# Terminal 1 — Backend API (must be running for the frontend to work)
pip install -r requirements.txt
python api/main.py
# API starts on http://localhost:8000
# Terminal 2 — Frontend
cd frontend
cp .env.example .env.local # Sets API URL to http://localhost:8000
npm install --legacy-peer-deps
npm run dev
# Frontend starts on http://localhost:3000python examples/demo_simple.py # Synthetic weather demo
python examples/example_ara_med.py # Rotterdam to Augusta optimization
python examples/example_calibration.py # Noon report calibrationCopy .env.example to .env and configure:
| Variable | Description | Default |
|---|---|---|
ENVIRONMENT |
development / staging / production | development |
DATABASE_URL |
PostgreSQL connection string | postgresql://windmar:...@db:5432/windmar |
REDIS_URL |
Redis connection string | redis://:...@redis:6379/0 |
API_SECRET_KEY |
API key hashing secret | (generate with openssl rand -hex 32) |
CORS_ORIGINS |
Allowed frontend origins | http://localhost:3000 |
COPERNICUS_MOCK_MODE |
Use synthetic weather data | true |
AUTH_ENABLED |
Require API key authentication | true |
RATE_LIMIT_PER_MINUTE |
API rate limit | 60 |
Windmar uses a three-tier provider chain that automatically falls back when a source is unavailable:
| Data Type | Source | Fallback | Credentials |
|---|---|---|---|
| Wind | NOAA GFS (0.25 deg, ~3.5h lag) | Synthetic | None (free) |
| Waves | CMEMS global wave model | Synthetic | CMEMS account (free) |
| Currents | CMEMS global physics model | Synthetic | CMEMS account (free) |
| SST / Ice | CMEMS | — | CMEMS account (free) |
| Forecast | GFS f000-f120 (5-day, 3h steps) | — | None |
Wind data works out of the box — GFS is fetched from NOAA NOMADS without authentication. For wave and current data, you need Copernicus Marine credentials.
GFS wind data requires no credentials — it is downloaded from NOAA NOMADS automatically.
CMEMS (waves, currents, SST, ice):
- Register for a free account at marine.copernicus.eu
- Set in
.env:COPERNICUSMARINE_SERVICE_USERNAME=your_username COPERNICUSMARINE_SERVICE_PASSWORD=your_password
Without CMEMS credentials, the system falls back to synthetic data for waves and currents. Wind visualization always works via GFS.
See WEATHER_PIPELINE.md for full technical details on data acquisition, GRIB processing, and the forecast timeline.
Noon reports are used to calibrate the vessel performance model against real operational data. Upload via CSV, Excel, or the JSON API.
Required fields:
| Field | Type | Description |
|---|---|---|
timestamp |
datetime | Report time (ISO 8601 or common date formats) |
latitude |
float | Position latitude (-90 to +90) |
longitude |
float | Position longitude (-180 to +180) |
speed_over_ground_kts |
float | Speed over ground in knots |
fuel_consumption_mt |
float | Fuel consumed in metric tons |
Optional fields: speed_through_water_kts, period_hours (default 24), is_laden (default true), heading_deg, wind_speed_kts, wind_direction_deg, wave_height_m, wave_direction_deg, engine_power_kw.
CSV example:
timestamp,latitude,longitude,speed_over_ground_kts,fuel_consumption_mt,is_laden
2025-01-15 12:00,48.5,-5.2,13.2,28.5,true
2025-01-16 12:00,43.8,-9.1,12.8,27.1,true
2025-01-17 12:00,38.2,-9.8,13.5,29.2,trueColumn names are auto-detected — lat/latitude, lon/longitude, speed/sog, etc. all work. Upload via:
- API:
POST /api/vessel/noon-reports/upload-csv(multipart file) - API:
POST /api/vessel/noon-reports/upload-excel(multipart file) - UI: Vessel page > Noon Reports tab > Upload
GET /api/weather/health- Weather subsystem healthGET /api/weather/wind- Wind field grid (U/V components)GET /api/weather/wind/velocity- Wind in leaflet-velocity format (GFS)GET /api/weather/waves- Wave height field (CMEMS)GET /api/weather/swell- Swell fieldGET /api/weather/currents- Ocean current field (CMEMS)GET /api/weather/currents/velocity- Currents in leaflet-velocity formatGET /api/weather/sst- Sea surface temperatureGET /api/weather/visibility- Visibility fieldGET /api/weather/ice- Sea ice concentrationGET /api/weather/point- Weather at specific coordinatesGET /api/weather/freshness- Weather data age indicatorPOST /api/weather/{layer}/resync- Per-layer viewport-aware resync
GET /api/weather/forecast/status- GFS prefetch progress and run infoPOST /api/weather/forecast/prefetch- Trigger 5-day forecast download (f000-f120)GET /api/weather/forecast/frames- Bulk download all forecast frames
GET /api/weather/forecast/{layer}/status- Prefetch progressPOST /api/weather/forecast/{layer}/prefetch- Trigger forecast downloadGET /api/weather/forecast/{layer}/frames- Bulk download forecast frames
POST /api/routes/parse-rtz- Parse RTZ route filePOST /api/routes/from-waypoints- Create route from coordinates
POST /api/voyage/calculate- Full voyage calculation with weatherGET /api/voyage/weather-along-route- Weather conditions per waypointPOST /api/voyage/monte-carlo- Parametric MC simulation (P10/P50/P90)
POST /api/optimize/route- Weather-optimal route finding (A* or Dijkstra engine)POST /api/optimize/pareto- Multi-objective Pareto front (fuel vs. time)GET /api/optimize/status- Optimizer configuration and available targets
GET /api/vessel/specs- Current vessel specificationsPOST /api/vessel/specs- Update vessel specifications (persisted to DB)GET /api/vessel/calibration- Current calibration factorsPOST /api/vessel/calibration/set- Manually set calibration factorsPOST /api/vessel/calibrate- Run calibration from noon reportsPOST /api/vessel/calibration/estimate-fouling- Estimate hull fouling factorGET /api/vessel/model-status- Full model parameters, calibration state, computed valuesGET /api/vessel/fuel-scenarios- Physics-based fuel scenarios (4 conditions)POST /api/vessel/predict- Performance predictor (engine load or target speed mode)GET /api/vessel/noon-reports- List uploaded noon reportsPOST /api/vessel/noon-reports- Add a single noon reportPOST /api/vessel/noon-reports/upload-csv- Upload operational data (CSV)POST /api/vessel/noon-reports/upload-excel- Upload operational data (Excel .xlsx/.xls)GET /api/vessel/noon-reports/template- Download noon report Excel templateDELETE /api/vessel/noon-reports- Clear all noon reports
POST /api/engine-log/upload- Upload engine log CSV/ExcelGET /api/engine-log/entries- Browse entries with pagination and filtersGET /api/engine-log/summary- Aggregate statistics per batchPOST /api/engine-log/calibrate- Calibrate vessel model from engine log dataDELETE /api/engine-log/batch/{batch_id}- Delete a batch
GET /api/zones- All regulatory zones (GeoJSON)GET /api/zones/list- Zone summary listGET /api/zones/{zone_id}- Single zone detailsPOST /api/zones- Create custom zoneDELETE /api/zones/{zone_id}- Delete a custom zoneGET /api/zones/at-point- Zones at specific coordinatesGET /api/zones/check-path- Check zone intersections along a route
GET /api/cii/vessel-types- IMO vessel type categoriesGET /api/cii/fuel-types- Fuel types and CO2 emission factorsPOST /api/cii/calculate- Calculate CII ratingPOST /api/cii/project- Multi-year CII projectionPOST /api/cii/reduction- Required fuel reduction for target rating
GET /api/live/status- Sensor connection statusPOST /api/live/connect- Connect to SBG IMU sensorPOST /api/live/disconnect- Disconnect sensorGET /api/live/data- Current fused sensor dataGET /api/live/timeseries/{channel}- Time series for a specific channelGET /api/live/timeseries- All time series dataGET /api/live/motion/statistics- Motion statistics (roll, pitch, heave)GET /api/live/channels- Available data channelsPOST /api/live/export- Export recorded data
GET /api/health- Health checkGET /api/health/live- Liveness probeGET /api/health/ready- Readiness probeGET /api/status- Application status summaryGET /api/metrics- Prometheus metricsGET /api/metrics/json- Metrics in JSON formatGET /api/data-sources- Weather data source configuration
Full interactive documentation at /api/docs when the server is running.
713 tests (531 unit, 182 integration).
pytest tests/ -v # All tests
pytest tests/unit/ -v # Unit tests only
pytest tests/integration/ -v # Integration tests
pytest tests/unit/test_vessel_model.py -v # Specific test fileThe system ships with a default MR Product Tanker configuration (all values configurable via API and persisted in DB):
| Parameter | Value |
|---|---|
| DWT | 49,000 MT |
| LOA / LPP | 183m / 176m |
| Beam | 32m |
| Draft (laden / ballast) | 11.8m / 6.5m |
| Displacement (laden / ballast) | 65,000 / 20,000 MT |
| Block coefficient (laden / ballast) | 0.82 / 0.75 |
| Wetted surface (laden / ballast) | 7,500 / 5,200 m2 |
| Main Engine MCR | 6,600 kW |
| SFOC at MCR | 171 g/kWh |
| Service Speed (laden / ballast) | 13.0 / 13.0 knots |
| Frontal area (laden / ballast) | 450 / 850 m2 |
| Lateral area (laden / ballast) | 2,100 / 2,800 m2 |
Local-first distribution — run Windmar from pre-built Docker images with no build step, no git clone, and no credentials required for wind data.
- Standalone Docker Compose —
docker-compose.standalone.ymlpulls from GHCR, starts 4 services (PostgreSQL, Redis, API, Frontend) with a single command - Pre-filled
.env.standalone— ready to use with step-by-step CMEMS credential instructions in comments - Noon report seed data — 30 synthetic noon reports (Rotterdam → Med route, Jul-Aug 2025) auto-loaded on startup
- Noon report Excel template — downloadable via
GET /api/vessel/noon-reports/templatewith column guide sheet :latestDocker tags — CI now publishes:latestalongside:mainfor both API and Frontend images- Demo VPS removed — no hosted demo; the standalone distribution is the only way to try Windmar
- Removed
Caddyfileanddocker-compose.demo.yml - README rewritten with "Try It Locally" quick-start section and credential setup guide
Open-source release — self-hosted weather routing tool with 5-day GFS forecast, CMEMS wave/current data, and vessel performance calibration from noon reports.
- Viewport persistence versioning — stale session bounds discarded on upgrade
- Demo bounds aligned to actual weather coverage (ADRS 1+2)
- README rewritten with credential setup, noon report ingestion format, and known limitations
- Version bumped across backend and frontend
Settings & Documentation
- Dedicated Settings page (
/settings) — optimization engine configuration (grid resolution, variable resolution, Pareto analysis, variable speed) with educational content explaining each feature, the optimization process, safety weights, and the local-first startup procedure - VISIR renamed to Dijkstra — all references across backend, frontend, API schemas, and documentation updated to reflect the actual algorithm
- Settings link added to header navigation
Variable Speed Voyage Calculation
- Per-leg speed optimization — tests 13 candidate speeds from 60%-100% of calm speed per leg, selects minimum fuel+time score using fuel ~ speed³ relationship
- Time penalty tuning — LAMBDA_TIME=1.5 MT-equivalent per hour prevents extreme slow-steaming in calm conditions
- Speed profile bar chart in voyage summary shows per-leg speed variations
- 8 new unit tests covering calm weather convergence, heavy weather savings, and speed profile bounds
Session Persistence
- All VoyageContext state backed by sessionStorage — waypoints, optimization results, route visibility, viewport, view mode, and settings survive full page reloads and hard navigations
- Map viewport restored from persisted state on remount (no more reset to default view)
displayedAnalysisIdmoved from local page state to shared context for cross-navigation persistence
Dijkstra Performance
- Frontend optimization timeout increased from 180s to 600s for long routes on time-expanded graphs
- Default node budget reduced from 350K to 150K to cap memory usage
Demo Mode Hardening
- File uploads (RTZ import, Load from File) hidden for demo users
- Map viewport fully locked in demo mode — dragging, zoom, scroll, keyboard, and touch interactions disabled
- Weather data: frozen snapshot (Feb 2025), forecast capped at 48h, Visibility/SST layers hidden, resync blocked
Phase 2 (commercial credibility) and Phase 3 (optimizer upgrade), plus security hardening and dark theme.
Phase 2 — Regulatory & Commercial Features
- 2a: Voyage Reporting — noon, departure, and arrival reports in IMO format; PDF export with branding placeholder; voyage history with search and filters
- 2b: CII Simulator — what-if CII projection with speed/fuel/route adjustments; fleet-level dashboard; A-E band threshold visualization with tightening schedule
- 2c: FuelEU Maritime — GHG intensity calculation (Well-to-Wake), compliance balance tracking, pooling scenario modeling, penalty exposure estimator (4-tab page, 7 endpoints, 35 tests)
- 2d: Charter Party Weather Clause Tools — good weather day counter (Beaufort thresholds), warranted speed/consumption verification, off-hire event detection from engine logs
Phase 3 — Optimizer Upgrade (ALGO-OPT-001)
- GSHHS coastline polygons — sub-km vector land boundaries with cached shapefile loading
- Variable resolution corridor grid — 0.1 deg nearshore, 0.5 deg open ocean, auto-refined around obstacles; UI toggle for variable/uniform resolution
- Strait visibility graph — 9 pre-validated commercial straits (Gibraltar EB/WB, Dover, Malacca, Hormuz, Bab el-Mandeb, Bosporus, Suez approach, Messina) with direct vertex-to-vertex edges injected into the A* search graph
- Multi-objective Pareto front — fuel vs. time tradeoff curve with widened lambda sweep and smart default selection; interactive Pareto chart in analysis panel
- Course-change penalty — graduated heading change cost (0-20% per edge) prevents zigzag paths from grid discretization artifacts
- Safety fallback routing — automatic retry with relaxed hard limits when severe weather blocks departure; structured error diagnostics (422 with explored-node count and failure reason)
- Speed optimization — optimizer selects speed from discrete set (10-16 kts in 0.5 kt steps) per leg
- SOG profile analysis — estimated speed-over-ground per waypoint with weather and current effects
- Dijkstra made optional — A* is the primary engine; Dijkstra time-expanded graph available via UI toggle (off by default) with node budget cap
- Smart grid bbox — strait waypoint expansion checks both lat AND lon proximity to avoid pulling in distant straits
- Smart retry logic — skip safety-fallback retry when >10K nodes explored (topology issue, not weather)
Infrastructure & Security
- Security hardening — fail-fast secrets validation, pinned dependency versions, container image scanning
- Tiered demo auth — bcrypt license keys with frame-limited demo mode
- Dark navy theme — unified dark palette across all pages
Complete structural refactoring of the API layer plus calibration accuracy improvements. Zero endpoint changes, zero test regressions (426 tests passing).
Monolith → Modular
- main.py reduced from 6,922 to 281 lines — now an application factory with startup/shutdown lifecycle only
- 9 domain routers extracted into
api/routers/: weather, vessel, voyage, optimization, engine_log, zones, cii, routes, system - 37 Pydantic schemas extracted into
api/schemas/(9 schema modules) — request/response models no longer embedded in endpoint code - Thread-safe VesselState — vessel model, specs, and calibration state managed by a singleton with
threading.Lockguards - WeatherService module — weather field accessors (wind, wave, current, SST, ice, visibility) extracted from inline endpoint logic
- ForecastLayerManager — deduplicates concurrent prefetch requests, tracks progress per layer, serves cached forecast frames
- All existing endpoints, URL paths, and response schemas unchanged
Calibration
- ME-specific fuel — calibration now uses main engine fuel (HFO ME + MGO ME) when available, falling back to total fuel only when ME columns are not reported; previous approach compared predicted ME fuel against total fuel (including auxiliary), biasing the calm water factor
- Laden/ballast detection from ME load % — entries classified by ME load percentage (>55% = laden), enabling correct displacement for resistance calculations; previously all entries were treated as laden
- Widened calibration bounds — calm water factor range expanded from (0.85, 1.5) to (0.6, 1.5), SFOC factor from (0.9, 1.2) to (0.85, 1.2), accommodating vessels where Holtrop-Mennen overpredicts
- Engine log deduplication — duplicate entries (same timestamp) are automatically skipped during upload
Engine log ingestion and analytics, physics model upgrade (SFOC fix, Kwon's wave resistance, performance predictor), weather pipeline refactoring, and dual-engine optimizer convergence with corrected cost formulas and MR safety limits.
Optimizer Fixes
- Dijkstra cost formula corrected — safety and zone multipliers now apply to fuel cost only, not the time penalty; previous formula
(fuel + lambda*hours) * safety * zoneinflated detour costs; fixed tofuel * safety * zone + lambda*hours - Hard avoidance limits — Hs >= 6m and wind >= 70 kts trigger instant rejection (
infcost) before computing vessel motions, matching MR Product Tanker operational limits (Beaufort 9+) - Wind speed plumbed to safety checks —
get_safety_cost_factor()now receives wind speed in both A* and Dijkstra engines - Dijkstra converges on 901nm route (Portugal to Casquets): 377 cells, 1.5s compute, -0.7% fuel savings
- A* converges on 901nm route: -2.6% fuel savings
Model Curves & Calibration
- Model curves endpoint —
GET /api/vessel/model-curvesreturns speed-indexed arrays for resistance, power, SFOC, and fuel consumption - Auto-load calibration — saved calibration factors restored on startup (survives container restarts)
- AnalysisPanel — calibration indicator and smart optimization route display
Layout Harmonization
- Standardized container layout (
container mx-auto px-6 pt-20 pb-12) across all dashboard pages - Vessel Model tab: 2x2 chart grid (was stacked), all charts at consistent height
- Engine Log: wider tab bar and upload section, consistent chart heights
- Analysis, CII, Live dashboard: consistent padding and offsets
Vessel Model Physics
- SFOC calibration factor fix —
sfoc_factorwas calibrated but never applied to the SFOC curve; now propagated throughVesselModel,state.py, and all model rebuild paths in the API - Kwon's wave resistance method — alternative to STAWAVE-1, selectable via
wave_methodparameter ('stawave1'|'kwon'); uses speed-loss percentage from Hs, Cb, Lpp, and directional factor (per TN001) - Performance predictor — bisection solver for the inverse problem: given engine load + weather, what speed is achievable? Returns STW, SOG, fuel/day, fuel/nm, resistance breakdown, weather speed loss
- Dual-mode prediction —
POST /api/vessel/predictaccepts eitherengine_load_pct(find speed at power) orcalm_speed_kts(find power for target speed); MCR capping with automatic fallback - Relative direction convention — all predictor directions are relative to bow (0 deg = ahead, 90 deg = beam, 180 deg = astern) instead of absolute compass headings
- Full model status endpoint —
GET /api/vessel/model-statusexposes all 20 VesselSpecs fields, calibration state, and computed optimal speeds - Physics-based fuel scenarios —
GET /api/vessel/fuel-scenariosreplaces hardcoded frontend scenarios with realVesselModel.calculate_fuel_consumption()results
Engine Log Analytics
- Engine log ingestion — upload CSV/Excel with automatic column mapping, parser handles multiple date formats and unit conversions
- Engine log DB model — batch + entries tables with indexes on timestamp, batch_id
- Entries browser — paginated entries with shared filters across Entries, Analytics, and Performance tabs
- Analytics dashboard — 5 KPIs (avg speed, avg fuel, efficiency, total distance, operating hours) + 6 interactive Recharts charts (speed-power scatter, fuel distribution, SFOC profile, voyage timeline)
- Performance tab — engine performance KPIs derived from operational data
- Engine-log calibration bridge —
POST /api/engine-log/calibrateruns vessel calibration against engine log entries - Vessel specs persistence — specs saved to PostgreSQL, restored on startup
Weather Pipeline
- User-triggered overlay model — removed all background ingestion loops, startup health gates, and ensure-all polling; weather data loads on demand when the user activates a layer
- Viewport-aware resync — per-layer
POST /api/weather/{layer}/resyncaccepts the frontend's current viewport bounds, so CMEMS data is downloaded for the region the user is viewing (not a hardcoded North Atlantic bbox) - CMEMS bbox cap — resync viewport capped at 40 deg lat x 60 deg lon to prevent API container OOM
- Overlay grid subsampling — all CMEMS overlay endpoints server-side subsampled to <=500 grid points per axis before JSON serialization
- Per-source isolation — resyncing one layer never touches another; supersede and orphan cleanup scoped by
sourcecolumn - Deferred supersede — new ingestion runs only replace old ones if they have >= forecast hours, preventing data loss when NOMADS/CMEMS is still publishing
- Wind DB fallback — when no GRIB file cache exists, wind frames are rebuilt from PostgreSQL
- Comprehensive pipeline documentation —
WEATHER_PIPELINE.mdrewritten with dataset sizes, memory estimates, subsampling rationale
Two-mode UI (Weather Viewer + Route Analysis), 7 weather overlay layers with forecast timeline, analysis panel with passage plan detail, route management, and production infrastructure.
Major UI overhaul to an ECDIS-style map-centric layout, enhanced weather visualization, and a formalized route optimization workflow with two speed strategies.
- ECDIS-style UI redesign — remove left sidebar, full-width map with header icon dropdowns for voyage parameters and regulation zones; consolidated vessel config, calibration, and fuel analysis into single
/vesselpage; ECDIS-style route indicator panel (bottom-left overlay) and right slide-out analysis panel - Wave crest rendering — Windy-style curved arc crest marks perpendicular to wave propagation direction, opacity scaled by wave height; click-to-inspect popup with SVG polar diagram showing wind, swell, and windwave components on compass rose
- Dual speed-strategy display — after A* path optimization, present two scenarios: Same Speed (constant speed, arrive earlier, moderate fuel savings) and Match ETA (slow-steam to match baseline arrival time, maximum fuel savings); strategy selector tabs in route comparison panel
- Voyage baseline gating — Optimize A* button disabled until a voyage calculation baseline is computed, ensuring meaningful fuel/time comparisons
- Dual-route visualization — display original (blue) and optimized (green dashed) routes simultaneously on map with comparison table (distance, fuel, time, waypoints) and Dismiss/Apply buttons
- GFS wind DB ingestion — add wind grids to the 6-hourly ingestion cycle (41 GFS forecast hours, 3h steps)
- Turn-angle path smoothing — post-filter removes waypoints with <15 deg course change to eliminate grid staircase artifacts from A* output
- A* optimizer tuning — increase time penalty to prevent long zigzag detours; scale smoothing tolerance to grid resolution
Pre-ingested weather grids in PostgreSQL, eliminating live download latency during route calculations.
- Weather ingestion service — background task downloads CMEMS wave/current and GFS wind grids every 6 hours, compresses with zlib (float32), stores in PostgreSQL
- DB weather provider — reads compressed grids, crops to route bounding box, returns
WeatherDataobjects compatible withGridWeatherProvider - Multi-tier fallback chain — Redis shared cache, DB pre-ingested, live CMEMS/GFS, synthetic
- Redis shared cache — replaces per-worker in-memory dict, all 4 Uvicorn workers share weather data
- Frontend freshness indicator — shows weather data age (green/yellow/red) in map overlay controls
- Performance: route optimization from ~90-180s to 2-5s; voyage calculation from minutes to sub-second
Component architecture refactor and Monte Carlo simulation engine.
- Frontend component split — monolithic
page.tsxrefactored into reusable components - Monte Carlo simulation — N=100 parametric simulation engine with P10/P50/P90 confidence intervals for ETA, fuel, and voyage time
- GridWeatherProvider — bilinear interpolation from pre-fetched weather grids, enabling 1000x faster A* routing
- Analysis tab — persistent storage of voyage results for comparison across routes
Live connectivity to Copernicus and NOAA weather services.
- CMEMS wave and current data — Copernicus Marine Service API integration with swell/wind-wave decomposition for accurate seakeeping
- GFS 5-day wind forecast timeline — f000-f120 (3-hourly steps) with Windy-style particle animation on the map
- ERA5 wind fallback — Climate Data Store reanalysis as secondary wind source (~5-day lag)
- Data sources documentation — credential setup guide, provider chain documentation
~67,000 lines of code across 197 files: 36K Python backend, 22K TypeScript frontend, 9K tests.
main— stable release branch (pushes trigger demo deployment via CI/CD)dev— active development branch
Full technical documentation, safety criteria, algorithm details, and changelog available at windmar-nav.github.io.
WindMar is free and open source. Sponsorships help fund ERA5 reanalysis, global coverage, automated weather refresh, and new vessel types.
Licensed under the Apache License, Version 2.0.
SL Mar







