Metadata-Version: 2.4
Name: galfit-builder
Version: 0.2.0
Summary: Convert DS9 region files to GALFIT feedme input files
Author: James Kulp
License: MIT
Project-URL: Homepage, https://github.com/jameskulp/galfit-builder
Project-URL: Issues, https://github.com/jameskulp/galfit-builder/issues
Keywords: astronomy,galfit,ds9,regions,galaxy fitting
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Astronomy
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: numpy>=1.20
Requires-Dist: astropy>=5.0
Requires-Dist: regions>=0.7
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Requires-Dist: ruff; extra == "dev"

# galfit-builder

A Python CLI toolkit for GALFIT galaxy fitting. Convert DS9 region files to GALFIT feedme files, freeze fitted components, cut/rotate images, extract config values from FITS headers, and convert results back to regions for visualization.

## Installation

```bash
pip install galfit-builder
```

Or install from source:
```bash
git clone https://github.com/jameskulp/galfit-builder.git
cd galfit-builder
pip install -e .
```

## Quick Start

1. Copy the example config and edit for your data:
```bash
cp $(python -c "import galfit_builder; print(galfit_builder.__path__[0])")/config/example_config.toml config.toml
```

2. Extract values from your FITS header (optional):
```bash
galfit-config science.fits -o config.toml
```

3. Draw regions in DS9, save as `regions.reg`

4. Generate feedme:
```bash
galfit-builder --config config.toml
```

5. Run GALFIT:
```bash
galfit output_galfit.feedme
```

6. Visualize results:
```bash
galfit-to-regions config.toml galfit.01
```

## CLI Tools

### galfit-builder

Convert DS9 regions to a GALFIT feedme file.

```bash
galfit-builder --config config.toml           # generate feedme
galfit-builder --config config.toml -c        # also generate constraints file
galfit-builder --config config.toml -f        # force overwrite existing files
```

### galfit-config

Extract config values (zeropoint, plate scale, dimensions) from FITS headers interactively.

```bash
galfit-config science.fits                              # print found values
galfit-config science.fits -o config.toml               # update config.toml in place
galfit-config science.fits -c template.toml -o out.toml # copy template and update
```

Searches for zeropoint keywords: `ZPT_AB`, `ZEROPNT`, `ZEROPOINT`, `MAGZPT`, `PHOTZPT`, `ZP`, `ZEROPT`. Also calculates from `PHOTFLAM`/`PHOTPLAM` (HST style).

### galfit-freeze

Freeze components outside green polygon regions. Lock down fitted components while working on a specific area.

```bash
galfit-freeze output.feedme regions.reg                              # freeze only
galfit-freeze output.feedme regions.reg -i image.fits -c config.toml # add new components
```

Draw a green polygon in DS9 around the area you want to fit. Components inside remain free; components outside are frozen.

### galfit-cutout

Rotate and cut FITS images based on a DS9 box region. Smaller cutouts run faster in GALFIT.

```bash
galfit-cutout box.reg -s science.fits -e sigma.fits -p psf.fits
galfit-cutout box.reg -s science.fits -v              # sigma is inverse variance
galfit-cutout box.reg -s science.fits --prefix rot_   # custom output prefix
```

Headers (including WCS) are updated for the new cutout size and rotation.

### galfit-to-regions

Convert GALFIT output back to DS9 regions for visualization.

```bash
galfit-to-regions config.toml galfit.01           # GALFIT output file
galfit-to-regions config.toml output.feedme       # or feedme file
```

## Configuration

### Minimal Config

```toml
[input]
region_file = "regions.reg"

[galfit_input_controls]
working_dir = "."
input_data_image = "science.fits"
psf_image = "psf.fits"
zeropoint = 25.0                    # REQUIRED
plate_scale = [0.03, 0.03]          # REQUIRED
fit_region = [1, 500, 1, 500]       # REQUIRED
conv_box = [100, 100]               # optional, "auto" or omit for GALFIT to decide
display_type = "regular"
mode = 0

[galfit_output_controls]
version_outputs = true
overwrite = false

[region_colors]
green = "sersic"
red = "devauc"
cyan = "gaussian"
```

### Required Parameters

- `zeropoint` - AB magnitude zeropoint (use `galfit-config` to extract from header)
- `plate_scale` - Plate scale in arcsec/pixel
- `fit_region` - Image region to fit `[xmin, xmax, ymin, ymax]`

### Region Color Mapping

DS9 region colors determine GALFIT component types:

| Color   | Component | Description |
|---------|-----------|-------------|
| green   | sersic    | Sersic profile |
| red     | devauc    | de Vaucouleurs (n=4) |
| blue    | ferrer    | Ferrer profile |
| cyan    | gaussian  | 2D Gaussian |
| yellow  | moffat    | Moffat profile |
| magenta | king      | King profile (globular clusters) |
| white   | nuker     | Nuker profile |
| orange  | expdisk   | Exponential disk |
| pink    | edgedisk  | Edge-on disk |

