Spatial-Causal Geometry · SPARC Dataset · 2025

What does space already know
about a galaxy
before we look?

A single geometric constant — the causal ratio γcause = 1.216 — partitions each galaxy into causal domains before any velocity data is consulted. Rotation curves emerge from that geometry alone.

1.216 γ_cause invariant
145 SPARC galaxies
0 Velocity data points used to place boundaries
0 Free parameters

The Rotation Problem

Galaxies spin too fast. The outer stars move as though held by invisible hands — far beyond what visible matter should allow. According to Newtonian dynamics, velocity should fall off with distance. Instead, rotation curves flatten and hold. This discrepancy is one of modern astrophysics's most enduring puzzles.

In 1933, Fritz Zwicky identified excess motion in galaxy clusters and proposed unseen mass — dunkle Materie. In the 1970s, Vera Rubin confirmed the effect in individual spirals with unmistakable precision. The mainstream response has been to invoke a massive dark matter halo surrounding each galaxy. An alternative, MOND, modifies dynamics at low accelerations. Both approaches reproduce the general shape of rotation curves — but neither arises from first principles, and neither connects the phenomenon to a fundamental constant of nature.

"If I could have my pick, I would like to learn that Newton's laws must be modified in order to correctly describe gravitational interactions at large distances." — Vera Rubin, 1980

Spatial-Causal Geometry offers a third path — not added mass, not modified force, but a change in the question itself.

The Geometric Perspective

In SCG, space is not empty. It has structure: a scalar density field ρ(x) whose gradients generate all apparent forces. Acceleration is not caused by mass pulling — it emerges from curvature in the log of this field:

\[ a(x) = c^2 \cdot \nabla \ln \rho(x) \]
THE SCG FIELD EQUATION

This is not a force law. It is a statement about geometry. Where the field curves, structures respond. Where it is flat, nothing moves. The geometry of space itself drives the motion of stars.

From this field equation, circular motion in a disk galaxy follows directly. A star at radius r within a causal domain where the density field has local exponent Bi will orbit with velocity:

\[ v(r) \propto r^{(1 - B_i)/2} \]
SCG VELOCITY LAW

When Bi ≈ 1, velocity is approximately flat — the canonical "flat rotation curve." When Bi < 1, velocity rises. When Bi > 1, it falls. The full variety of observed galactic rotation profiles emerges naturally from local variations in the causal-density exponent — no free parameters, no dark matter.

The Invariant: γ_cause = 1.216

The critical question in applying this framework to galaxies is: where do the domain boundaries sit? What determines where one kinematic regime ends and another begins?

The answer is a universal geometric constant. Derived originally from the causal closure condition of transverse electromagnetic oscillations — the requirement that a photon's internal structure remain coherent across its propagation — the causal ratio γcause defines the ratio between causal path length L and propagation wavelength λ in any c-bounded system:

\[ \gamma_{\text{cause}} = \frac{L}{\lambda} \approx 1.216 \]
THE CAUSAL INVARIANT

Applied to a galaxy, this invariant defines the radial width of each causal domain — the distance over which one geometric closure of the causal field occurs. The spacing rule is:

\[ \Delta r_i = \gamma_{\text{cause}} \cdot \sqrt{r_i} \]
DOMAIN SPACING LAW

These boundaries are computed from the invariant alone — before any velocity data is consulted. The domain positions are a prediction, not a fit. The fact that observed slope reversals in rotation curves align systematically with these pre-computed boundaries is not a coincidence; it is what the invariant claims to explain.

The same constant that governs a photon's internal oscillation also governs the coherence scale of a rotating disk tens of kiloparsecs across. This scale invariance — from quantum to galactic — is a central claim of SCG.

How the Pipeline Works

