Metadata-Version: 2.4
Name: secular-equilibrium
Version: 1.1.1
Summary: Secular equilibrium calculator for radioactive decay chains
Home-page: https://github.com/Josiah1/secular-eq
Author: Jinjing Li
License: MIT
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering :: Physics
Requires-Python: >=3.7
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: radioactivedecay>=0.6.0
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-python

# Secular Equilibrium Calculator

Radioactive Decay Chain Secular Equilibrium Calculation Tool

## 📦 Features

- Calculate parent nuclide activity and mass based on measured daughter nuclide activity
- Supports any radioactive decay chain, including natural series (U-238, Th-232, U-235) and artificial chains
- Automatic cumulative branching ratio calculation across decay chains
- Supports all decay types (α, β-, β+, EC, SF, IT, p, n, etc.)
- Decay type specification with shorthand support (a for α, b for β-, e for EC)
- Provide command-line interface (CLI) and Python API
- Detailed error handling and input validation
- Flexible output modes including quiet and mass-only outputs
- Measurement uncertainty propagation for activity and mass outputs
- Batch CSV processing mode for multi-sample calculations
- Full decay-path explanation with per-path branching contributions

## 🔧 Installation

### Install via pip (recommended)

```bash
pip install secular-equilibrium
```

### Install from source

```bash
# Clone repository
git clone https://github.com/Josiah1/secular-eq.git
cd secular-eq

# Install dependencies
pip install -r requirements.txt

# Install in development mode
pip install -e .
```

## 🚀 Quick Start

### Method 1: Python library usage

```python
from secular_equilibrium import calculate_secular_equilibrium

# Calculate U-238 content from Pb-214 activity
results = calculate_secular_equilibrium(
    measured_nuclide='Pb-214',
    measured_activity=100.0,  # Bq
    parent_nuclides=['U-238', 'Ra-226'],
    verbose=True
)

print(f"U-238 activity: {results['U-238']['activity_Bq']:.4e} Bq")
print(f"U-238 mass: {results['U-238']['mass_g']:.4e} g")
```

### Method 2: Command-line usage

```bash
# Basic usage
secular-eq --measured Pb-214 --activity 100 --parents U-238 Ra-226

# Short form
secular-eq -m Pb-214 -a 100 -p U-238

# Multiple parent nuclides
secular-eq -m Bi-214 -a 50 -p U-238 U-234 Ra-226 Rn-222

# Quiet mode (only output key results)
secular-eq -m Pb-214 -a 100 -p U-238 -q

# Specify decay type (e.g., alpha decay)
secular-eq -m Pb-214 -a 100 -p U-238 -d α

# Using shorthand for decay type (a for alpha, b for beta, e for EC)
secular-eq -m Pb-214 -a 100 -p U-238 -d a

# Mass-only output (only masses in grams, one per line)
secular-eq -m Pb-214 -a 100 -p U-238 Ra-226 --mass-only

# Include measured activity uncertainty (Bq)
secular-eq -m Pb-214 -a 100 -p U-238 --activity-unc 5

# Explain all parent-to-measured decay paths and path contributions
secular-eq -m Ra-223 -a 100 -p Ac-227 --explain-paths

# Batch mode from CSV (output to stdout)
secular-eq --input-csv batch_inputs.csv

# Batch mode with output file
secular-eq --input-csv batch_inputs.csv --output-csv batch_outputs.csv
```

## 📊 Practical Application Examples

### Example 1: U-238 content determination in environmental samples

```python
from secular_equilibrium import calculate_secular_equilibrium

# Measured Pb-214 activity in soil sample is 85 Bq/kg
results = calculate_secular_equilibrium(
    measured_nuclide='Pb-214',
    measured_activity=85.0,  # Bq/kg
    parent_nuclides=['U-238'],
    verbose=True
)

# Get U-238 content
u238_mass_per_kg = results['U-238']['mass_g']
u238_ppm = u238_mass_per_kg * 1e6  # Convert to ppm
print(f"\nU-238 concentration in soil: {u238_ppm:.2f} ppm")
```

### Example 2: Th-232 series analysis

```python
# Measured Bi-212 activity
results = calculate_secular_equilibrium(
    measured_nuclide='Bi-212',
    measured_activity=120.0,
    parent_nuclides=['Th-232', 'Ra-228', 'Th-228'],
    verbose=False  # Don't print detailed information
)

# Extract key information
for parent, data in results.items():
    print(f"{parent}:")
    print(f"  Activity: {data['activity_Bq']:.2e} Bq")
    print(f"  Mass: {data['mass_g']:.2e} g")
    print(f"  Branching ratio: {data['branching_ratio']:.4f}")
```

## 📚 API Documentation

### `SecularEquilibriumCalculator` class

