Contributing to EPyR Tools

We welcome contributions to EPyR Tools! This document provides guidelines for contributing code, documentation, and reporting issues.

Getting Started

Setting up Development Environment

  1. Fork and Clone

git clone https://github.com/yourusername/epyrtools.git
cd epyrtools
  1. Install Development Dependencies

pip install -e .[dev]

# Or install all optional dependencies
pip install -e .[all]
  1. Set up Pre-commit Hooks

pre-commit install

This ensures code formatting and quality checks run automatically.

Development Workflow

  1. Create a Feature Branch

git checkout -b feature/your-feature-name
  1. Make Changes

    • Write code following project conventions

    • Add tests for new functionality

    • Update documentation as needed

  2. Test Your Changes

# Run tests
pytest

# Check code formatting
black --check .
isort --check-only .
flake8
  1. Commit and Push

git add .
git commit -m "Add feature: description"
git push origin feature/your-feature-name
  1. Create Pull Request

    • Describe your changes clearly

    • Reference any related issues

    • Ensure all CI checks pass

Code Standards

Style Guidelines

We follow PEP 8 with some specific conventions:

  • Line Length: Maximum 88 characters (Black default)

  • Imports: Organized with isort

  • Formatting: Automatic with Black

  • Linting: flake8 for code quality

Example:

"""Module for EPR data processing."""

import numpy as np
from pathlib import Path
from typing import Tuple, Optional, List

from epyr.physics import PLANCK, BMAGN


def process_epr_data(
    x_data: np.ndarray,
    y_data: np.ndarray,
    correction_order: int = 1
) -> Tuple[np.ndarray, np.ndarray]:
    """Process EPR data with baseline correction.

    Args:
        x_data: Field values in Gauss
        y_data: EPR signal intensity
        correction_order: Polynomial order for baseline

    Returns:
        Tuple of (corrected_data, baseline)

    Raises:
        ValueError: If data arrays have different lengths
    """
    if len(x_data) != len(y_data):
        raise ValueError("Data arrays must have same length")

    # Implementation here
    return corrected_data, baseline

Documentation

  • Docstrings: Use Google/NumPy style

  • Type Hints: Add for all public functions

  • Examples: Include usage examples in docstrings

  • Comments: Explain complex algorithms and physics

Testing

Test Structure

Tests are organized in the tests/ directory:

tests/
├── conftest.py          # Pytest configuration
├── test_eprload.py      # Data loading tests
├── test_baseline.py     # Baseline correction tests
├── test_fair.py         # FAIR conversion tests
└── data/                # Test data files
    ├── sample.dsc
    └── sample.dta

Writing Tests

Use pytest for all tests:

import pytest
import numpy as np
from epyr.baseline import baseline_polynomial


class TestBaselineCorrection:
    """Test baseline correction functionality."""

    def test_polynomial_correction(self):
        """Test polynomial baseline correction."""
        # Create test data with known baseline
        x = np.linspace(0, 100, 1000)
        true_signal = np.exp(-((x - 50)**2) / 100)
        true_baseline = 0.1 * x + 5
        noisy_data = true_signal + true_baseline + np.random.normal(0, 0.01, 1000)

        # Apply correction
        corrected, fitted_baseline = baseline_polynomial(
            noisy_data, x_data=x, poly_order=1
        )

        # Check results
        np.testing.assert_allclose(fitted_baseline, true_baseline, rtol=0.1)
        np.testing.assert_allclose(corrected, true_signal, atol=0.1)

    @pytest.mark.parametrize("order", [0, 1, 2, 3])
    def test_different_orders(self, order):
        """Test different polynomial orders."""
        x = np.linspace(0, 100, 500)
        y = np.ones_like(x) + 0.01 * np.random.randn(len(x))

        corrected, baseline = baseline_polynomial(y, x_data=x, poly_order=order)

        assert len(corrected) == len(y)
        assert len(baseline) == len(y)

Running Tests

# Run all tests
pytest

# Run specific test file
pytest tests/test_baseline.py

# Run with coverage
pytest --cov=epyr

# Run tests for specific function
pytest -k "test_polynomial"

Documentation Contributions

Types of Documentation

  1. API Documentation: Automatically generated from docstrings

  2. User Guides: Tutorial and how-to content

  3. Examples: Jupyter notebooks and scripts

  4. Reference: Technical specifications and algorithms

Building Documentation

# Install documentation dependencies
pip install -e .[docs]

# Build documentation
cd docs
make html