The processing pipeline applies the γ_cause domain spacing law to each galaxy in the SPARC sample and reads the local velocity structure within each pre-defined domain. No global optimization is performed. The sequence for each galaxy is:

  1. Compute domain boundaries from Δri = γ_cause · √ri, starting at the galaxy's innermost observed radius. Boundaries are fixed before any velocity data is examined.
  2. Extract local slope Bi within each domain via least-squares regression on log(r) vs. log(v). Bi is a diagnostic — it describes the curvature of the density field in that domain. It is read, not fitted.
  3. Anchor the amplitude locally at the domain's median-radius data point: Ai = v* / r*(1−Bi)/2. No global scaling constant is introduced.
  4. Compute per-domain RMSD between the predicted and observed velocities. Domains with fewer than 3 data points are flagged as under-sampled and excluded from statistics.

Validity filter — and why some galaxies drop out

A galaxy's global RMSD is only interpreted as meaningful when the validity ratio v/N ≥ 0.50 and the total domain count N ≥ 4. Galaxies that fall below this threshold are not failures of the model — they are failures of the observation to resolve the causal structure. The γ_cause spacing law partitions a galaxy into domains whose width grows as √r. In a sparsely sampled galaxy, many domains contain fewer than three data points, which is insufficient to establish a reliable local slope Bi. The invariant still predicts where the boundaries are; the data simply doesn't exist to characterize what happens inside them. Those galaxies are marked — in the table and await denser HI observations rather than a different model.

Why a Single Curve Is the Wrong Question

The conventional approach to galactic rotation curve fitting draws one smooth function across the entire disk and minimizes the residuals globally. This seems natural — but it rests on an assumption the data do not support: that a galaxy is a single, geometrically uniform system from center to edge.

SCG says otherwise. Each causal domain is a geometrically distinct region of the galaxy — a zone in which the scalar density field has its own local curvature character, its own exponent Bi, its own kinematic identity. The domain boundaries at Δri = γ_cause · √ri are not arbitrary breakpoints chosen to improve a fit. They are where the causal field undergoes a geometric closure — where one coherence scale ends and the next begins. Crossing a domain boundary means entering physically distinct territory.

Fitting a single curve across causally separate domains is therefore not merely imprecise — it is categorically the wrong thing to do. It is like measuring the slope of a road that bends several times and reporting a single average gradient. You will get a number, but it describes the average of turns you refused to acknowledge, not the road itself. The residuals of such a fit are not noise. They are the geometry you flattened out.

This is why the SCG pipeline treats each domain independently. Bi is read locally within each pre-defined region. The amplitude is anchored locally. The RMSD is computed per domain. The galaxy is not forced into a single geometric identity it does not possess. It is allowed to be — as it actually is — a succession of distinct causal regimes, each described by the same invariant law operating at a different local curvature.

Two Galaxies, One Lesson

The most important insight from applying the γ_cause pipeline at scale is this: high RMSD does not mean the model failed. It means the galaxy experienced something. The invariant faithfully describes systems in causal equilibrium. When a galaxy has been disturbed — by a merger, a tidal interaction, a disk warp — its velocity field carries the memory of that event, and the RMSD reads it.

Two galaxies illustrate this precisely. Both have 100% valid domains — the data is dense and well-sampled in both cases. The difference is not in the measurement. It is in the history of the galaxy itself.

DDO 161 In Equilibrium
DDO 161 SCG domain fit
0.62 km/s RMSD
6 / 6 Valid domains
1.00 Validity ratio
12.8 kpc Radial span

A late-type dwarf irregular, geometrically simple and kinematically quiet. All six γ_cause domains are fully sampled. The predicted boundaries align with the observed slope transitions, and the velocity curve follows the causal geometry without deviation. This is what equilibrium looks like.

NGC 4013 Historical Disturbance
NGC 4013 SCG domain fit
3.74 km/s RMSD
6 / 6 Valid domains
1.00 Validity ratio
25.5 kpc Radial span

NGC 4013 is a well-documented warped-disk galaxy. Its outer disk has been displaced from the plane, almost certainly by a past tidal interaction. All six domains are fully sampled — the data quality is excellent. The elevated RMSD reflects a characteristic V-shaped velocity dip at 14–16 kpc that no smooth causal-density field can follow, because the disk itself is no longer in equilibrium. The γ_cause boundaries are correctly placed. The galaxy is not.

