# A significant accretion event 1.8 billion years before the last major Milky Way merger

## Overview

This repository contains:

1. tabular datasets of Galactic globular-cluster (GC) ages, metallicities, and orbital/dynamical quantities;  
2. Python code implementing two Bayesian inference workflows:
   - Nested Sampling (dynesty) for joint chemical+dynamical inference, posterior estimation, and model evidence;
   - MCMC (emcee) for hierarchical chrono-chemical modeling driven by JSON configuration files.

The repository is organized in such a way that the data, configuration files, and analysis scripts can be run independently for the different sub-samples discussed in the manuscript.

---

## Repository layout

repo_root/
├── data/
│   ├── GC_amr_orbit_data.txt
│   ├── GSE.txt
│   ├── LHK.txt
│   └── MW.txt
├── config/
│   ├── config_GSE.json
│   ├── config_LHK.json
│   └── config_MW.json
├── code/
│   ├── NS_amrdyn.py
│   ├── main.py
│   ├── model.py
│   └── save.py
└── environment.yml


### File summary

#### Data files
- data/GC_amr_orbit_data.txt: full chemical+dynamical GC table used by the nested-sampling workflow.
- data/GSE.txt: age-metallicity table for the GSE MCMC run.
- data/LHK.txt: age-metallicity table for the LHK MCMC run.
- data/MW.txt:  age-metallicity table for the MW MCMC run.

#### Configuration files
- config/config_GSE.json: configuration for the GSE MCMC run.
- config/config_LHK.json: configuration for the LHK MCMC run.
- config/config_MW.json: configuration for the MW MCMC run.

#### Code files
- code/main.py: entry point for the emcee-based MCMC workflow.
- code/model.py: prior, likelihood, posterior, and model functions used by the MCMC workflow.
- code/save.py: plotting and output utilities used by the MCMC workflow.
- code/NS_amrdyn.py: entry point for the dynesty + JAX nested-sampling workflow.

---

## Installation

The recommended installation method is via the provided Conda environment file.

### 1. Create the environment
From the repository root, run:
>conda env create -f environment.yml


### 2. Activate the environment
>conda activate mw-merger


### 3. Verify the installation
A minimal check is (copy and paste):
> python -c "import numpy, scipy, emcee, corner, jax, jaxlib, numpyro, dynesty, matplotlib; print('Environment OK')"

---

## Dependencies
The environment installs the packages required by the code:
- numpy
- scipy
- argparse
- emcee
- corner
- jax
- jaxlib
- numpyro
- dynesty
- matplotlib
---

## How to run the code
All commands below assume that you are running them from the repository root.

### A. MCMC workflow (emcee)
code/main.py requires a single positional argument: the path to a JSON configuration file.

#### Example commands

bash
python code/NS_amrdyn.py ../data/GC_amr_orbit_data.txt ../output_ns/
python code/main.py ../config/config_MW.json
python code/main.py ../config/config_GSE.json
python code/main.py ../config/config_LHK.json


#### What main.py does

The script:
1. reads the selected JSON configuration file;
2. loads the corresponding input table from data/;
3. initializes and runs the emcee ensemble sampler;
4. discards the burn-in fraction defined in the configuration file;
5. saves plots and numerical summaries to the output directory specified in the JSON file.

#### Expected outputs from main.py

Depending on the flags in the JSON configuration (saveplot, savetxt, savesamples), the output files are produced in the folder defined by:

- output.savepath
- output.folder_name

Typical outputs are:

- corner_plot.png
- fit_plot.png
- walker_plot.png
- best_fit_parameters.txt
- posterior_samples.npy

### B. Nested-sampling workflow (dynesty + JAX)

Run:

python code/NS_amrdyn.py ../data/GC_amr_orbit_data.txt ../output_ns/


#### What NS_amrdyn.py does
The script:
1. loads the full chemical+dynamical table data/GC_amr_orbit_data.txt;
2. defines a multi-component mixture model in JAX;
3. runs dynesty.NestedSampler to estimate posterior samples and log-evidence;
4. computes posterior summaries, inferred masses, and object-by-object component probabilities;
5. saves posterior products and a trace plot.


