Skip to main content

Walk through phase-space observations

Project description

phasecurvefit: Construct Paths through Phase-Space Points

PyPI version Python versions

Construct paths through phase-Space points, supporting many different algorithms.

Installation

Install the core package:

pip install phasecurvefit

Or with uv:

uv add phasecurvefit
from source, using uv
uv add git+https://github.com/GalacticDynamics/phasecurvefit.git@main

You can customize the branch by replacing main with any other branch name.

building from source
cd /path/to/parent
git clone https://github.com/GalacticDynamics/phasecurvefit.git
cd phasecurvefit
uv pip install -e .  # editable mode

Optional Dependencies

phasecurvefit has optional dependencies for extended functionality:

  • unxt: Physical units support for phase-space calculations
  • tree (jaxkd): Spatial KD-tree queries for large datasets

Install with optional dependencies:

pip install phasecurvefit[interop]  # Install with unxt for unit support
pip install phasecurvefit[kdtree]  # Install with jaxkd for KD-tree strategy

Or with uv:

uv add phasecurvefit --extra interop
uv add phasecurvefit --extra kdtree

Quick Start

import jax.numpy as jnp
import phasecurvefit as pcf

# Create phase-space observations as dictionaries (Cartesian coordinates)
pos = {"x": jnp.array([0.0, 1.0, 2.0]), "y": jnp.array([0.0, 0.5, 1.0])}
vel = {"x": jnp.array([1.0, 1.0, 1.0]), "y": jnp.array([0.5, 0.5, 0.5])}

# Order the observations (use KD-tree for spatial neighbor prefiltering)
config = pcf.WalkConfig(strategy=pcf.strats.KDTree(k=2))
result = pcf.walk_local_flow(pos, vel, config=config, start_idx=0, metric_scale=1.0)
print(result.indices)  # Array([0, 1, 2], dtype=int32)

With Physical Units

When unxt is installed, you can use physical units:

import unxt as u

# Create phase-space observations with units
pos = {"x": u.Q([0.0, 1.0, 2.0], "kpc"), "y": u.Q([0.0, 0.5, 1.0], "kpc")}
vel = {"x": u.Q([1.0, 1.0, 1.0], "km/s"), "y": u.Q([0.5, 0.5, 0.5], "km/s")}

# Units are preserved throughout the calculation
metric_scale = u.Q(1.0, "kpc")
result = pcf.walk_local_flow(
    pos, vel, start_idx=0, metric_scale=metric_scale, usys=u.unitsystems.galactic
)

Features

  • JAX-powered: Fully compatible with JAX transformations (jit, vmap, grad)
  • Cartesian coordinates: Works in Cartesian coordinate space (x, y, z)
  • Physical units: Optional support via unxt for unit-aware calculations
  • Pluggable metrics: Customizable distance metrics for different physical interpretations
  • Type-safe: Comprehensive type hints with jaxtyping
  • GPU-ready: Runs on CPU, GPU, or TPU via JAX
  • Spatial KD-tree option: Use jaxkd to prefilter neighbors

Distance Metrics

The algorithm supports pluggable distance metrics to control how points are ordered. The default FullPhaseSpaceDistanceMetric uses true 6D Euclidean distance across positions and velocities:

from phasecurvefit.metrics import FullPhaseSpaceDistanceMetric
import jax.numpy as jnp

# Define simple Cartesian arrays (not quantities)
pos = {"x": jnp.array([0.0, 1.0, 2.0]), "y": jnp.array([0.0, 0.5, 1.0])}
vel = {"x": jnp.array([1.0, 1.0, 1.0]), "y": jnp.array([0.5, 0.5, 0.5])}

# Configure with full phase-space metric (the default)
config = pcf.WalkConfig(metric=FullPhaseSpaceDistanceMetric())
result = pcf.walk_local_flow(pos, vel, config=config, start_idx=0, metric_scale=1.0)

Using Different Metrics

phasecurvefit provides three built-in metrics:

  1. FullPhaseSpaceDistanceMetric (default): True 6D Euclidean distance in phase space
  2. AlignedMomentumDistanceMetric: Combines spatial distance with velocity alignment (NN+p metric)
  3. SpatialDistanceMetric: Pure spatial distance, ignoring velocity
from phasecurvefit.metrics import SpatialDistanceMetric, FullPhaseSpaceDistanceMetric
import jax.numpy as jnp