Point regions become PSF components regardless of color.

### The "auto" Keyword

Use `"auto"` for smart defaults:

```toml
sigma_image = "auto"    # writes "none" — let GALFIT estimate
conv_box = "auto"       # writes "0 0" — let GALFIT decide
background = "auto"     # compute sky from image edges
```

### Sky Component

Sky is added automatically as component 1. Disable with:

```toml
[defaults.sky]
include = false
```

Or configure:

```toml
[defaults.sky]
include = true
background = "auto"       # or a number like 100.5
dsky_dx = 0.0
dsky_dy = 0.0
background_freeze = false
dsky_dx_freeze = true
dsky_dy_freeze = true
```

### Constraints

Generate parameter constraints with `-c`:

```bash
galfit-builder --config config.toml -c
```

Configure in TOML:

```toml
[constraints.sersic]
n = "0.5 to 8"           # hard limits (min max)
q = "0.1 to 1"
re_scale = 0.1           # re constrained to [re*0.1, re/0.1]
mag = "10 to 35"
x = "-5 5"               # offset from initial: +/- 5 pixels
y = "-5 5"
```

Output format:
```
# Component  Parameter   Constraint

1  x      -5.0  5.0
1  y      -5.0  5.0
1  mag    10.0  35.0
```

### Component Defaults

Set default parameters and freeze states:

```toml
[defaults.sersic]
sersic_index = 2.5
mag_freeze = false
sersic_index_freeze = false
axis_ratio_freeze = false
pos_angle_freeze = false

[defaults.psf]
mag_freeze = false
```

## Workflow Example

**Initial fit:**
```bash
# Extract config values from FITS header
galfit-config science.fits -o config.toml

# Draw ellipses/points in DS9, save as regions.reg
galfit-builder --config config.toml -c
galfit science_galfit.feedme
galfit-to-regions config.toml galfit.01
# Load galfit.01.reg in DS9 to see fitted positions
```

**Iterative refinement:**
```bash
# Draw green polygon around area to refine
# Adjust regions inside polygon
galfit-freeze galfit.01 regions.reg -i science.fits -c config.toml
galfit frozen_galfit.01.feedme
```

**Working with cutouts:**
```bash
# Draw box region in DS9 for cutout area
galfit-cutout box.reg -s science.fits -e sigma.fits -p psf.fits
# Edit config to point to cutout_* files, update fit_region
galfit-builder --config config.toml
```

## Python API

```python
from galfit_builder.config.loader import load_config
from galfit_builder.io.parse_regions import read_regions
from galfit_builder.builders.component_builder import build_components
from galfit_builder.controls.controls import GalfitControls
from astropy.io import fits

config = load_config("config.toml")
regions = read_regions("regions.reg")
image_data = fits.getdata("science.fits")

components = build_components(regions, image_data, config)

controls = GalfitControls(
    working_dir=".",
    input_data_image="science.fits",
    output_data_image="output.fits",
    zeropoint=25.0,
    plate_scale=(0.03, 0.03),
    fit_region=(1, 500, 1, 500),
)
print(controls)
for comp in components:
    print(comp)
```

## Supported Components

| Component | Region | Key Parameters |
|-----------|--------|----------------|
| sersic | Ellipse | magnitude, effective radius, sersic index, axis ratio, PA |
| psf | Point | magnitude |
| devauc | Ellipse | magnitude, effective radius, axis ratio, PA |
| expdisk | Ellipse | magnitude, scale radius, axis ratio, PA |
| gaussian | Ellipse | magnitude, FWHM, axis ratio, PA |
| moffat | Ellipse | magnitude, FWHM, powerlaw, axis ratio, PA |
| king | Ellipse | surface brightness, core radius, tidal radius, alpha |
| nuker | Ellipse | surface brightness, break radius, alpha, beta, gamma |
| ferrer | Ellipse | surface brightness, outer radius, alpha, beta |
| edgedisk | Ellipse | surface brightness, scale height, scale length, PA |
| sky | N/A | background, dsky/dx, dsky/dy |

## Project Structure

```
galfit_builder/
├── cli/                    # Command-line tools
│   ├── run.py              # galfit-builder
│   ├── freeze.py           # galfit-freeze
│   ├── cutout.py           # galfit-cutout
│   ├── to_regions.py       # galfit-to-regions
│   └── config_from_header.py  # galfit-config
├── builders/               # Component builders
├── components/             # GALFIT component classes
├── config/                 # Config loader and example
├── constraints/            # Constraint file generation
├── controls/               # GALFIT control parameters
├── io/                     # Region file parsing
└── masking/                # Bad pixel mask generation
```

## Dependencies

- Python >= 3.10
- numpy
- astropy
- regions

## License

MIT