The contrast is the point. Both galaxies have identical data quality by the validity filter. The difference between RMSD = 0.62 and RMSD = 3.74 is not a modeling artifact — it is a record of galactic history. The SCG pipeline does not just fit rotation curves. It classifies them: systems in causal equilibrium versus systems that have been disturbed and are still carrying the signature of that disturbance in their kinematics.

This gives RMSD a second meaning in the SCG context. It is not only a goodness-of-fit statistic. It is a kinematic disturbance index. Galaxies with elevated RMSD and high validity ratios are candidates for morphological follow-up — warped disks, recent mergers, tidal interactions. The geometry points the way.

Global Results: 145 Galaxies

The central result is the alignment of pre-computed domain boundaries with observed kinematic transitions across all 145 galaxies. These boundaries are placed by the causal spacing law Δri = γcause√ri before any velocity data is consulted. The fact that observed slope reversals fall systematically at these pre-computed radii — across galaxies spanning four orders of magnitude in baryonic mass — is the primary claim of this framework.

Within each domain, the locally reconstructed velocity profiles achieve a median root-mean-square deviation of 1.06 km/s and a mean of 1.73 km/s. These low residuals confirm that the predicted boundaries correctly identified the natural kinematic structure of each galaxy. They are not a claim of fitting power — they are the answer to: did the boundaries work?

Statistic Value Units
Boundary prediction accuracySystematic alignment with observed slope reversals across all 145 galaxies
Median RMSD1.06km/s
Mean RMSD1.73km/s
Std. deviation2.17km/s
Galaxies with RMSD > 5 km/s4.1%of sample
Avg. valid domains per galaxy6.8
Free parameters0

Comparison with other approaches

Note: The table below compares RMSD values across frameworks for context only. Dark matter and MOND models make forward dynamical predictions with globally constrained parameters. SCG places domain boundaries before any velocity data is consulted and reads local geometry within those boundaries. These are different operations and RMSD values are not directly comparable across them. The unique claim of SCG — that kinematic transition locations are predicted by γcause alone — has no equivalent in any other framework listed here.

Study / Model Predicts boundary locations? Typical RMSD (km/s) Free parameters
McGaugh et al. (2016, 2020) No 6–13 1–2 per galaxy
Li et al. (2018) No ~13 3–5 per galaxy
NFW / Burkert / MOND No 6–15 2–4 per galaxy
D. J. Hallman — SCG γcause (2025) Yes — from γcause alone median 1.06 0

The correlation between RMSD and domain count is slightly positive (r = +0.25), confirming that the per-domain amplitude anchoring does not artificially reduce residuals. If local normalization were driving the fit quality, the correlation would be strongly negative. More complex galaxies produce slightly higher residuals — exactly what a genuine geometric model predicts.

Click any row's View link to display the SCG domain reconstruction for that galaxy. Sort by any column. Use the filter buttons to focus on specific populations.

