MRVA container
The analysis stage: fits the multi-scale field to every observation and writes the NetCDF product.
This directory contains the containerized implementation of the MRVA (Multi-Resolution Variational Analysis) module for the MUR (Multi-scale Ultra-high Resolution) SST processing pipeline.
Overview
MRVA is the core analysis stage of the MUR SST pipeline that combines satellite and in-situ observations using multi-scale variational analysis to produce high-resolution (~1 km) daily foundation sea surface temperature fields.
Key Features:
- Multi-scale progressive refinement (L=2-11, ~400 km down to ~1 km resolution)
- Optimal interpolation with spatial smoothness constraints
- Temporal decorrelation modeling (scale-dependent decay times)
- GHRSST L4 compliant NetCDF4 output
- OpenMP parallelized Fortran core with MATLAB orchestration
Architecture
The MRVA container uses a multi-stage Docker build pattern:
- Build Stage: Full MATLAB R2024b + gfortran compiler
- Compiles 5 Fortran executables (
mrva,spgrid,trimbip3,makehiresgrid,samplegdscsp) - Compiles MATLAB wrapper using
mcc(includes 70+ MATLAB scripts) - Creates standalone deployment package
- Compiles 5 Fortran executables (
- Runtime Stage: MATLAB Runtime R2024b only (~4GB vs ~8GB for full MATLAB)
- Copies compiled binaries from build stage
- Minimal dependencies (curl, wget, gzip, libgomp1)
- Fixed container paths for reproducibility
Prerequisites
System Requirements
- Memory: 32GB (NRT mode) to 64GB (REA mode) recommended
- L=11 grid: 51,712 × 23,040 = 1.19 billion points
- Processing memory: ~15GB per scale
- CPU: 8-16 cores (OpenMP parallelization enabled)
- Disk: 10GB temporary space for intermediate files
- Docker: Version 20.10+ with platform support (linux/amd64)
Build Requirements
- Access to JPL MATLAB license servers (network connectivity required during build)
- MATLAB R2024b license with Compiler, Image Processing, and Statistics toolboxes
- Docker with multi-stage build support
Input Data Requirements
MRVA requires preprocessed data from earlier pipeline stages:
- L2P Satellite Data (BIC.gz format)
- From
l2pmodule:/testing/preprocessing/output/l2p/ - Sensors: AMSR2R, MODISA, MODIST, AVMTAG, AVMTBG
- Files:
Global_SENSOR_YYYY_DDD.bic.gz
- From
- iQUAM Buoy Data (BII format)
- From
iquammodule:/testing/preprocessing/output/iquam/ - Files:
Global_IQUAM0_YYYY_DDD.bii
- From
- Land/Ice Masks (BIP format)
- From
landicemodule:/testing/preprocessing/output/landice/YYYY/ - Files:
Global_ice_YYYY_DDD.bip.gz,landiceP01_YYYY_DDD.gds.gz
- From
- Polar Cap Reference File (Static, one-time setup)
- File:
CylinderP01_edge.bip(~33 MB) - Location:
testing/static-resources/landice/CylinderP01_edge.bip - Purpose: Synthetic observations for polar latitudes (89°-95° N/S) to handle coordinate singularity
- Generation: One-time using
makeedge.mscript (see setup section below) - Note: This is a static reference file, not generated by preprocessing stages
- File:
Initial Setup
Generate Polar Cap Reference File (One-Time)
Before running MRVA for the first time, you must generate the static polar cap reference file:
# Navigate to the legacy code directory
cd mur-internal/icenew/p01/
# Run MATLAB to generate the file
matlab -batch "addpath('../mat'); makeedge"
This creates /nas2/landice/CylinderP01_edge.bip (~33 MB). For containerized deployment, copy it to the static resources directory:
# Create static resources directory
mkdir -p testing/static-resources/landice
# Copy the generated file
cp /nas2/landice/CylinderP01_edge.bip \
testing/static-resources/landice/CylinderP01_edge.bip
What it does: Creates synthetic SST observations (-1.8°C, weight=100) at polar latitudes (89°-95° N/S) in a cylindrical grid pattern to handle coordinate singularity at the poles.
Why it's needed: The MRVA algorithm needs observations at all latitudes. Real satellite/buoy data has gaps at extreme polar latitudes due to coordinate system limitations. This file provides synthetic "observations" to fill those gaps and prevent numerical instabilities.
Note: This file never changes and only needs to be generated once. If missing, MRVA will run but with reduced accuracy at polar latitudes.
Building the Container
Quick Start
Build with build_module.sh from the mur/ directory:
cd mur
./build_module.sh mrva
It builds the mur-matlab-base:r2024b image first if missing, checks that network.lic exists, builds --platform linux/amd64 with the parent mur/ directory as context, and tags the image mur-mrva:latest — the name config.json expects.
Build Options:
# Force rebuild without cache (useful after code changes)
./build_module.sh mrva --no-cache
# Debug build: symbols, bounds checking, uninitialized-variable and FP-exception traps
# (still tagged :latest, so the pipeline picks it up unchanged)
./build_module.sh mrva --debug
Build Time: ~15-30 minutes (depends on network speed and CPU), plus ~15-20 minutes the first time the base image is built.
Build Stages:
- Compile Fortran executables with the Intel oneAPI toolchain (~2 min)
- Compile the MATLAB application against
mur-matlab-base:r2024b(~10-20 min) - Create runtime image (~2 min)
Manual Build (Advanced)
Only when build_module.sh doesn't fit — a custom tag, external CI, or debugging the Dockerfile. Build context must be the parent mur directory (for common/), and the base image must already exist (./build_matlab_base.sh from mur/):
cd mur/mrva
docker build --platform linux/amd64 -t mur-mrva:latest -f Dockerfile ..
# Debug variant (what --debug passes)
docker build --platform linux/amd64 --build-arg DEBUG=1 -t mur-mrva:latest -f Dockerfile ..
Running the Container
Container Interface
Named args only — every input is an explicit flag, resolved by the calling Python orchestrator (run_mur_pipeline.py / run_mur_maap.py). See mrva/bin/entrypoint.sh's usage() for the authoritative flag list; the static and dynamic input flags mirror static input data.
docker run [OPTIONS] mur-mrva:latest \
--year YEAR --doy DOY --mode MODE [--sensors LIST] \
--polar-cap-edge-file FILE --seasonal-file FILE \
--landice-ice-p011-file FILE --landice-grid-p01-file FILE --landice-icefiles-p011-file FILE \
--sensor-inputs-manifest FILE \
[--mur25-grid-file FILE] [--prior-csp-file FILE] [--l4-reference-root DIR] [--debug]
Arguments:
| Argument | Required | Description | Example |
|---|---|---|---|
--year | Yes | 4-digit year | 2025 |
--doy | Yes | Day of year (1-366) | 220 |
--mode | Yes | Processing mode: nrt or rea | nrt |
--sensors | No | Comma-separated sensor list (default: all configured) | AMSR2R,MODISA |
--sensor-inputs-manifest | Yes | Path/href to a manifest JSON listing this run's BIC + iQuam files (schema: the input contract, §3) | |
--mur25-grid-file | No | Absent → skip MUR25 generation | |
--prior-csp-file | No | Absent → bootstrap reference field from L4 instead |
Every FILE/DIR value may be a local path or an s3:// href — resolved via common/bin/localize.sh before MATLAB runs.
Processing Modes:
- NRT (Near Real-Time): L0=6 → LF=11 (starts at ~50 km resolution)
- Faster processing (~1-2 hours)
- Used for recent data within stability latency
- Interim product (may be reprocessed)
- REA (Reanalysis): L0=2 → LF=11 (starts at ~400 km resolution)
- Comprehensive processing (~3-4 hours)
- Used for stable historical data
- Final product (not reprocessed)
Volume Mounts
Output/working paths are still fixed container-internal bind mounts, unchanged from before — only the input side became explicit flags:
| Container Path | Purpose | Example Host Path |
|---|---|---|
/data/output/csp/ | Coefficient files (CSP format) | /local/mrva/output/csp/ |
/data/output/netcdf/ | Final NetCDF4 products | /local/mrva/output/netcdf/ |
/data/cache/ | Temporary working files | /local/mrva/cache/ |
/data/logs/ | Execution logs | /local/mrva/logs/ |
Every input flag's value (a local path or an s3:// href) needs to be reachable from inside the container — for local paths, bind-mount the source root at the same absolute path (run_mur_pipeline.py does this automatically); for s3:// hrefs, no mount is needed at all.
Example Usage
In practice, use run_mur_pipeline.py (local) or run_mur_maap.py (MAAP) — both resolve every flag automatically (static-resource files, per-day landice outputs, and the sensor-inputs manifest) and invoke the container correctly. The flags below are for manual/debug invocation only:
docker run --rm \
--memory=32g --shm-size=4g \
-v /local/static-resources:/local/static-resources:ro \
-v /local/preprocessing:/local/preprocessing:ro \
-v /local/manifest.json:/local/manifest.json:ro \
-v /local/mrva/output:/data/output \
-v /local/mrva/cache:/data/cache \
-v /local/mrva/logs:/data/logs \
mur-mrva:latest \
--year 2025 --doy 220 --mode nrt \
--polar-cap-edge-file /local/static-resources/landice/CylinderP01_edge.bip \
--seasonal-file /local/static-resources/seasonal/mur_220.nc \
--landice-ice-p011-file /local/preprocessing/landice-p011/2025/Global_ice_2025_220.bip \
--landice-grid-p01-file /local/preprocessing/landice-p01/2025/landiceP01_2025_220.gds.gz \
--landice-icefiles-p011-file /local/preprocessing/landice-p011/2025/icefiles_2025_220.txt \
--sensor-inputs-manifest /local/manifest.json \
--l4-reference-root /local/static-resources/L4
Testing
Basic Validation
Validates that the container is built correctly and all components are present:
cd mur/mrva
./test_container.sh basic
Tests:
- ✓ Image exists
- ✓ Entrypoint shows usage
- ✓ Fortran executables present
- ✓ MATLAB executable present
- ✓ Directory structure correct
Full Processing Test
Runs MRVA with sample data from preprocessing pipeline:
cd mur/mrva
./test_container.sh full
Prerequisites:
- Preprocessing stages must be run first to generate test data
- Run:
uv run run_mur_pipeline.py --config config.json --date 2024-08-08 --execute landice,iquam,l2p
Integration with Orchestrator
MRVA is integrated into the main pipeline orchestrator (run_mur_pipeline.py).
Configuration
Add MRVA configuration to mur/config.json:
{
"mrva": {
"container_image": "mur-mrva:latest",
"input_dir_bic": "testing/preprocessing/output/l2p",
"input_dir_iquam": "testing/preprocessing/output/iquam",
"input_dir_landice": "testing/preprocessing/output/landice",
"output_dir_csp": "testing/mrva/output/csp",
"output_dir_netcdf": "testing/mrva/output/netcdf",
"cache_dir": "testing/mrva/cache",
"logs_dir": "testing/mrva/logs",
"active_sensors": ["IQUAM0", "AMSR2R", "MODISA", "MODIST", "AVMTAG", "AVMTBG"],
"L0_nrt": 6,
"L0_rea": 2,
"LF": 11,
"decay": [48, 48, 48, 48, 48, 48, 42, 36, 30, 24, 18, 12]
}
}
Running via Orchestrator
There is no separate --run-mrva flag — MRVA runs by default alongside landice/iquam/l2p unless you narrow the run with --preprocess-only or --execute:
# Run full pipeline including MRVA
uv run run_mur_pipeline.py --config config.json --date 2024-08-08
# Run only MRVA stage (requires preprocessed inputs already present)
uv run run_mur_pipeline.py --config config.json --date 2024-08-08 --execute mrva --keep-containers
# Run full window (9 days) including MRVA
uv run run_mur_pipeline.py --config config.json --all-stages
--keep-containers is worth adding when debugging a specific day — it stops the container from being auto-removed on failure, so docker logs <container_name> still works afterward.
Output Files
Coefficient Files (CSP Format)
Location: /data/output/csp/YYYY/
Files:
YYYYMMDDH_MRVA4_Global.c02through.c11- Analysis coefficients per scaleYYYYMMDDH_MRVA4_Global.u06through.u08- Uncertainty estimates (optional)
Format: Binary Fortran unformatted (see filemod.f for structure)
NetCDF4 Output (GHRSST L4)
Location: /data/output/netcdf/YYYY/DDD/
File: YYYYMMDD090000-JPL-L4_GHRSST-SSTfnd-MUR-GLOB-v02.0-fv04.1.nc
Variables:
analysed_sst(time, lat, lon)- Foundation SST [Kelvin, float32]analysis_error(time, lat, lon)- Uncertainty (1σ) [Kelvin, float32]mask(time, lat, lon)- Land/sea/ice classification [int8]sea_ice_fraction(time, lat, lon)- Ice concentration [0-1, float32]dt_1km_data(time, lat, lon)- Distance to high-res obs [km, float32]
Grid:
- Longitude: -179.995° to 180.005° (36,000 points, 0.01° resolution)
- Latitude: -89.995° to 89.995° (17,999 points, 0.01° resolution)
- Time: Single daily analysis at 09:00 UTC
Compliance: GHRSST Data Specification v2.0
Performance Characteristics
Processing Time
| Mode | Scales | Time (16 cores) | Memory |
|---|---|---|---|
| NRT | L=6-11 | ~1-2 hours | ~32 GB |
| REA | L=2-11 | ~3-4 hours | ~64 GB |
Breakdown:
- Data preparation (BIQ generation): ~5 min
- Reference field generation: ~10 min
- Outlier detection: ~5 min
- Bias correction: ~5 min
- MRVA core (L=2-11): ~30-45 min per scale
- NetCDF generation: ~20 min
Parallelization
- Fortran: OpenMP parallelization across observation loop
- Set
--cpus=Nto control thread count - Scales well up to 16 cores
- Memory bandwidth limited beyond 16 cores
- Set
- MATLAB: Single-threaded orchestration
- NetCDF generation can be backgrounded
Troubleshooting
Build Issues
Problem: Compilation timeout after 10 minutes
ERROR: Compilation failed or timed out after 10 minutes
Solution: Check MATLAB license server connectivity
- Verify network access to JPL license servers
- Check firewall rules for port 7282
- Try building with
--no-cacheto force re-download of mpm
Problem: Fortran compilation fails with gfortran
Error: Unclassifiable statement at (1)
Solution: Fortran source uses fixed-form format
- Ensure Makefile uses
-ffixed-line-length-noneflag - Original code uses Intel Fortran; gfortran compatibility may vary
- Consider using Intel oneAPI HPC Toolkit base image for production
Runtime Issues
Problem: Container exits with "No such file or directory"
ERROR: /opt/mrva/bin/mrva: No such file or directory
Solution: Platform mismatch (common on Apple Silicon)
- Add
--platform linux/amd64to docker run command - Rebuild with
./build_module.sh mrva(frommur/), which always builds--platform linux/amd64
Problem: Out of memory error during L=10 or L=11
Error: Memory allocation failed
Solution: Increase container memory limits
- NRT mode: Minimum 32GB (
--memory=32g) - REA mode: Minimum 64GB (
--memory=64g) - Also increase swap:
--memory-swap=72g - Check host system has sufficient RAM available
Problem: Missing input files
WARNING: L2P data directory not found
Solution: Run preprocessing stages first
# Generate required input data
uv run run_mur_pipeline.py --config config.json \
--date 2024-08-08 \
--execute landice,iquam,l2p
Performance Issues
Problem: Processing slower than expected
Solutions:
- Check CPU allocation: Ensure
--cpus=16or similar - Verify OpenMP threads: Container should log thread count at startup
- Check I/O: Slow disk or network mounts can bottleneck
- Review logs: Look for repeated warnings or error-recovery loops
Advanced Configuration
Custom Decay Times
Edit config.json to adjust temporal decorrelation parameters:
{
"mrva": {
"decay": [48, 48, 48, 48, 48, 48, 42, 36, 30, 24, 18, 12]
}
}
- 12 values corresponding to L=0 through L=11
- Units: hours (time scale for exponential decay)
- Lower values = stronger temporal constraint
- Default values from production system
Scale Range Adjustment
Modify start/end scales:
{
"mrva": {
"L0_nrt": 6, # NRT starts at L=6 (~50 km)
"L0_rea": 2, # REA starts at L=2 (~400 km)
"LF": 11 # Both end at L=11 (~1 km)
}
}
Trade-offs:
- Higher L0 → Faster, but less large-scale constraint
- Lower LF → Faster, but coarser output resolution
References
Documentation
- The algorithm: the MRVA algorithm
- The implementation: MRVA internals
- Daily scheduling: daily execution
Source Code
- Fortran: src/fortran/
mrva.f- Main variational analysisspmm.f- Spline module (1266 lines)filemod.f- Binary I/O modulespgrid.f- Coefficient samplingtrimbip3.f- Outlier filteringmakehiresgrid.f- Distance-to-land grid
- MATLAB: src/matlab/
workflow/mrva4com.m- Main orchestrationpreprocessing/- Data preparation (14 scripts)io/- Binary file I/O (16 scripts)output/csp2nc4a.m- NetCDF generation
Publications
- Chin, T. M., et al. (2017). "A multi-scale high-resolution analysis of global sea surface temperature." Remote Sensing of Environment, 200, 154-169.
- JPL MUR Project: https://podaac.jpl.nasa.gov/dataset/MUR-JPL-L4-GLOB-v4.1
License
This software is subject to NASA JPL licensing terms. Contact the MUR team for details.
Support
For questions or issues:
- Check Troubleshooting section
- Review logs in
/data/logs/ - Contact MUR development team
The image ships MATLAB Runtime R2024b and Fortran built with gfortran (GCC).