# Define simple Cartesian arrays (not quantities)
pos = {"x": jnp.array([0.0, 1.0, 2.0]), "y": jnp.array([0.0, 0.5, 1.0])}
vel = {"x": jnp.array([1.0, 1.0, 1.0]), "y": jnp.array([0.5, 0.5, 0.5])}

# Pure spatial ordering (ignores velocity)
config_spatial = pcf.WalkConfig(metric=SpatialDistanceMetric())
result = pcf.walk_local_flow(
    pos, vel, config=config_spatial, start_idx=0, metric_scale=0.0
)

# Full 6D phase-space distance
config_phase = pcf.WalkConfig(metric=FullPhaseSpaceDistanceMetric())
result = pcf.walk_local_flow(
    pos, vel, config=config_phase, start_idx=0, metric_scale=1.0
)

Custom Metrics

You can define custom metrics by subclassing AbstractDistanceMetric:

import equinox as eqx
import jax
import jax.numpy as jnp
from phasecurvefit.metrics import AbstractDistanceMetric


class WeightedPhaseSpaceMetric(AbstractDistanceMetric):
    """Custom weighted phase-space metric."""

    def __call__(self, current_pos, current_vel, positions, velocities, metric_scale):
        # Compute position distance
        pos_diff = jax.tree.map(jnp.subtract, positions, current_pos)
        pos_dist_sq = sum(jax.tree.leaves(jax.tree.map(jnp.square, pos_diff)))

        # Compute velocity distance
        vel_diff = jax.tree.map(jnp.subtract, velocities, current_vel)
        vel_dist_sq = sum(jax.tree.leaves(jax.tree.map(jnp.square, vel_diff)))

        # Custom weighting scheme
        return jnp.sqrt(pos_dist_sq + (metric_scale**2) * vel_dist_sq)


# Use custom metric via WalkConfig
config = pcf.WalkConfig(metric=WeightedPhaseSpaceMetric())
result = pcf.walk_local_flow(pos, vel, config=config, start_idx=0, metric_scale=1.0)

See the Metrics Guide for more details and examples.

KD-tree Strategy

For large datasets, you can enable spatial KD-tree prefiltering to accelerate neighbor selection:

# Install optional dependency first:
# pip install phasecurvefit[kdtree]

import jax.numpy as jnp

# Define simple Cartesian arrays (not quantities)
pos = {"x": jnp.array([0.0, 1.0, 2.0]), "y": jnp.array([0.0, 0.5, 1.0])}
vel = {"x": jnp.array([1.0, 1.0, 1.0]), "y": jnp.array([0.5, 0.5, 0.5])}

# Use KD-tree strategy and query 2 spatial neighbors per step
config = pcf.WalkConfig(strategy=pcf.strats.KDTree(k=2))
result = pcf.walk_local_flow(pos, vel, config=config, start_idx=0, metric_scale=1.0)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

phasecurvefit-0.1.0.tar.gz (2.8 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

phasecurvefit-0.1.0-py3-none-any.whl (70.3 kB view details)

Uploaded Python 3

File details

Details for the file phasecurvefit-0.1.0.tar.gz.

File metadata

  • Download URL: phasecurvefit-0.1.0.tar.gz
  • Upload date:
  • Size: 2.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for phasecurvefit-0.1.0.tar.gz
Algorithm Hash digest
SHA256 2298de28421edc4881b838278a13e4910b06092b5f7d7cf6e5ec4cae1f3385f5
MD5 7dba66a511864b85856c2f05900edb09
BLAKE2b-256 54a58e65c269a673db2330db800a9f51806159e3d16379c66c6290d201d06602

See more details on using hashes here.

Provenance

The following attestation bundles were made for phasecurvefit-0.1.0.tar.gz:

Publisher: cd.yml on GalacticDynamics/phasecurvefit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file phasecurvefit-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: phasecurvefit-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 70.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for phasecurvefit-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 af95ead63502a800305dd8cf19a6037ac20d070e45e0df5726e562dd4bd3070b
MD5 d1fbeb320c638ec9916b2021296c4287
BLAKE2b-256 be605a3894cadb1fdd0ffa63bf9f0349c29c4a8bb2215975da0292ba31761e57

See more details on using hashes here.

Provenance

The following attestation bundles were made for phasecurvefit-0.1.0-py3-none-any.whl:

Publisher: cd.yml on GalacticDynamics/phasecurvefit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page