# Extractors Catalog Module

**Last Updated**: December 5, 2025
**Version**: 1.0
**Type**: Optional Module

This module documents all available extractors in the Atomizer framework. Load this when the user asks about result extraction or needs to understand what extractors are available.

---

## When to Load

- User asks "what extractors are available?"
- User needs to extract results from OP2/BDF files
- Setting up a new study with custom extraction needs
- Debugging extraction issues

---

## PR.1 Extractor Catalog

| ID | Extractor | Module | Function | Input | Output | Returns |
|----|-----------|--------|----------|-------|--------|---------|
| E1 | **Displacement** | `optimization_engine.extractors.extract_displacement` | `extract_displacement(op2_file, subcase=1)` | `.op2` | mm | `{'max_displacement': float, 'max_disp_node': int, 'max_disp_x/y/z': float}` |
| E2 | **Frequency** | `optimization_engine.extractors.extract_frequency` | `extract_frequency(op2_file, subcase=1, mode_number=1)` | `.op2` | Hz | `{'frequency': float, 'mode_number': int, 'eigenvalue': float, 'all_frequencies': list}` |
| E3 | **Von Mises Stress** | `optimization_engine.extractors.extract_von_mises_stress` | `extract_solid_stress(op2_file, subcase=1, element_type='cquad4')` | `.op2` | MPa | `{'max_von_mises': float, 'max_stress_element': int}` |
| E4 | **BDF Mass** | `optimization_engine.extractors.bdf_mass_extractor` | `extract_mass_from_bdf(bdf_file)` | `.dat`/`.bdf` | kg | `float` (mass in kg) |
| E5 | **CAD Expression Mass** | `optimization_engine.extractors.extract_mass_from_expression` | `extract_mass_from_expression(prt_file, expression_name='p173')` | `.prt` + `_temp_mass.txt` | kg | `float` (mass in kg) |
| E6 | **Field Data** | `optimization_engine.extractors.field_data_extractor` | `FieldDataExtractor(field_file, result_column, aggregation)` | `.fld`/`.csv` | varies | `{'value': float, 'stats': dict}` |
| E7 | **Stiffness** | `optimization_engine.extractors.stiffness_calculator` | `StiffnessCalculator(field_file, op2_file, force_component, displacement_component)` | `.fld` + `.op2` | N/mm | `{'stiffness': float, 'displacement': float, 'force': float}` |
| E11 | **Part Mass & Material** | `optimization_engine.extractors.extract_part_mass_material` | `extract_part_mass_material(prt_file)` | `.prt` | kg + dict | `{'mass_kg': float, 'volume_mm3': float, 'material': {'name': str}, ...}` |

**For Zernike extractors (E8-E10)**, see the [zernike-optimization module](./zernike-optimization.md).

---

## PR.2 Extractor Code Snippets (COPY-PASTE)

### E1: Displacement Extraction

```python
from optimization_engine.extractors.extract_displacement import extract_displacement

disp_result = extract_displacement(op2_file, subcase=1)
max_displacement = disp_result['max_displacement']  # mm
max_node = disp_result['max_disp_node']  # Node ID
```

**Return Dictionary**:
```python
{
    'max_displacement': 0.523,      # Maximum magnitude (mm)
    'max_disp_node': 1234,          # Node ID with max displacement
    'max_disp_x': 0.123,            # X component at max node
    'max_disp_y': 0.456,            # Y component at max node
    'max_disp_z': 0.234             # Z component at max node
}
```

### E2: Frequency Extraction

```python
from optimization_engine.extractors.extract_frequency import extract_frequency

# Get first mode frequency
freq_result = extract_frequency(op2_file, subcase=1, mode_number=1)
frequency = freq_result['frequency']  # Hz

# Get all frequencies
all_freqs = freq_result['all_frequencies']  # List of all mode frequencies
```

**Return Dictionary**:
```python
{
    'frequency': 125.4,             # Requested mode frequency (Hz)
    'mode_number': 1,               # Mode number requested
    'eigenvalue': 6.21e5,           # Eigenvalue (rad/s)^2
    'all_frequencies': [125.4, 234.5, 389.2, ...]  # All mode frequencies
}
```

### E3: Stress Extraction

```python
from optimization_engine.extractors.extract_von_mises_stress import extract_solid_stress

# For shell elements (CQUAD4, CTRIA3)
stress_result = extract_solid_stress(op2_file, subcase=1, element_type='cquad4')

# For solid elements (CTETRA, CHEXA)
stress_result = extract_solid_stress(op2_file, subcase=1, element_type='ctetra')

max_stress = stress_result['max_von_mises']  # MPa
```

**Return Dictionary**:
```python
{
    'max_von_mises': 187.5,         # Maximum von Mises stress (MPa)
    'max_stress_element': 5678,     # Element ID with max stress
    'mean_stress': 45.2,            # Mean stress across all elements
    'stress_distribution': {...}    # Optional: full distribution data
}
```

### E4: BDF Mass Extraction

```python
from optimization_engine.extractors.bdf_mass_extractor import extract_mass_from_bdf

mass_kg = extract_mass_from_bdf(str(dat_file))  # kg
```

**Note**: Calculates mass from element properties and material density in the BDF/DAT file.

### E5: CAD Expression Mass

```python
from optimization_engine.extractors.extract_mass_from_expression import extract_mass_from_expression

mass_kg = extract_mass_from_expression(model_file, expression_name="p173")  # kg
```

**Note**: Requires `_temp_mass.txt` to be written by solve journal. The expression name is the NX expression that contains the mass value.

### E6: Field Data Extraction