✓ Equilibrium (RMSD < 2.5, v/N ≥ 0.5, N ≥ 4) ~ Mild disturbance (2.5–5.0) ⚠ Significant disturbance (> 5.0) — Below validity threshold
Galaxy ↕ Domains ↕ Valid ↕ v/N ↕ Span kpc ↕ RMSD ↕ Status Plot
CamB221.001.60.19View
D512-2200.002.9View
D564-8310.332.60.12View
D631-7430.756.70.91View
DDO064331.002.92.26View
DDO154430.755.40.44View
DDO161661.0012.80.62View
DDO168331.003.71.25View
DDO170410.2510.50.56View
ESO079-G014720.2916.32.43View
ESO116-G012520.409.61.96View
ESO444-G084410.254.20.52View
ESO563-G0211170.6442.02.88~View
F561-1400.008.1View
F563-1740.5719.02.83~View
F563-V1400.006.6View
F563-V2610.1710.20.65View
F565-V2400.007.5View
F567-2400.007.7View
F568-1610.1712.80.15View
F568-3720.2917.32.12View
F568-V1730.4317.20.48View
F571-8710.1415.31.06View
F571-V1500.0011.6View
F574-1630.5012.10.22View
F574-2400.008.7View
F579-V1720.2914.70.59View
F583-1740.5716.02.22View
F583-4510.207.12.35View
IC2574551.009.42.16View
IC4202860.7525.14.13~View
KK98-251331.002.90.36View
NGC0024630.5011.12.58~View
NGC0055551.0012.30.80View
NGC0100540.809.40.59View
NGC0247650.8313.50.76View
NGC02891350.3869.63.73View
NGC0300551.0010.91.92View
NGC08011210.0858.618.41View
NGC0891640.6716.21.89View
NGC1003870.8829.01.43View
NGC10901040.4029.73.23View
NGC1705430.755.80.38View
NGC2366441.005.90.79View
NGC2403881.0020.73.21~View
NGC2683800.0031.7View
NGC284111100.9160.22.89~View
NGC2903980.8924.67.40View
NGC2915551.009.72.70~View
NGC29551030.3034.78.67View
NGC2976320.672.23.25View
NGC29981100.0042.0View
NGC3109441.006.20.91View
NGC31981290.7543.82.10View
NGC3521740.5717.24.86~View
NGC3726720.2929.00.89View
NGC3741540.806.81.05View
NGC3769900.0035.4View
NGC3877520.4010.50.53View
NGC3893600.0017.3View
NGC3917630.5014.00.98View
NGC3949310.335.30.09View
NGC3953410.2512.20.81View
NGC3972410.257.82.30View
NGC3992700.0036.8View
NGC4010510.209.64.10View
NGC4013661.0025.53.74~View
NGC4051500.0010.4View
NGC4068310.332.10.71View
NGC4085400.005.3View
NGC4088710.1419.70.18View
NGC4100661.0020.12.59~View
NGC4138500.0016.0View
NGC4157830.3827.90.84View
NGC4183740.5720.10.94View
NGC4214441.005.40.44View
NGC4217630.5015.81.55View
NGC4389300.004.5View
NGC4559850.6220.30.61View
NGC5005640.6711.02.80~View
NGC50331130.2743.81.61View
NGC50551240.3353.91.59View
NGC53711110.0944.82.72View
NGC5585650.8310.92.15View
NGC5907930.3345.31.32View
NGC5985860.7531.23.62~View
NGC6015980.8928.93.00~View
NGC6195940.4435.13.09View
NGC6503860.7522.71.32View
NGC66741300.0069.9View
NGC6789111.000.60.79View
NGC6946881.0020.22.45View
NGC7331881.0033.62.15View
NGC7793551.007.87.04View
NGC7814730.4318.90.45View
PGC51017300.003.3View
UGC001281230.2552.52.16View
UGC00191510.209.42.85View
UGC00634400.0013.5View
UGC00731510.2010.00.83View
UGC00891300.005.9View
UGC012301000.0035.8View
UGC01281441.004.90.86View
UGC02023300.003.0View
UGC02259400.007.1View
UGC02455320.673.50.72View
UGC024871110.0970.40.23View
UGC028851310.0872.40.00View
UGC029161160.5537.60.70View
UGC0295314130.9362.31.16View
UGC032051160.5539.81.03View
UGC03546960.6728.61.42View
UGC03580970.7826.91.98View
UGC04278540.806.61.97View
UGC04305441.005.31.49View
UGC04325410.254.90.08View
UGC04483210.501.12.52View
UGC04499410.257.30.24View
UGC05005900.0027.8View
UGC052531380.6253.20.43View
UGC05414300.003.4View
UGC05716530.6011.30.59View
UGC05721540.806.74.01~View
UGC05750810.1222.50.27View
UGC05764331.003.31.20View
UGC05829420.506.30.74View
UGC05918320.673.90.36View
UGC05986540.808.81.06View
UGC05999400.0012.7View
UGC06399410.257.00.28View
UGC06446540.809.60.69View
UGC066141220.1761.40.41View
UGC06628410.256.60.33View
UGC06667410.257.00.08View
UGC067861080.8033.91.84View
UGC0678711100.9137.111.11View
UGC06818400.006.1View
UGC06917430.758.71.35View
UGC06923300.004.2View
UGC06930610.1714.90.38View
UGC06973320.676.10.45View
UGC06983540.8013.91.68View
UGC07089510.208.32.03View
UGC07125620.3317.20.33View
UGC07151420.505.00.55View
UGC07232111.000.60.49View
UGC07261400.005.7View
UGC07323420.505.21.15View
UGC07399420.505.50.75View
UGC07524650.8310.30.98View
UGC07559221.002.20.49View
UGC07577221.001.50.22View
UGC07603331.003.81.27View
UGC07608320.674.20.31View
UGC07690310.333.50.25View
UGC07866221.002.00.52View
UGC08286530.607.61.14View
UGC08490551.009.80.61View
UGC08550420.504.90.41View
UGC08699970.7825.51.49View
UGC08837320.673.70.56View
UGC09037750.7125.54.31~View
UGC0913318130.72108.00.49View
UGC09992300.003.1View
UGC10310410.256.60.02View
UGC114551180.7341.35.52View
UGC11557610.1710.20.40View
UGC11820710.1415.63.52View
UGC11914551.009.62.02View
UGC125061260.5049.23.11~View
UGC12632530.609.90.42View
UGC12732630.5014.40.65View
UGCA281210.501.02.57View
UGCA442410.255.91.10View
UGCA444331.002.51.12View