#### Initialization parameters
- `measured_nuclide` (str): Measured nuclide name (e.g., 'Pb-214', 'Bi-214')
- `measured_activity` (float): Measured activity (Bq)
- `parent_nuclides` (List[str]): List of parent nuclides (e.g., ['U-238', 'Ra-226'])
- `decay_type` (str, optional): Decay type to consider (e.g., 'α', 'β-', 'β+', 'EC'). If None, considers all decay types (default).

#### Methods
- `calculate()`: Perform calculation, return result dictionary
- `print_results(results)`: Print formatted results

### `calculate_secular_equilibrium()` function

Convenience function that automatically creates calculator and returns results.

```python
def calculate_secular_equilibrium(
    measured_nuclide: str,
    measured_activity: float,
    parent_nuclides: List[str],
    decay_type: Optional[str] = None,
    verbose: bool = True,
    measured_activity_uncertainty: Optional[float] = None,
    include_paths: bool = False,
) -> Dict[str, Dict[str, float]]
```

#### Example with decay type specification

```python
# Calculate U-238 activity from measured Pb-214 alpha decay activity
results = calculate_secular_equilibrium(
    measured_nuclide='Pb-214',
    measured_activity=50.0,  # Alpha decay activity (Bq)
    parent_nuclides=['U-238'],
    decay_type='α',  # or use shorthand 'a'
    verbose=True
)

# Using shorthand for decay type
results = calculate_secular_equilibrium(
    measured_nuclide='Pb-214',
    measured_activity=50.0,
    parent_nuclides=['U-238'],
    decay_type='a',  # shorthand for alpha
    verbose=True
)
```

#### Return value format

```python
{
    'U-238': {
        'activity_Bq': 100.0,           # Activity (Bq)
        'mass_g': 8.04e-6,              # Mass (g)
        'branching_ratio': 1.0,         # Branching ratio
        'halflife_yr': 4.468e9,         # Half-life (years)
        'atomic_mass': 238.05078826,    # Atomic mass (u)
        'activity_uncertainty_Bq': 5.0, # Optional uncertainty field
        'mass_uncertainty_g': 4.02e-7,  # Optional uncertainty field
        'relative_uncertainty': 0.05,   # Optional uncertainty field
        'paths': [...]                  # Optional when include_paths=True
    }
}
```

## 🧾 Batch CSV Input/Output

### Input CSV columns

Required:
- `measured_nuclide`
- `measured_activity`
- `parent_nuclides` (semicolon-separated, e.g., `U-238;Ra-226`)

Optional:
- `decay_type`
- `measured_activity_uncertainty`

### Output CSV columns

Always includes input columns plus:
- `parent`
- `activity_Bq`, `mass_g`, `branching_ratio`, `halflife_yr`, `atomic_mass`
- `activity_uncertainty_Bq`, `mass_uncertainty_g`, `relative_uncertainty` (when available)
- `paths_json` (when `--explain-paths` is enabled)
- `error` (row-level or parent-level errors)

Batch mode continues processing on errors and returns non-zero exit code if any row fails.

## 🔬 Supported Decay Chains

The calculator supports **any radioactive decay chain** based on the nuclear decay database. While commonly used for natural radioactive series, it works equally well for artificial decay chains and custom nuclide combinations.

### Major natural radioactive series (common examples)

1. **U-238 series** (Uranium series)
   - U-238 → Th-234 → Pa-234m → U-234 → Th-230 → Ra-226 → Rn-222 → Po-218 → Pb-214 → Bi-214 → Po-214 → Pb-210

2. **Th-232 series** (Thorium series)
   - Th-232 → Ra-228 → Ac-228 → Th-228 → Ra-224 → Rn-220 → Po-216 → Pb-212 → Bi-212 → Po-212/Tl-208

3. **U-235 series** (Actinium series)
   - U-235 → Th-231 → Pa-231 → Ac-227 → Th-227 → Ra-223 → Rn-219 → Po-215 → Pb-211 → Bi-211

## ⚠️ Important Notes

1. **Closed system**: Assumes closed system with no external nuclide addition or loss
2. **Equilibrium time**: Requires waiting about 7-10 daughter half-lives to reach equilibrium
3. **Branching decay**: Automatically considers branching ratios, but ensure correct decay chain
4. **Measurement uncertainty**: Result accuracy depends on input activity measurement precision

## 🧪 Running Tests

```bash
# Run all tests
python -m pytest tests/

# Run specific test
python -m pytest tests/test_calculator.py::TestSecularEquilibrium::test_u238_chain

# Use unittest
python -m unittest tests/test_calculator.py
```

## 📄 License

MIT License - See [LICENSE](LICENSE) file for details

## 🤝 Contributing

Welcome to submit Issues and Pull Requests!

1. Fork the project
2. Create feature branch (`git checkout -b feature/AmazingFeature`)
3. Commit changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to branch (`git push origin feature/AmazingFeature`)
5. Open Pull Request

## 📧 Contact

For questions, please submit an Issue on GitHub.