# View documentation
open _build/html/index.html

Writing Documentation

  • Clear Examples: Always include working code examples

  • Screenshots: Add images for GUI features

  • Cross-references: Link to related functions and concepts

  • Math: Use LaTeX for equations when needed

Example RST:

Advanced Baseline Correction
============================

The :func:`epyr.baseline.baseline_polynomial` function supports
advanced baseline correction with signal exclusion.

.. math::

   y_{corrected} = y_{original} - P_n(x)

where :math:`P_n(x)` is a polynomial of order :math:`n`.

Example Usage
-------------

.. code-block:: python

   from epyr.baseline import baseline_polynomial

   # Apply quadratic correction excluding peak region
   y_corrected, baseline = baseline_polynomial(
       y_data,
       x_data=x_data,
       poly_order=2,
       exclude_regions=[(3300, 3400)]
   )

Issue Reporting

Bug Reports

When reporting bugs, please include:

  1. System Information: OS, Python version, EPyR version

  2. Minimal Example: Smallest code that reproduces the issue

  3. Expected vs Actual: What should happen vs what happens

  4. Data Files: If possible, share problem data files

  5. Error Messages: Full traceback and error output

Template:

## Bug Report

**System:**
- OS: macOS 12.0
- Python: 3.9.7
- EPyR Tools: 0.1.6

**Issue:**
Baseline correction fails with 2D data

**Minimal Example:**
```python
import epyr
x, y, params, _ = epyr.eprload('2d_data.dsc')
# Error occurs here:
corrected, baseline = baseline_polynomial(y, x_data=x)
```

**Error:**
```
ValueError: y_data must be a 1D NumPy array.
```

**Expected:** Should handle 2D data or give clear guidance

Feature Requests

For feature requests:

  1. Use Case: Describe the scientific problem

  2. Proposed Solution: How should it work?

  3. Alternatives: What workarounds exist?

  4. Examples: Show expected API usage

EPR Domain Knowledge

Contributing EPR-Specific Features

When adding EPR-specific functionality:

  • Physical Accuracy: Ensure equations and constants are correct

  • Units: Be explicit about units (Gauss vs Tesla, etc.)

  • Conventions: Follow EPR community standards

  • References: Cite relevant papers and textbooks

Example - g-factor calculation:

def calculate_g_factor(frequency_hz: float, field_gauss: float) -> float:
    """Calculate g-factor from resonance condition.

    Uses the EPR resonance condition: hν = gμBB

    Args:
        frequency_hz: Microwave frequency in Hz
        field_gauss: Magnetic field in Gauss

    Returns:
        Dimensionless g-factor

    References:
        Weil, J. A., & Bolton, J. R. (2007). Electron paramagnetic
        resonance: elementary theory and practical applications.
        John Wiley & Sons.
    """
    from epyr.physics import PLANCK, BMAGN

    # Convert Gauss to Tesla
    field_tesla = field_gauss * 1e-4

    # g = hν / (μB * B)
    return (PLANCK * frequency_hz) / (BMAGN * field_tesla)

Common Contribution Areas

Areas where contributions are especially welcome:

  1. New File Formats: Support for other spectrometer manufacturers

  2. Analysis Algorithms: Advanced peak fitting, simulation

  3. Visualization: Interactive plots, publication templates

  4. Data Processing: Noise reduction, phase correction

  5. Integration: Bridges to other software (Origin, MATLAB)

Code Review Process

What to Expect

  1. Automated Checks: CI runs tests and style checks

  2. Maintainer Review: Core team reviews code and design

  3. Community Feedback: Other users may comment

  4. Iteration: Expect requests for changes or improvements

Review Criteria

  • Correctness: Does the code work as intended?

  • Testing: Are there adequate tests?

  • Documentation: Is it properly documented?

  • Style: Does it follow project conventions?

  • Performance: Is it reasonably efficient?

  • Compatibility: Works with supported Python versions?

Getting Help

If you need help contributing:

  1. GitHub Discussions: Ask questions about implementation

  2. Issues: Tag issues with “help wanted” or “good first issue”

  3. Email: Contact maintainers for major changes

  4. Documentation: Check existing docs and examples

Recognition

Contributors are recognized in:

  • CHANGELOG.md: Major contributions noted in release notes

  • AUTHORS: List of all contributors

  • Git History: Detailed commit attribution

  • Documentation: Citation in relevant sections

Thank you for contributing to EPyR Tools and supporting the EPR research community!