Skip to main content
Sandbox Physics
Galaxy rotation curves and mass models

Galaxy rotation curves · L3

Recompute a named SPARC galaxy from saved observations

First run the complete saved-data analysis on our synthetic observations. Then acquire the fixed NGC 2403 files on your own computer and repeat the calculation. Every optimum is computed from a saved observation; the public package contains no original SPARC rows.

Unpack the independent scientific materials

Download the scientific ZIP, compare its SHA-256, extract into a new directory and open a terminal there. The README records the actual tested environment: Python 3.9.6, NumPy 2.0.2 and SciPy 1.13.1. Record your own compatible versions too; final optimizer digits can change.

The package contains independent Python, own synthetic input, units and source identities. Its default workflow has no network access. It excludes the browser Engine, original papers, SPARC observations and measured-derived plots. Begin with the fully offline calculation below.

Reading: Independent saved-observation rotation-curve calculation

Save the observation before starting the fitter

The first command generates 48 radii from thin exponential stellar/gas disks and a prescribed NFW field, adds the declared random noise and writes JSON. The generator reports its injection for provenance. The saved observation passed to the fitter has no injection parameters.

The second command opens that file and fits its observed speeds, errors and component columns. It does not read the generator’s truth. The NFW conditional optimum has mass-to-light ratio near 0.6070.607, rather than the injected 0.550.55: noise has moved the optimum.

Each halo receives six starting points. Every stop status, objective value and function-evaluation count is saved. Several synthetic cored fits stop near χ2=167.54\chi^2=167.54, while another reaches 126.43126.43. Both satisfy stopping conditions, so their actual objective values still need comparison.

python science/generate_observation.py --output results/own-observation.json
python science/analyze.py --input results/own-observation.json --output results/own-analysis

Reading: Independent saved-observation rotation-curve calculation

Recompute checks and figures from those saved results

The validator recalculates positive-density halo integrals, an independent ring-potential thin-disk reference, numerical distance/inclination derivatives and both likelihood-coordinate Jacobians. It also recomputes every saved predicted field and checks that the fit refers to the same input.

The output retains wrong-algorithm controls: treating the exponential disk as a sphere, subtracting nearly equal floating-point numbers and averaging a common error as though it were independent. Correct-method tolerances and failed controls are reported separately.

The plotter reads the saved observation and analysis to draw total speed, components, errors and conditional profiles. The published examples use our own synthetic data. Its poorer cored fit is a deliberate model-mismatch control for an NFW-generated fixture, not a test of real galaxies.

Own synthetic speeds with errors and a newly fitted NFW component decomposition
Own48-point synthetic observation. Independent Python fits the saved speeds, errors and component basis; points and curves are not a measured galaxy image. Equivalent component speeds encode forces whose signed squares add. Open the full figure
python science/validate.py --input results/own-observation.json --analysis results/own-analysis --output results/own-validation.json
python science/plot.py --input results/own-observation.json --analysis results/own-analysis --output results/own-figures

Reading: Independent saved-observation rotation-curve calculation

Acquire only the two fixed upstream products

The explicit online command below reads the official SPARC Table 1 and small Rotmod archive, a total of 138,996 body bytes. Exact sizes, SHA-256 and member CRC must pass before it extracts only NGC 2403. The other 174 members remain unextracted and unused. A changed identity stops acquisition without an automatic retry or mirror.

The author actually obtained both 200 responses into an empty directory on 5 November 2026. That fresh-acquisition receipt is separate from the subsequent offline cold-package replay. Future availability is established only by the reader’s own requests.

The fixed Table 1 body is 28,259 bytes and the archive 110,737 bytes. Complete hashes are in the package’s source metadata and downloader. The public material supplies the acquisition procedure; original products remain on the reader’s computer.

python science/fetch_named_source.py --online --http-budget-bytes 138996 --output local-sparc

Reading: Lelli, McGaugh & Schombert (2016), SPARC, AJ152,157 · Independent saved-observation rotation-curve calculation

Convert native columns into a traceable saved observation

NGC 2403 is the fixed quality 1, zero-bulge selection. Table 1 supplies D0=3.16±0.16 MpcD_0=3.16\pm0.16\,\mathrm{Mpc} and i0=63∘±3∘i_0=63^{\circ}\pm3^{\circ}. The native component file has 7373 radii. Conversion checks hashes, the named 19-field metadata row and the no-bulge conditions before saving the observation.

The eight columns are radius, observed circular speed, speed error, gas equivalent speed, unit-ratio stellar speed, bulge speed, disk surface brightness and bulge surface brightness. Radii are in kiloparsecs; speeds are kilometres per second. The native error excludes inclination systematics and is not a complete covariance matrix.

A negative gas column marks the radial-force direction. Stellar columns retain the native finite-thickness model. This processed rotation-curve record is not the original two-dimensional velocity field; the procedure does not remeasure warps, noncircular motions or photometric deprojection.

python science/save_native.py --source local-sparc --output results/native-observation.json

Reading: Lelli, McGaugh & Schombert (2016), SPARC, AJ152,157 · Independent saved-observation rotation-curve calculation

Run the same optimizer and shared-geometry scenarios

The same analysis reads the saved real observation. Bounds are 0.05–1.5 for stellar mass-to-light ratio, 1000–10 billion solar masses per cubic kiloparsec for halo density, and 0.05–200 kiloparsecs for scale radius. This offline search is wider than the interactive demonstration, and those bounds remain part of the analysis.

Ten fixed stellar ratios each receive a new halo optimization. The nine common-geometry scenarios combine central and plus/minus one metadata-error distance and inclination. Every scenario is refitted. These are sensitivity calculations, not posterior samples or an assumed measured joint prior.

This actual rerun gives NFW stellar ratio about 0.2880.288 and scale 7.147 kpc7.147\,\mathrm{kpc}; the cored solution gives about 0.7580.758 and 3.029 kpc3.029\,\mathrm{kpc}. Working reduced chi-square values are 9.1389.138 and 10.69610.696. Both descriptions are poor at the supplied point-error weights. No selected point or original error is altered.

python science/analyze.py --input results/native-observation.json --output results/native-analysis
python science/validate.py --input results/native-observation.json --analysis results/native-analysis --output results/native-validation.json

Reading: Independent saved-observation rotation-curve calculation · Lelli, McGaugh & Schombert (2016), SPARC, AJ152,157

Generate measured-derived figures locally

The explicit option below acknowledges that the output contains local measured-derived figures. Use them on your computer to inspect radial residuals, parameter boundaries and coherent departures. Figures published with these chapters continue to use own synthetic observations.

Early development retained three failures: fixed-byte metadata slicing disagreed with the actual whitespace layout; NumPy booleans failed JSON serialization; and small-core subtraction plus a likelihood-coordinate auditor missed their original numerical gates. Corrected parsing/equivalent arithmetic and the earlier failures are documented separately. The package recomputes mathematical negative controls; a clean exit is not a certificate of every physical inference.

python science/plot.py --allow-local-observations --input results/native-observation.json --analysis results/native-analysis --output results/local-measured-figures

Reading: Independent saved-observation rotation-curve calculation

Carry the checks to the next dataset

Record source identities and selection first. Check column units and signs, save observations, then fit. Compare starts and bounds; handle common geometry separately from point errors. Finally read the residuals alongside the physical and error assumptions that produced the score.

This workflow actually recalculates the fixed object’s conditional mass models. It supplies no particle identification, calibrated probability interval or complete original-velocity-field analysis. The next guide uses these habits to examine a newer paper’s changes of observations, assumptions and model comparisons.

Reading: Independent saved-observation rotation-curve calculation · Lelli, McGaugh & Schombert (2016), SPARC, AJ152,157

Exercises and explained answers

  1. Why save the synthetic observation and launch a separate fitter instead of passing the generator’s parameters directly?

    Read the explanation

    The fit then receives the actual saved speeds and errors, without injection parameters. File hashes, repeat analyses and starting-point comparisons become inspectable. The validator also inserts an unusable extra truth field and confirms that fitting ignores it.

  2. How can you test acquisition/conversion with no network if you already hold the exact upstream bodies?

    Read the explanation

    Use the downloader’s --from-cache option with the verified source directory and a fresh output directory. Hash and CRC checks still run, followed by saving and analysis. This proves cache replay; a fresh download requires a separate actual network receipt.

  3. May the two large real-object scores be fixed by inflating errors until reduced chi-square approaches one?

    Read the explanation

    That changes the statistical question and needs an independently justified error model. Preserve the present mismatch first, then examine residuals, geometry sensitivity and missing physics. Adjusting errors only to improve the displayed score would conceal the original discrepancy.

Try the prediction

Compare the stellar disk and conditional halo

  1. Export the own synthetic default’s observations and forward prediction.
  2. Compare source identities, units and the full likelihood with the currently accepted model.
  3. For a local fixed-file import, distinguish the manual forward comparison from this offline six-start fit and inspect residuals in your own output directory.

Standalone scientific materials

Download the scientific ZIP · Read setup and calculation scope