```python
from optimization_engine.extractors.field_data_extractor import FieldDataExtractor

# Create extractor
extractor = FieldDataExtractor(
    field_file="results.fld",
    result_column="Temperature",
    aggregation="max"  # or "min", "mean", "sum"
)

result = extractor.extract()
value = result['value']  # Aggregated value
stats = result['stats']  # Full statistics
```

### E7: Stiffness Calculation

```python
# Simple stiffness from displacement (most common)
applied_force = 1000.0  # N - MUST MATCH YOUR MODEL'S APPLIED LOAD
stiffness = applied_force / max(abs(max_displacement), 1e-6)  # N/mm

# Or using StiffnessCalculator for complex cases
from optimization_engine.extractors.stiffness_calculator import StiffnessCalculator

calc = StiffnessCalculator(
    field_file="displacement.fld",
    op2_file="results.op2",
    force_component="Fz",
    displacement_component="Tz"
)
result = calc.calculate()
stiffness = result['stiffness']  # N/mm
```

### E11: Part Mass & Material Extraction

```python
from optimization_engine.extractors import extract_part_mass_material, extract_part_mass

# Full extraction with all properties
result = extract_part_mass_material(prt_file)
mass_kg = result['mass_kg']           # kg
volume = result['volume_mm3']          # mm³
area = result['surface_area_mm2']      # mm²
cog = result['center_of_gravity_mm']   # [x, y, z] mm
material = result['material']['name']  # e.g., "Aluminum_2014"

# Simple mass-only extraction
mass_kg = extract_part_mass(prt_file)  # kg
```

**Return Dictionary**:
```python
{
    'mass_kg': 0.1098,                    # Mass in kg
    'mass_g': 109.84,                     # Mass in grams
    'volume_mm3': 39311.99,               # Volume in mm³
    'surface_area_mm2': 10876.71,         # Surface area in mm²
    'center_of_gravity_mm': [0, 42.3, 39.6],  # CoG in mm
    'material': {
        'name': 'Aluminum_2014',          # Material name (or None)
        'density': None,                  # Density if available
        'density_unit': 'kg/mm^3'
    },
    'num_bodies': 1                       # Number of solid bodies
}
```

**Prerequisites**: Run the NX journal first to create the temp file:
```bash
run_journal.exe nx_journals/extract_part_mass_material.py -args model.prt
```

---

## Extractor Selection Guide

| Need | Extractor | When to Use |
|------|-----------|-------------|
| Max deflection | E1 | Static analysis displacement check |
| Natural frequency | E2 | Modal analysis, resonance avoidance |
| Peak stress | E3 | Strength validation, fatigue life |
| FEM mass | E4 | When mass is from mesh elements |
| CAD mass | E5 | When mass is from NX expression |
| Temperature/Custom | E6 | Thermal or custom field results |
| k = F/δ | E7 | Stiffness maximization |
| Wavefront error | E8-E10 | Telescope/mirror optimization |
| Part mass + material | E11 | Direct from .prt file with material info |

---

## Engineering Result Types

| Result Type | Nastran SOL | Output File | Extractor |
|-------------|-------------|-------------|-----------|
| Static Stress | SOL 101 | `.op2` | E3: `extract_solid_stress` |
| Displacement | SOL 101 | `.op2` | E1: `extract_displacement` |
| Natural Frequency | SOL 103 | `.op2` | E2: `extract_frequency` |
| Buckling Load | SOL 105 | `.op2` | `extract_buckling` |
| Modal Shapes | SOL 103 | `.op2` | `extract_mode_shapes` |
| Mass | - | `.dat`/`.bdf` | E4: `bdf_mass_extractor` |
| Stiffness | SOL 101 | `.fld` + `.op2` | E7: `stiffness_calculator` |

---

## Common Objective Formulations

### Stiffness Maximization
- k = F/δ (force/displacement)
- Maximize k or minimize 1/k (compliance)
- Requires consistent load magnitude across trials

### Mass Minimization
- Extract from BDF element properties + material density
- Units: typically kg (NX uses kg-mm-s)

### Stress Constraints
- Von Mises < σ_yield / safety_factor
- Account for stress concentrations

### Frequency Constraints
- f₁ > threshold (avoid resonance)
- Often paired with mass minimization

---

## Adding New Extractors

When the study needs result extraction not covered by existing extractors (E1-E10):

```
STEP 1: Check existing extractors in this catalog
        ├── If exists → IMPORT and USE it (done!)
        └── If missing → Continue to STEP 2

STEP 2: Create extractor in optimization_engine/extractors/
        ├── File: extract_{feature}.py
        ├── Follow existing extractor patterns
        └── Include comprehensive docstrings

STEP 3: Add to __init__.py
        └── Export functions in optimization_engine/extractors/__init__.py

STEP 4: Update this module
        ├── Add to Extractor Catalog table
        └── Add code snippet

STEP 5: Document in SYS_12_EXTRACTOR_LIBRARY.md
```

See [EXT_01_CREATE_EXTRACTOR](../../docs/protocols/extensions/EXT_01_CREATE_EXTRACTOR.md) for full guide.

---

## Cross-References

- **System Protocol**: [SYS_12_EXTRACTOR_LIBRARY](../../docs/protocols/system/SYS_12_EXTRACTOR_LIBRARY.md)
- **Extension Guide**: [EXT_01_CREATE_EXTRACTOR](../../docs/protocols/extensions/EXT_01_CREATE_EXTRACTOR.md)
- **Zernike Extractors**: [zernike-optimization module](./zernike-optimization.md)
- **Core Skill**: [study-creation-core](../core/study-creation-core.md)
