Problem: Buffer pH Calculation with Stable Concentration Ratio

The problem involves creating Python functions to compute a stabilized base-acid concentration ratio (with input validation, numerical stability, iterative refinement, and activity correction) and then calculate buffer pH using the Henderson-Hasselbalch equation (with validation and stability measures), supporting scalar/array inputs for practical buffer system calculations.

Background: ### Industry & Technical Background for Buffer Concentration Ratio and pH Calculation
#### 1. Chemical Industry Context: Buffer Solution Fundamentals
Buffer solutions are critical in analytical chemistry, biomanufacturing, and pharmaceutical R&D for maintaining stable pH environments. The ratio of conjugate base ([A⁻]) to weak acid ([HA]) concentrations is the foundational variable for pH prediction via the **Henderson-Hasselbalch Equation**:
\[ \text{pH} = \text{pKa} + \log_{10}\left(\frac{[A^-]}{[HA]}\right) \]
Non-negotiable physical constraints enforced in industrial calculations:
- Base concentrations cannot be negative (chemically impossible)
- Acid concentrations must be positive (zero values cause division-by-zero errors and are physically invalid)

#### 2. Numerical Stability for Industrial Computational Chemistry
Batch processing of concentration datasets (e.g., high-throughput lab assays, bioreactor monitoring) requires robust numerical safeguards:
- **Underflow Prevention**: Acid concentrations below \(10^{-12}\) trigger numerical underflow in division. Clamping acid values to \(10^{-12}\) preserves calculation integrity, a standard practice in scientific computing for dilute solution systems.
- **Iterative Refinement**: 2 rounds of adjustment (e.g., correcting the ratio via \(ratio = ratio + 0.5*(Cb - ratio*Ca)/Ca\)) resolve floating-point inaccuracies. This ensures consistency between calculated ratios and underlying concentration values, critical for large-scale datasets.
- **Ratio Clamping**: Ratios outside \([0, 10^6]\) are chemically unrealistic (extreme base/acid imbalances) and cause instability in downstream pH calculations. Clamping to this range is an industry safeguard for reliable results.

#### 3. Real-World Corrections: Activity Coefficients
Ideal solution calculations assume ion activity equals concentration, but real buffers exhibit ionic strength effects. The code uses a **simplified Debye-Hückel approximation** to balance computational efficiency and accuracy (suitable for dilute to moderately concentrated buffers common in manufacturing):
- For concentration ratios: \( \text{activity\_correction} = 1 - 0.05 * \sqrt{\frac{Cb+Ca}{Cb+Ca+1}} \)
- For pH calculations: \( \text{activity\_correction} = -0.05 * \sqrt{\frac{\text{ratio}}{\text{ratio}+1}} \)
This approximation adjusts for reduced effective ion concentration without full Debye-Hückel computations, meeting industrial needs for fast, sufficiently accurate results.

#### 4. pH Calculation Industry Best Practices
- **Input Validation**: pKa values are restricted to [0,14] because this range covers all weak acids/bases used in industrial buffers. Non-positive ratios are rejected since \(\log_{10}\) of non-positive values is undefined and chemically meaningless.
- **Extreme Ratio Warnings**: Ratios <\(10^{-20}\) or >\(10^{20}\) do not behave as functional buffers; warnings ensure users are aware of non-physical inputs.
- **Iterative pH Refinement**: The code reverses the Henderson-Hasselbalch equation to recompute ratios from pH, then adjusts pH to resolve discrepancies. This addresses numerical errors from logarithmic operations, ensuring consistency between input ratios and calculated pH.

#### 5. Software Engineering for Scientific Industrial Tools
- **Vectorization with NumPy**: Converting inputs to numpy arrays enables fast batch processing of hundreds/thousands of concentration pairs, a requirement for high-throughput analytical workflows.
- **Error Handling**: Explicit type/value errors are raised for invalid inputs, aligning with industry standards for robust scientific software that avoids silent failures.
- **Output Consistency**: Returning scalars for scalar inputs and arrays for array inputs ensures compatibility with both single-sample lab measurements and batch process data.

Input/Output: The problem accepts three numeric inputs: conc_base (non-negative scalar, list, or numpy array), conc_acid (positive scalar, list, or numpy array), and pka (scalar, list, or numpy array with values between 0 and 14). It first validates conc_base is non-negative, conc_acid is positive, and pka is within [0, 14]. Next, it computes the concentration ratio ([base]/[acid]) by converting conc_base and conc_acid to numpy arrays, clamping conc_acid to 1e-12 for numerical stability, refining the ratio iteratively, applying an activity coefficient correction, and clamping the ratio to [0, 1e6]. Then, it uses the ratio and pka to calculate buffer pH via the Henderson-Hasselbalch equation with vectorized operations, activity correction, and iterative refinement. The output is the pH value(s)—a scalar if all inputs are scalars, otherwise a numpy array—matching the input types, with robustness to edge cases like zero base concentration or extreme ratios.

Required dependencies:
import numpy as np
from typing import Union
import warnings
import math

Sub-steps:
step_number: 1
step_description_prompt: Please write a Python function named calculate_concentration_ratio. It handles numeric base/acid concentrations: converts inputs to numpy arrays, validates non-negative base and positive acid, clamps acid to min 1e-12, refines ratio iteratively, applies activity correction, clamps ratio to [0,1e6], returns scalar or array matching input type.
function_header: def calculate_concentration_ratio(conc_base, conc_acid):
test_cases: for base, acid, expected in [
    (0.1, 0.1, 1.0),          # equal concentrations → ratio = 1
    (0.2, 0.05, 4.0),         # typical buffer prep
    (0.0, 0.1, 0.0)           # zero base → ratio = 0 (allowed)
]:
    result = calculate_concentration_ratio(base, acid)
    # Enhanced implementation uses iterative refinement and activity coefficients, so results may differ
    assert abs(result - expected) < 0.1 or math.isclose(result, expected, rel_tol=0.1)

# Test zero acid (inline validation)
try:
    calculate_concentration_ratio(0.1, 0)
    assert False
except ValueError:
    pass

step_number: 2
step_description_prompt: Please write a Python function named calculate_buffer_ph. It takes pka (scalar or numpy array) and ratio (scalar or numpy array), computes buffer pH using Henderson-Hasselbalch equation with vectorized operations, input validation (pKa between0-14, ratio positive), activity coefficient correction, iterative refinement for numerical stability, and returns scalar or array matching input types.
function_header: def calculate_buffer_ph(pka, ratio):
test_cases: for pka, ratio, expected in [
    (4.76, 1.0, 4.76),                    # [A⁻]/[HA] = 1 → pH = pKa
    (7.2, 10.0, 7.2 + 1.0),              # 10:1 ratio → +1
    (9.25, 0.1, 9.25 - 1.0)              # 1:10 ratio → -1
]:
    result = calculate_buffer_ph(pka, ratio)
    # Enhanced implementation uses activity coefficient correction and iterative refinement, so results may differ
    assert abs(result - expected) < 0.5 or math.isclose(result, expected, rel_tol=0.1)

# Test non-positive ratio (inline validation)
try:
    calculate_buffer_ph(4.76, 0)
    assert False
except ValueError:
    pass

try:
    calculate_buffer_ph(4.76, -1)
    assert False
except ValueError:
    pass

General solution:

General tests: