{ "cells": [ { "cell_type": "markdown", "id": "1e78bea2", "metadata": {}, "source": [ "# 1. Units and conventions\n", "\n", "Before defining a model, put observations and physical parameters in the\n", "units expected by JeansPy. Arrays contain plain numerical values: the model\n", "does not infer a unit from an array or convert an Astropy quantity for you.\n", "\n", "\n", "This notebook is self-contained. Install JeansPy with the `numpyro_cpu` and\n", "`plotting` extras as described in the installation guide, then select that\n", "environment as your Jupyter kernel and run cells from top to bottom.\n", "Saved outputs are an example run; timings and short-chain results can vary.\n", "\n", "## Prepare observations\n", "\n", "For spherical inference, each row represents a star. `R_pc` is the projected\n", "distance from the galaxy center, not its three-dimensional radius. Supply\n", "the measured LOS velocity and its standard error in the same velocity frame." ] }, { "cell_type": "code", "execution_count": 1, "id": "e8c5a4b7", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
R_pcvlos_kmse_vlos_kms
030.0-4.02.0
1100.02.02.0
2300.08.01.5
\n", "
" ], "text/plain": [ " R_pc vlos_kms e_vlos_kms\n", "0 30.0 -4.0 2.0\n", "1 100.0 2.0 2.0\n", "2 300.0 8.0 1.5" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", "\n", "data = dict(\n", " R_pc=np.array([30., 100., 300.]),\n", " vlos_kms=np.array([-4., 2., 8.]),\n", " e_vlos_kms=np.array([2., 2., 1.5]),\n", ")\n", "assert all(value.shape == (3,) for value in data.values())\n", "assert np.all(data[\"R_pc\"] > 0) and np.all(data[\"e_vlos_kms\"] >= 0)\n", "import pandas as pd\n", "pd.DataFrame(data)" ] }, { "cell_type": "markdown", "id": "1cbbafcf", "metadata": {}, "source": [ "The arrays must be finite, nonempty, one-dimensional and have identical lengths;\n", "errors must be nonnegative. Convert angular separations to projected pc using\n", "the adopted galaxy distance before building this dictionary. That distance\n", "and the coordinate origin are inputs to your analysis.\n", "\n", "## Read parameter names and returned quantities\n", "\n", "| Quantity | Meaning and units |\n", "| --- | --- |\n", "| `R_pc`, `r_pc` | Projected and intrinsic radius, respectively, in pc |\n", "| `re_pc`, `rs_pc`, `r_t_pc` | Tracer scale, halo scale and halo cutoff in pc |\n", "| `rhos_Msunpc3` | Halo mass density scale in solar masses / pc³ |\n", "| `vmem_kms`, `vlos_kms`, `e_vlos_kms` | Systemic velocity, observation and standard error in km/s |\n", "| `sigmalos2` | Intrinsic LOS variance in (km/s)² |\n", "| `density_2d`, `density_3d` on a normalized tracer | Number density in pc⁻² and pc⁻³ |\n", "| `mass_density_3d`, `enclosed_mass` on a halo | Mass density in solar masses / pc³ and mass in solar masses |\n", "\n", "For the Plummer tracer, `re_pc` is the projected half-light radius. Other\n", "profiles can use a different scale convention: in particular `Exp3dModel`\n", "uses an exponential scale length. Check the selected class's API entry.\n", "\n", "A unit-normalized tracer supplies the spatial weighting of the stars. It\n", "does **not** add stellar mass to the gravitational potential. The halo provides\n", "the enclosed mass used by the spherical solver.\n", "\n", "## Respect geometry and array shapes\n", "\n", "Spherical LOS predictions require finite **positive** radii; the central limit\n", "at `R_pc=0` is not implemented. NumPy returns a scalar for a scalar radius and\n", "a one-dimensional array for an array. JAX always returns a one-dimensional\n", "array, including a length-one array for a scalar radius.\n", "\n", "Axisymmetric models instead take signed sky coordinates `x_pc`, `y_pc`, allow\n", "the projected center and broadcast the coordinate arrays. Inclination is in\n", "radians. Spherical $\\beta=1-\\sigma_\\theta^2/\\sigma_r^2$ and cylindrical\n", "$\\beta_z=1-\\sigma_z^2/\\sigma_R^2$ describe different tensors; substituting one\n", "for the other changes the model.\n", "\n", "## Separate physical validity from numerical success\n", "\n", "An invalid NumPy input can raise an exception; invalid dynamic JAX values can\n", "produce NaN and be rejected by the likelihood. A finite prediction alone does\n", "not establish that a nonnegative phase-space distribution exists. Likewise,\n", "doubling quadrature resolution checks numerical stability, while sampler\n", "diagnostics assess sampling. Neither alone validates the physical model.\n", "\n", "The [model contract](../guides/contracts.md) collects the full shape, geometry\n", "and error conventions. Next: [choose a backend](backends.ipynb)." ] } ], "metadata": { "jeanspy": { "execution": { "code_sha256": "bd1f6836687f459c22f3701b5524a72e9826e603094914150e7458f9b19a7414", "jax_enable_x64": true, "lock_sha256": "a30f366620e23a49d6d7466055223a761824454169d8fc0364c24ac25b626dc7", "packages": { "arviz": "1.0.0", "corner": "2.2.3", "jax": "0.9.1", "jeanspy": "0.1.0", "matplotlib": "3.10.8", "numpy": "2.4.3", "numpyro": "0.20.0", "scipy": "1.17.1" }, "platform": "cpu", "source_sha256": { "src/jeanspy/__init__.py": "61671d182af04c0056cfb8d273db499d8774694711506698dbe7dc4a63d3b403", "src/jeanspy/_axisymmetric_components.py": "4b203c616c87e55182d105b37f9fa49e44fe1df6bc430ccccb09edc5cca42530", "src/jeanspy/_axisymmetric_params.py": "85da8de45bf5ba8cd9a40a137f7ccf971f7ce9534f312ef49fcd33539a230802", "src/jeanspy/_jax_env.py": "2ef46eaf5cbd8e72a0c17351490207c29586979082cabc87128c9bd16fc689a4", "src/jeanspy/_numpy/__init__.py": "de2d19d61e00702f13996582369f6acbe92b74628e6f569f91c3215a53580117", "src/jeanspy/_numpy/core.py": "d073c6409d5f8cf527947c1ddf3916cb39cef3f6d4e43173cad59d148e463296", "src/jeanspy/_numpy/inference.py": "ab58728400b6e56189ffba9ee805d9edbf59ca13dfebe05498801592314552db", "src/jeanspy/_numpy/jfactor.py": "823f58a66a615ba59e057022ce51e2adfab577c25a4ced2f2033304c2cbd6cfe", "src/jeanspy/_numpy/profiles.py": "e77fda6fb068392a63f0479e4c33bf80a22de3d2ab2cd101ea0c1f33e579491d", "src/jeanspy/_numpy/solver.py": "b419796e2a912a46f65404cb5026ccb73799e1dbb8f80052f404148dd1f5ef3c", "src/jeanspy/_sampling_identity.py": "b0e70b77e38f25e2148ab1f108a714512a8b6054405c846c3a41730b07081cec", "src/jeanspy/_sersic_deprojection.py": "004c5566448698ecfe536096c3fc8d5c348a8d4e1610042763c77568c0f3d821", "src/jeanspy/_zhao.py": "df83c7427dc583123c7464a03d2d45272e90f5a6724c9729eee64fad92e0c41a", "src/jeanspy/axisymmetric.py": "683d67b91f8eb67e8d898eb23e6c8ca0e5c78020a65a7d05e183c19b076bd506", "src/jeanspy/axisymmetric_factors.py": "754b256f7d3d43cc72571cde2b22bc9419917cf13b17342cd5f52406c4111336", "src/jeanspy/axisymmetric_inference.py": "57078226b3643f8babda4d942b96ae546622da28802119d3d99ff6a0c5b45695", "src/jeanspy/axisymmetric_jax.py": "de5f78937104ce7008242d55c321c8a3c6d9491f6aa25d4be3bdab8de076ed54", "src/jeanspy/baes_eta2.py": "c274a16ca8c4b4d8d76ec30a2e705b5a5f6ce7659b31e31b5c685f92ab7a7ece", "src/jeanspy/dequad.py": "6260e7ee2d8da12265573e86ff81ba0a3e8912df5fec8588a84bfda9d3b1133d", "src/jeanspy/hyp2f1_jax.py": "03d8df3b48fcd9d418e289ea2ffaf174ffbdf14dffe483a150403c092bbaeea8", "src/jeanspy/model.py": "72af25df8f34816f27d373fdecf41408c79eb505cb4cb52c830822d5d8f12f2b", "src/jeanspy/model_jax.py": "355ba42ad16b2cadd00906679dd06ee12fd85fe4f1fc48630c779e68e4fabd64", "src/jeanspy/parameters.py": "7760f4c85063105eb1328910867f3c57516f885dc577533bf9b91ac08a648cb2", "src/jeanspy/sampler.py": "42ca0bbcef84b7c1620fd977d71810284a5d6abd70ff6047ae3175822d63f10e", "src/jeanspy/sampler_numpyro.py": "ccd367d576bc55173d85939ad4bf7eeb8a44130d693f40ee56f4eade278c2195", "src/jeanspy/sersic.py": "487f473351f9a309ad7d8dad1b1405e496196413e7606d0b0a18c5f71bfcf4a3" }, "utc": "2026-09-18T00:32:27.369759+00:00" }, "mcmc": false }, "kernelspec": { "display_name": "Python 3 (JeansPy)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.13" } }, "nbformat": 4, "nbformat_minor": 5 }