Constraint-first polar-motion diagnostics dashboard for geometry, phase structure, and experimental transition-probability diagnostics
Source paper: Earth-Fixed Geometric Structure, Bistable Dynamics, and Phase-Locked Planetary Torque Coupling in Polar Motion
Current release: v1.5.1
- Added the Loop-Center Angular Velocity panel, reproducing the paper diagnostic from the live EOP store instead of a static figure.
- Preserved the paper-equivalent completed-loop smoothing while showing the newest incomplete-loop estimate as a separate provisional endpoint.
- Labeled low-radius provisional centers as low-confidence and added a visible endpoint error bar that combines robust residual spread with near-origin angular sensitivity.
- Added dashboard/docs guidance for interpreting provisional loop-center angular velocity without over-reading endpoint instability.
- Added confirmed turning-point markers to the Polar Motion Trajectory and Residual Polar Motion (XY) path views.
- Filtered unconfirmed boundary turning-point regions so the newest sample is not marked before the low-omega episode is bracketed by future data.
- Increased horizontal legend spacing in the Conditional Lag Response phase-bin slice plot.
- Updated internal docs with reordered experimental panel guides and a companion Phase-Locked Escape Model detail panel.
- Fixed adaptive turning-point detection so the default threshold no longer collapses the full omega history into one turning region.
- Reworked the conditional lag response anchors so all selected states can populate from contiguous state episodes, with sample-count metadata exposed to the transition panel.
- Updated transition probability to use the computed lag kernel, preserve base probability in cumulative probabilities, and report
P(≤30d)against the actual 30-day lag. - Fixed
R(t)tail computation so the latest samples use trailing windows instead of being forward-filled from the last pre-padding value. - Added rolling-stats cache invalidation for model-code changes so derived outputs refresh when the Python computation changes.
- Added the Residual Polar Motion (XY) panel and Polar Motion Trajectory panel, both with square plot geometry and chronological path coloring.
- Standardized the polar-motion displays against the IERS EOP convention:
x_poleis shown north/up along the Greenwich meridian andy_poleis shown west/left toward 90°W. - Aligned the 3D Vector View with the same frame, including unambiguous vector labels, drift longitude in E/W notation, and clearer label placement.
- Enlarged and corrected square fullscreen modals so the residual, trajectory, and 3D views can use the available browser window efficiently.
- Added the Phase-Locked Escape Model as the first full-width dashboard panel, using internal DRIFT state plus DE442-derived phase composites rather than exploratory CSV exports.
- Added phase drift, local linear time-to-alignment, oscillatory regime detection, phase acceleration, curvature signal, and phase stability diagnostics.
- Added the escape-energy diagnostic: phase kinetic energy, phase potential energy, total phase energy, barrier ratio, energy-state classification, and a Kramers-like comparative index using
R(t)as a noise proxy. - Added energy overlays and optional time-series traces for phase potential energy, total phase energy, and barrier ratio.
- Added a sidebar-driven Update Data workflow that runs
scripts/fetch_latest.pythrough a local API route, with spinner feedback and post-update dashboard reload. - Added timestamp-aware freshness checks to
scripts/fetch_latest.pyso EOP, GFZ-KP, GRACE, and combined outputs are skipped while local files are still fresh; use--forcefor a full manual refresh. - Reworked panel fullscreen behavior so the existing panel instance expands in place, preserving selected traces, ranges, controls, and guide/info content across panel and fullscreen views.
- Removed synthetic GRACE, inertia, and fallback geomagnetic-axis data from the ingestion and retrieval pipeline so the dashboard now serves real inputs only.
- Corrected the phase portrait and phase-diagnostics handling around phase-wrap artifacts to avoid spurious branch-cut spikes in the displayed loop geometry.
- Temporarily disabled the Angle Diagnostics and Alignment panels in the UI while their real-data-only replacements are being reworked.
- Added date information to the Phase Portrait hover popup so users can identify when specific phase-space features, loops, and turning points occurred.
- Added a highlighted present-state marker and recent trajectory overlay to the Phase Portrait, now focused on the last 180 days.
- Enlarged fullscreen popup charts to use roughly 85% of browser width and a taller plotting area, with responsive plot resizing inside the modal.
- Added shared fullscreen-aware plot sizing so expanded charts across the dashboard actually use the larger popup dimensions.
- Moved stale-data checking and conditional pipeline execution to server startup so the dashboard only launches after required data are current.
- Fixed Transition Probability plot redraw and rescaling when State or Base Prob changes.
- Compacted the sidebar layout, restored clean stacking between Sources and Panels, and improved sidebar scrolling on medium-height displays.
- Corrected the Transition Probability expected-date label so it now adds the probability horizon to the actual current date rather than the cached data timestamp.
- Added start, back, forward, and finish controls to the 3D Vector View timeline for direct frame stepping.
- Reworked 3D playback timing to use elapsed time rather than rounded interval steps, improving low-speed behavior and realtime smoothness.
- Anchored Transition Probability expected dates to the latest available sample so 3D timeline scrubbing no longer shifts the probability horizon.
- Replaced the plain startup loading text with a centered animated progress widget for a cleaner initial launch experience.
- Added DE442-backed Earth-geocentric overlay signals for all tracked bodies.
- Added a slim daily ephemeris cache covering
1973-01-02through2050-12-31. - Added overlay-selectable distance, angular velocity, radial velocity, ecliptic longitude, and heuristic torque-proxy series.
- Removed hidden default ephemeris selections so an unchecked overlay plot is truly empty.
The dashboard is built around the source paper Earth-Fixed Geometric Structure, Bistable Dynamics, and Phase-Locked Planetary Torque Coupling in Polar Motion, which analyzes polar motion with a constraint-first method: start from the geometric structure required by the observations, then interpret cautiously.
The paper's strongest claims are:
- polar motion is confined to a low-dimensional, near-planar structure over the observed interval
- projection onto the dominant axis reveals a robust two-state or bistable organization
- residual phase space shows coupled fast-slow behavior: looping motion embedded in a slower drifting structure
The paper is also explicit about what is weaker:
- absolute directional anisotropy and apparent axis stability are not statistically decisive against correlated-noise null models
- conclusions apply to the observed record, not necessarily to all times outside that window
- comparative geomagnetic context may be suggestive, but it is not by itself proof of a causal coupling
This repository should therefore be read as a geometry-first monitoring tool. The geomagnetic panels are comparison layers, and the Transition Probability and Phase-Locked Escape Model panels are explicitly experimental diagnostics derived from lag-conditioned and phase-conditioned state structure rather than deterministic prediction engines.
# Install dependencies
npm install
# Refresh pipeline artifacts as needed; fresh local source files are skipped
python scripts/fetch_latest.py
python scripts/fetch_latest.py --force
python scripts/combine_data.py
# Run development server
npm run dev
# Open http://localhost:3000Build the production image:
docker build -t drift-dashboard:latest .Run it locally or on a Linux host:
docker run -d \
--name drift-dashboard \
-p 3000:3000 \
--restart unless-stopped \
drift-dashboard:latestNotes:
- The container serves the Next.js app on port
3000. - Python runtime dependencies are bundled because
/api/rolling-statscomputes diagnostics on demand. - The image includes the current
data/,public/data/, andscripts/directories needed by the dashboard. - Point your reverse proxy or firewall rule at the host’s port
3000.
The live deployment is designed around a single Linux VM:
- public app URL:
https://drift.nobulart.com - app container port:
3000 - edge web server:
nginx - TLS: Let's Encrypt via
certbot
Internet
-> nginx on ports 80/443
-> reverse proxy to 127.0.0.1:3000
-> Docker container running the Next.js standalone server
Build and publish the production image for the target host architecture:
docker buildx build \
--platform linux/amd64 \
-t sunbear73/drift-dashboard:latest \
--push .Install Docker:
apt-get update
apt-get install -y docker.io
systemctl enable --now dockerInstall the reverse proxy and TLS tooling:
apt-get install -y nginx certbot python3-certbot-nginx
systemctl enable --now nginxPull the latest image and replace the running container:
docker pull sunbear73/drift-dashboard:latest
docker rm -f drift-dashboard || true
docker run -d \
--name drift-dashboard \
--restart unless-stopped \
-p 3000:3000 \
sunbear73/drift-dashboard:latestVerify locally on the server:
docker ps
docker logs --tail=100 drift-dashboard
curl -I http://127.0.0.1:3000Create /etc/nginx/sites-available/drift.nobulart.com:
server {
listen 80;
listen [::]:80;
server_name drift.nobulart.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 300;
}
}Enable the site:
ln -sf /etc/nginx/sites-available/drift.nobulart.com /etc/nginx/sites-enabled/drift.nobulart.com
rm -f /etc/nginx/sites-enabled/default
nginx -t
systemctl reload nginxAfter the DNS A record for drift.nobulart.com points to the server public IP, issue the certificate:
certbot --nginx -d drift.nobulart.com --redirectUseful checks:
dig +short drift.nobulart.com
curl -I http://drift.nobulart.com
curl -I https://drift.nobulart.com
certbot certificatesFor subsequent updates, the deployment cycle is:
npm run builddocker buildx build --platform linux/amd64 -t sunbear73/drift-dashboard:latest --push .- SSH to the deployment host
docker pull sunbear73/drift-dashboard:latestdocker rm -f drift-dashboard || truedocker run -d --name drift-dashboard --restart unless-stopped -p 3000:3000 sunbear73/drift-dashboard:latest- Verify
https://drift.nobulart.com
Use this sequence when staging a new build to the live VM.
- Confirm the working tree is clean enough to release:
git status --short --branch
npm run lint
npx tsc --noEmit
npm run build- Push the release commit to GitHub:
git push origin main- Build and publish the Linux image used by the deployment host:
docker buildx build \
--platform linux/amd64 \
-t sunbear73/drift-dashboard:latest \
--push .- SSH to the deployment VM as
rootand confirm the currently running container:
ssh root@drift.nobulart.com
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'- Pull the freshly published image and replace the container:
docker pull sunbear73/drift-dashboard:latest
docker rm -f drift-dashboard || true
docker run -d \
--name drift-dashboard \
--restart unless-stopped \
-p 3000:3000 \
sunbear73/drift-dashboard:latest- Verify on the VM before checking the public URL:
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'
docker logs --tail=100 drift-dashboard
curl -I http://127.0.0.1:3000- Verify the public deployment and the visible version from another shell:
curl -I https://drift.nobulart.com
curl -s https://drift.nobulart.com/docs | rg 'Version v'- If the public site still appears stale in a browser, hard-refresh first. If the curl checks still show the old version, the container was not actually refreshed and steps 4-7 should be repeated.
- A successful image push does not mean the live host is updated. The VM must still
docker pulland restartdrift-dashboard. - The most reliable user-visible version check is currently the docs badge at
/docs. - If SSH by hostname fails, use the current VM address from the hosting console rather than hard-coding server IPs or credentials into the repo.
drift/
├── app/ # Next.js App Router pages
├── components/ # React components
│ ├── Controls.tsx # UI controls
│ ├── PolarPlot.tsx # Polar motion visualization
│ ├── DriftDirectionPlot.tsx # Drift direction plot (PRIMARY)
│ ├── TransitionForecastPanel.tsx # Experimental lag-conditioned transition probability
│ └── SphereView.tsx # 3D frame visualization
├── lib/ # Core libraries
│ ├── math.ts # Vec3 operations
│ ├── transforms.ts # Frame transformation utilities
│ ├── drift.ts # PCA-based drift extraction
│ ├── parsing.ts # Data parsing utilities
│ └── types.ts # Shared type definitions
├── store/ # Zustand state management
├── scripts/ # Data pipeline scripts
├── public/data/ # Preprocessed data files
└── api/ # Next.js API routes
- Polar Motion Visualization - Plot xp/yp from IERS and inspect confinement, loops, and turning points
- Drift Direction - Track the dominant axis implied by the local geometry
- Phase Diagnostics - Read looping structure, angular velocity, and intermittency in phase space
- Orthogonal Deviation and Lag Structure - Compare local anisotropy, turning-point response, and conditional lag behavior
- Geomagnetic Context - Compare dashboard geometry with Kp/ap and related context without assuming causation
- Transition Probability - Surface transition-like similarity using lag-conditioned historical structure
- Planetary Overlay Context - Compare drift and related signals against DE442-derived Earth-geocentric planetary observables
- Phase-Locked Escape Model - Inspect phase-dependent escape probability, phase drift, curvature, escape-energy diagnostics, barrier ratio, and residual phase misalignment from internal DRIFT state plus DE442
scripts/fetch_latest.py- Refresh upstream source cachesscripts/combine_data.py- Merge observed source products into dashboard-ready JSONscripts/compute_rolling_stats.py- Compute rolling diagnostics, lag models, and transition-probability inputsscripts/build_ephemeris.py- Extract slim DE442 overlay series into daily JSON cachescripts/compute_phase_escape.py- Build phase-escape state inputs from internal EOP and DE442 caches
- Returns cached historical Earth Orientation Parameters from
eop_historic.json. - Primary fields:
t,xp,yp.
- Returns cached inertia-frame time series from
inertia_timeseries.jsonwhen real upstream inputs are available. - Primary fields:
t,e1,e2,e3.
- Returns cached GRACE / GRACE-FO mass-context series from
grace_historic.jsonwhen real upstream inputs are available. - Primary fields:
t,lwe_mean,lwe_std.
- Returns normalized daily GFZ geomagnetic records derived from
geomag_gfz_kp.json. - Primary fields:
t,kp,ap,cp,c9.
- Returns the raw cached GFZ geomagnetic history from
geomag_gfz_kp.json. - Use this when you want the underlying cached series without the extra normalization wrapper used by
/api/geomag.
- Returns a lightweight merged series combining EOP with any available real auxiliary fields where dates overlap.
- Primary fields:
t,xp,yp, optionalgrace_lwe_mean,grace_lwe_std.
- Returns the full combined dashboard dataset from
combined_historic.json. - Primary fields include
t,xp,yp, geomagnetic context, GRACE context, and inertia-frame vectors when available from real cached products.
- Returns the cached DE442-derived Earth-geocentric overlay dataset.
- Current cache window:
1973-01-02through2050-12-31. - Primary payload shape:
sourcemetadata plusrecords[], where each record hastandbodies. - Per-body overlay metrics currently exposed:
distance_au,angular_velocity_deg_per_day,radial_velocity_km_s,ecliptic_longitude_deg,torque_proxy.
- Computes or serves cached rolling diagnostics from
compute_rolling_stats.py. - Supported query params:
windowSize,turnThreshold,centerWindow,centerStep,danceWindow,conditionalTargetState. - Returns rolling geometry and state outputs such as
theta,omega,rRatio,turningPoints,lagModel, andconditionalLagModel.
- Converts the requested lag-conditioned state kernel into a forward transition probability curve.
- Supported query params:
currentState,theta,baseProb,smoothSigma. - Returns
lags,P_tau,expected_time,peak_time,cumulative,probability_level,probability_message, and related probability-summary metadata.
- Builds the Phase-Locked Escape Model inputs from the internal DRIFT EOP state and the cached DE442 ephemeris series.
- Computes solar-residual DRIFT phase, DE442 torque-proxy analytic phases, the registered planetary composites, and residual phase misalignment.
- Supports the panel's phase-drift, phase-acceleration, escape-energy, barrier-ratio, and Kramers-like comparative diagnostics in the frontend model layer.
- Does not depend on
docs/drift.csvor anydocs/outputsexploratory artifacts.
- Drift Axis: PCA on sliding window of polar motion
- θ3: Angle between drift and e3 (out-of-plane tilt)
- θ12: In-plane alignment angle to e1
- Phase Portrait: Fast cyclic structure in
(theta, omega)state space - Orthogonal Deviation Ratio: Local elongation versus isotropy of the inferred structure
Use the dashboard in this order when you want the most paper-aligned interpretation:
- Start with
Polar Motion,Drift Direction, andR(t)to assess the geometry itself. - Use
Phase PortraitandPhase Diagnosticsto inspect fast-slow organization and intermittent behavior. - Check the 3D panel, overlays, and any available geomagnetic context for timing comparison.
- Use the
Phase-Locked Escape Model(experimental) to inspect phase-conditioned escape probability, drift, curvature, barrier ratio, and comparative escape-energy diagnostics. - Read
Transition Probability(experimental) as an exploratory summary of whether the current state resembles prior transition-like behavior.
If a conclusion depends mainly on geomagnetic coincidence or on a single transition-probability peak, it is weaker than a conclusion supported by the geometric panels together.
The Phase-Locked Escape Model panel uses the production DRIFT database/state and the internal DE442 ephemeris pipeline. docs/drift.csv was an exploratory analysis export only; the production panel does not read that CSV and does not require files from docs/outputs at runtime.
The model is an experimental phase-conditioned metastable escape diagnostic. It reports residual phase misalignment, phase-dependent escape probability, phase drift, local linear time-to-alignment, phase acceleration, curvature signal, phase stability, the current metastable phase-well state, and high-R escape modulation. It should not be read as deterministic planetary forcing or prediction certainty.
The escape-energy diagnostic treats residual phase motion as movement in a modulated phase potential. Kinetic energy is estimated from phase velocity, potential energy from angular offset relative to the preferred escape phase, and the barrier ratio normalizes the current phase-energy state against the empirical modulation barrier. The Kramers-like index uses R(t) as a noise proxy and should be interpreted as a comparative index rather than an absolute probability, physical-joule energy, or deterministic transition clock.
- Next.js 14+ (App Router)
- TypeScript (strict mode)
- Plotly.js for charts
- Three.js (react-three-fiber) for 3D
- Zustand for state
- Tailwind for styling