Pipeline Code (Python)

The complete pipeline. Domain boundaries are computed from γ_cause before any velocity data is examined. The local slope Bi is read, not fitted. No global optimization is performed.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pathlib import Path

# === CONFIG ===
gamma_cause = 1.216
skiprows = 3
colnames = ["r_kpc", "Vobs", "errV", "Vgas", "Vdisk", "Vbul", "SBdisk", "SBbul"]
out_dir = Path("gamma_cause_results")
out_dir.mkdir(exist_ok=True)

def load_rotation_file(filepath):
    df = pd.read_csv(filepath, delim_whitespace=True, comment="#",
                     skiprows=skiprows, names=colnames)
    return df[["r_kpc", "Vobs"]].dropna().sort_values("r_kpc")

def compute_domain_edges(r_min, r_max, gamma=gamma_cause):
    """
    Pre-compute domain boundaries from the causal spacing law:
        Δr_i = γ_cause · √r_i
    Boundaries are fixed before any velocity data is consulted.
    """
    edges = [r_min]
    r = r_min
    while r < r_max:
        dr = gamma * np.sqrt(max(r, 0.5))
        r += dr
        edges.append(r)
    return edges

def compute_Bs(df, edges):
    """
    Read the local causal-density exponent B_i within each pre-defined domain.
    B_i = 1 - 2·(d ln v / d ln r)  — diagnostic, not fitted.
    """
    rows = []
    for i in range(len(edges)-1):
        r_lo, r_hi = edges[i], edges[i+1]
        dom = df[(df["r_kpc"] >= r_lo) & (df["r_kpc"] <= r_hi)]
        if len(dom) < 2:
            B = np.nan
        else:
            m, _ = np.polyfit(np.log(dom["r_kpc"]), np.log(dom["Vobs"]), 1)
            B = 1 - 2 * m
        rows.append({"i": i, "r_lo": r_lo, "r_hi": r_hi, "B": B, "n": len(dom)})
    return pd.DataFrame(rows)

def rmsd(obs, model):
    return np.sqrt(np.nanmean((obs - model) ** 2))

# --- main loop ---
summary_rows = []