The offline calculation needs Python, NumPy and SciPy. Default synthetic data are fully generated and fitted. Optional named SPARC files are fetched only on your computer; the ZIP has no original rows or browser Engine.

Individual scripts, sizes and SHA-256
  • README.md (6785 B)
    5fbf0d29e006fc06f35d2290fd8fee7d5abc2301b601814165495331f9c37a84
  • LICENSE.txt (1325 B)
    4f15facc82fd0218a74907ae83f1716569277d9c40f55b249451dd8d89191b2f
  • requirements.txt (185 B)
    359f4c650ca6dd5a2705535e32377aa86db27d8d6ebd9b47333070850b9c5980
  • source-identities.json (724 B)
    409cf4931c19dc97049f943eb005165a59f88d1842a3dd2596eaa1dabcfbd458
  • own-observation.json (9009 B)
    48cd32150a8eff02b4c3e870cb82f8df008d90c2b5aed3f9bca743506852a5e1
  • analyze.py (2750 B)
    5baed281117d3980af0f0e19e428c4163f79a97a84d1db71955ecbee7993ac3a
  • conditional_fit.py (3618 B)
    37700d28edc852a10d09f949a7270a652b61f1c9d30cc2d8d0e99d4347e92d70
  • fetch_named_source.py (5014 B)
    240b29a1c6e929895b5ead31269b495b1223be0615da62c703e2962028e6de5a
  • generate_observation.py (849 B)
    c5442424f9cecdcd81022ec31cae0b81bdc21400f06eea6dde4108c7062de743
  • observation_record.py (2693 B)
    2d791013b5c8b289e6bfdc5ba9ed408e18b9fc4334d44ba32091546ed297e752
  • physical_units.py (255 B)
    2db6448e5f4e657ef48ffd9d2a58c7487c6f7655a8033dc001327fe43192507c
  • plot.py (5734 B)
    c30e8e160f1f73f6451ebb903402a316ecba858814e6b1d5059ad31926abb4e1
  • rotation_model.py (2003 B)
    97c2c5ca56373f20996b26ef179267549ad3a341817b29666ce368029cfa96a1
  • save_native.py (655 B)
    bbf0881e28cf1dd4d13105af656cc4072e3a42a62a5f7013b9f48075b764c082
  • spherical_halos.py (1459 B)
    4678e06bf172167f3a8a3a5d199447658eb51860507405b80110807165c5ef83
  • synthetic_record.py (1538 B)
    6285cda07f2b9324806d25ecc89712eb6b94479e3caaa1f24a88c004d449a063
  • thin_disk_reference.py (1298 B)
    67ba0512e47c10d10c5b8d17f435d808812eec25f0edce296b6c80eaf72e0bc0
  • validate.py (5709 B)
    7cfbf116c5e51e9a3e1aa0ecd113a24f7a069706336ae01221de67dbf331cb6d
  • verify_analytic_limits.py (3073 B)
    68bca45f2d3d8a1f8cda804bb45c3e165025effa0221c2f45d7c1416009bae6a
  • verify_nuisance_mapping.py (4184 B)
    04b8587eb21a257b809fe930c33d43ddb2e008e4ebf2026134ee0a1d35b4015e
  • SHA256SUMS.json (3306 B)
    2fb52c937f2026d872f053e17343e55595fb3568862c20573d59123f3d897b49
  • galaxy-rotation-science-v1.zip (29081 B)
    f389268ed651be3a66ad7d87ee6760ebe39d87f6bd2498b2fb8904c9f10893a3

Sources and calculation scope

  1. Lelli, McGaugh & Schombert (2016), SPARC, AJ152,157

    Official fixed Table1 and Rotmod_LTG.zip; named NGC2403 member only. The master paper sections3.1–3.3/5.1–5.3 and original Table2 notes establish signed gas, unit stellar mass-to-light, finite thickness and error meaning. Fresh source acquisition is separate from cached replay. Original rows and measured-derived plots stay local.

  2. Independent saved-observation rotation-curve calculation

    Own MIT Python produces synthetic observations, actual six-start fits, profiles, commonD/i scenarios, positive-density/ring-potential/Jacobian references and SVGs. Optional exact named-source acquisition and73-row conversion/fits were actually run. Default is offline; ZIP contains no App Engine, original SPARC rows, paper or measured-derived graph.

FeedbackSomething broken, confusing, or missing on this page?Tell us
What kind of feedback?

Sent with this page’s address, its Lab ID, the site language and your device type. Please leave out personal details. Feedback is kept for up to 12 months.Privacy policy