#### Important note on paths in NS_amrdyn.py
In the current version of the script, DATA_FILE and SAVE_PATH are hard-coded near the top of the file. Before execution, users should verify that these paths are valid on their local machine and, if necessary, edit them to match the local repository layout.


#### Expected outputs from NS_amrdyn.py
The nested-sampling workflow writes outputs to the directory defined by SAVE_PATH. Typical outputs are:
- run_{N_MODELS}models.txt (log file with posterior summaries and class probabilities)
- samples.npy (saved posterior object)
- traceplot.png
---


## Mapping between scripts, configurations, and generated results
This section is included to make it clear which script/configuration is responsible for each class of result.

| Workflow | Script / config | Input data | Main outputs | Result produced |
|---|---|---|---|---|
| Nested Sampling | code/NS_amrdyn.py | data/GC_amr_orbit_data.txt | run_{N_MODELS}models.txt, samples.npy, traceplot.png | Joint chemical+dynamical posterior, log-evidence, inferred masses, and per-cluster component probabilities |
| MCMC | code/main.py + config/config_MW.json | data/MW.txt | fit_plot.png, corner_plot.png, walker_plot.png, best_fit_parameters.txt, posterior_samples.npy | Age-metallicity fit and posterior summary for the MW sample |
| MCMC | code/main.py + config/config_GSE.json | data/GSE.txt | same as above | Age-metallicity fit and posterior summary for the GSE sample |
| MCMC | code/main.py + config/config_LHK.json | data/LHK.txt | same as above | Age-metallicity fit and posterior summary for the LHK sample |
---


## Input data description
### 1. Full chemical+dynamical table
File: data/GC_amr_orbit_data.txt  
Format: ASCII text, whitespace-delimited; first line is a commented header beginning with #.

Columns:

| Column | Name | Description |
|---|---|---|
| 0 | GC | globular cluster identifier |
| 1 | Age | age |
| 2 | eAge | 1-sigma uncertainty on age |
| 3 | [M/H] | metallicity |
| 4 | e[M/H] | 1-sigma uncertainty on metallicity |
| 5 | E | orbital energy |
| 6 | eE | uncertainty on orbital energy |
| 7 | Lz | z-component of angular momentum |
| 8 | eLz | uncertainty on Lz |
| 9 | circ | circularity |
| 10 | ecirc | uncertainty on circularity |
| 11 | Ecc | eccentricity |
| 12 | eEcc | uncertainty on eccentricity |
| 13 | Jr | radial action |
| 14 | eJr | uncertainty on radial action |
| 15 | Jz | vertical action |
| 16 | eJz | uncertainty on vertical action |
| 17 | EJ | additional orbital quantity |
| 18 | eEJ | uncertainty on EJ |

### 2. 5-column tables used by main.py
Files:
- data/GSE.txt
- data/LHK.txt
- data/MW.txt

Format: ASCII text, whitespace-delimited; first line is a commented header beginning with #.
Columns:
| Column | Name | Description |
|---|---|---|
| 0 | name | globular cluster identifier |
| 1 | Age | age |
| 2 | eAge | 1-sigma uncertainty on age |
| 3 | [M/H] | metallicity |
| 4 | e[M/H] | 1-sigma uncertainty on metallicity |
---


## Reproducibility notes
- The MCMC workflow is configuration-driven; therefore, the exact priors, sampler settings, and output paths are controlled by the selected JSON file.
- The nested-sampling workflow is script-driven; therefore, the number of model components, priors, dynamical variables, and output paths are edited directly inside code/NS_amrdyn.py.
- For exact manuscript reproduction, users should record the configuration file used (config_MW.json, config_GSE.json, or config_LHK.json) and, for the nested-sampling workflow, the values of N_MODELS, PRIOR_PARAMS_LIST, DELTAT_LIST, and DYN_VAR_CONFIG defined in code/NS_amrdyn.py.

---

## Citation / contact

If you use this repository and need clarification about the workflow, inputs, or outputs, please contact:

Cristiano Fanelli
cristiano.fanelli@inaf.it