for file in Path("./SPARC_Data").glob("*.dat"):
    name = file.stem.split("_rotmod")[0]
    try:
        df = load_rotation_file(file)
        edges = compute_domain_edges(df["r_kpc"].min(), df["r_kpc"].max())
        Bdf = compute_Bs(df, edges)
        v_pred_all, v_obs_all = [], []
        valid_domains = 0

        fig, ax = plt.subplots(figsize=(9, 6))
        ax.scatter(df["r_kpc"], df["Vobs"], s=35, color="tab:blue",
                   label="Observed velocity")
        for r_edge in edges:
            if r_edge <= df["r_kpc"].max():
                ax.axvline(r_edge, color="gray", linestyle="--", alpha=0.6)

        for _, row in Bdf.iterrows():
            if np.isnan(row["B"]) or row["n"] < 3:
                continue
            valid_domains += 1
            r_lo, r_hi, B = row["r_lo"], row["r_hi"], row["B"]
            dom = df[(df["r_kpc"] >= r_lo) & (df["r_kpc"] <= r_hi)]
            # Amplitude anchored at median-radius data point — no global fitting
            anchor = dom.iloc[len(dom) // 2]
            r_star, v_star = anchor["r_kpc"], anchor["Vobs"]
            p = (1 - B) / 2
            if r_star <= 0:
                continue
            A_i = v_star / (r_star ** p)
            r_s = np.linspace(r_lo, r_hi, 200)
            v_s = A_i * (r_s ** p)
            ax.plot(r_s, v_s, color="red", alpha=0.6, lw=1.5)
            v_model_interp = np.interp(dom["r_kpc"], r_s, v_s)
            v_pred_all.extend(v_model_interp)
            v_obs_all.extend(dom["Vobs"])

        galaxy_rmsd = (rmsd(np.array(v_obs_all), np.array(v_pred_all))
                       if len(v_obs_all) > 0 else np.nan)

        ax.set_xlabel("Radius (kpc)")
        ax.set_ylabel("Velocity (km/s)")
        ax.set_title(f"{name}: empirical vs SCG per-domain fits\n"
                     f"RMSD = {galaxy_rmsd:.2f} km/s  |  "
                     f"{valid_domains}/{len(Bdf)} valid domains")
        ax.legend()
        fig.tight_layout()
        fig.savefig(out_dir / f"{name}_with_SCG_domains.png", dpi=200)
        plt.close(fig)

        summary_rows.append({
            "galaxy": name,
            "n_domains_total": len(Bdf),
            "n_domains_valid": valid_domains,
            "r_min": df["r_kpc"].min(),
            "r_max": df["r_kpc"].max(),
            "r_span": df["r_kpc"].max() - df["r_kpc"].min(),
            "RMSD_kms": galaxy_rmsd
        })

        print(f"✅ {name}: RMSD={galaxy_rmsd:.2f} km/s  "
              f"({valid_domains}/{len(Bdf)} valid domains)")

    except Exception as e:
        print(f"⚠️  {name}: failed ({e})")

summary_df = pd.DataFrame(summary_rows)
summary_df.to_csv("SCG_summary.csv", index=False)
print(f"\n📊 Summary saved to SCG_summary.csv")

References

Zwicky, F. (1933). Die Rotverschiebung von extragalaktischen Nebeln. Helvetica Physica Acta 6, 110.

Rubin, V. C. & Ford, W. K. (1970). Rotation of the Andromeda Nebula from a Spectroscopic Survey of Emission Regions. Astrophysical Journal 159, 379.

Lelli, F., McGaugh, S. S., & Schombert, J. M. (2016). SPARC: 175 Disk Galaxies with Spitzer Photometry and HI Kinematics. AJ 152, 157. DOI: 10.3847/0004-6256/152/6/157 · SPARC database

McGaugh, S. S., Lelli, F., & Schombert, J. M. (2016). The Radial Acceleration Relation in Rotationally Supported Galaxies. Phys. Rev. Lett. 117, 201101.

Li, P. et al. (2018). Fitting the Radial Acceleration Relation to Individual SPARC Galaxies. AJ 157, 202.

Hallman, D. J. (2025). Galactic Rotation Curves Without Dark Matter Using SCG and the γ_cause Invariant. Zenodo. DOI: 10.5281/zenodo.17507056

Hallman, D. J. (2025). γ_cause — A Fundamental Ratio Governing Transverse Electromagnetic Oscillations. Zenodo. DOI: 10.5281/zenodo.15567483

Hallman, D. J. (2025). Recovering Conventional Spacetime Metrics as a Limiting Case of SCG. Zenodo. DOI: 10.5281/zenodo.17467892

SCG Project: dhallman.com