# Atomizer Extractor Library

*Auto-generated: 2025-12-07 12:53*

This document is automatically generated from the extractor source code.

---

## Quick Reference

| Extractor | Category | Phase | Description |
|-----------|----------|-------|-------------|
| `check_force_equilibrium` | forces | Phase 2 | Check if reaction forces balance applied loads (equilibrium  |
| `extract_reaction_component` | forces | Phase 2 | Extract maximum absolute value of a specific reaction compon |
| `extract_spc_forces` | forces | Phase 2 | Extract SPC (reaction) forces from boundary conditions. |
| `extract_total_reaction_force` | forces | Phase 2 | Convenience function to extract total reaction force magnitu |
| `extract_frequencies` | general | Phase 3 | Extract natural frequencies from modal analysis F06 file. |
| `extract_part_material` | general | Phase 1 | Convenience function to extract just material info. |
| `PartMassExtractor` | mass | Phase 1 | Class-based extractor for part mass and material with cachin |
| `extract_part_mass` | mass | Phase 1 | Convenience function to extract just the mass in kg. |
| `extract_part_mass_material` | mass | Phase 1 | Extract mass and material properties from NX part file. |
| `extract_modal_mass` | modal | Phase 3 | Extract modal effective mass from F06 file. |
| `get_first_frequency` | modal | Phase 3 | Get first natural frequency from F06 file. |
| `get_modal_mass_ratio` | modal | Phase 3 | Get cumulative modal mass ratio for first n modes. |
| `ZernikeExtractor` | optical | Phase 1 | Complete Zernike analysis extractor for telescope mirror opt |
| `extract_zernike_filtered_rms` | optical | Phase 1 | Extract filtered RMS WFE - the primary metric for mirror opt |
| `extract_zernike_from_op2` | optical | Phase 1 | Convenience function to extract Zernike metrics from OP2. |
| `extract_zernike_relative_rms` | optical | Phase 1 | Extract relative filtered RMS between two subcases. |
| `extract_strain_energy` | strain | Phase 2 | Extract strain energy from structural elements. |
| `extract_strain_energy_density` | strain | Phase 2 | Extract strain energy density (energy per volume). |
| `extract_total_strain_energy` | strain | Phase 2 | Convenience function to extract total strain energy. |
| `extract_max_principal_stress` | stress | Phase 2 | Convenience function to extract maximum principal stress. |
| `extract_min_principal_stress` | stress | Phase 2 | Convenience function to extract minimum principal stress. |
| `extract_principal_stress` | stress | Phase 2 | Extract principal stresses from solid or shell elements. |
| `extract_solid_stress` | stress | Phase 1 | Extract stress from solid elements. |
| `extract_heat_flux` | thermal | Phase 3 | Extract element heat flux from thermal analysis OP2 file. |
| `extract_temperature` | thermal | Phase 3 | Extract nodal temperatures from thermal analysis OP2 file. |
| `extract_temperature_gradient` | thermal | Phase 3 | Extract temperature gradients from thermal analysis. |
| `get_max_temperature` | thermal | Phase 3 | Get maximum temperature from OP2 file. |

---

## Forces Extractors

### `check_force_equilibrium`

**Module**: `optimization_engine.extractors.extract_spc_forces`
**Phase**: Phase 2

**Parameters**:

- `op2_file`
- `applied_load` = `None`
- `tolerance` = `1.0`

**Description**:

```
Check if reaction forces balance applied loads (equilibrium check).

In a valid static analysis, sum of reactions should equal applied loads.

Args:
    op2_file: Path to .op2 file
    applied_load: Optional dict of applied loads {'fx': N, 'fy': N, 'fz': N}
    tolerance: Tolerance for equilibrium check (default 1.0 N)

Returns:
    dict: {
        'in_equilibrium': Boolean,
        'reaction_sum': [fx, fy, fz],
        'imbalance': [dx, dy, dz] (if applied_load provided),
        'max_imbalance': Maximum component imbalance
    }
```

---

### `extract_reaction_component`

**Module**: `optimization_engine.extractors.extract_spc_forces`
**Phase**: Phase 2

**Parameters**:

- `op2_file`
- `component` = `fz`
- `subcase` = `1`

**Description**:

```
Extract maximum absolute value of a specific reaction component.

Args:
    op2_file: Path to .op2 file
    component: 'fx', 'fy', 'fz', 'mx', 'my', 'mz'
    subcase: Subcase ID

Returns:
    Maximum absolute value of the specified component
```

---

### `extract_spc_forces`

**Module**: `optimization_engine.extractors.extract_spc_forces`
**Phase**: Phase 2

**Parameters**:

- `op2_file`
- `subcase` = `1`
- `component` = `total`

**Description**:

```
Extract SPC (reaction) forces from boundary conditions.

SPC forces are the reaction forces at constrained nodes. They balance
the applied loads and indicate load path through the structure.

Args:
    op2_file: Path to .op2 file
    subcase: Subcase ID (default 1)
    component: Which component(s) to return:
        - 'total': Resultant force magnitude (sqrt(fx^2+fy^2+fz^2))
        - 'fx', 'fy', 'fz': Individual force components
        - 'mx', 'my', 'mz': Individual moment components
        - 'force': Vector sum of forces only
        - 'moment': Vector sum of moments only

Returns:
    dict: {
        'total_reaction': Total reaction force magnitude,
        'max_reaction': Maximum nodal reaction,
        'max_reaction_node': Node ID with max reaction,
        'sum_fx': Sum of Fx at all nodes,
        'sum_fy': Sum of Fy at all nodes,
        'sum_fz': Sum of Fz at all nodes,
        'sum_mx': Sum of Mx at all nodes,
        'sum_my': Sum of My at all nodes,
        'sum_mz': Sum of Mz at all nodes,
        'node_reactions': Dict of {node_id: [fx,fy,fz,mx,my,mz]},
        'num_constrained_nodes': Number of nodes with SPCs,
        'subcase': Subcase ID,
        'units': 'N, N-mm (model units)'
    }

Example:
    >>> result = extract_spc_forces('model.op2')
    >>> print(f"Total reaction: {result['total_reaction']:.2f} N")
    >>> print(f"Sum Fz: {result['sum_fz']:.2f} N")
```

---

### `extract_total_reaction_force`

**Module**: `optimization_engine.extractors.extract_spc_forces`
**Phase**: Phase 2

**Parameters**:

- `op2_file`
- `subcase` = `1`

**Description**:

```
Convenience function to extract total reaction force magnitude.

Args:
    op2_file: Path to .op2 file
    subcase: Subcase ID

Returns:
    Total reaction force magnitude (N)
```

---

## General Extractors

### `extract_frequencies`

**Module**: `optimization_engine.extractors.extract_modal_mass`
**Phase**: Phase 3

**Parameters**:

- `f06_file`
- `n_modes` = `None`

**Description**:

```
Extract natural frequencies from modal analysis F06 file.

Simpler version of extract_modal_mass that just gets frequencies.

Args:
    f06_file: Path to F06 file
    n_modes: Number of modes to extract (default: all)

Returns:
    dict: {
        'success': bool,
        'frequencies': list of frequencies in Hz,
        'mode_count': int,
        'first_frequency': float,
        'error': str or None
    }
```

---

### `extract_part_material`

**Module**: `optimization_engine.extractors.extract_part_mass_material`
**Phase**: Phase 1

**Parameters**:

- `prt_file`
- `properties_file` = `None`

**Description**:

```
Convenience function to extract just material info.

Args:
    prt_file: Path to .prt file
    properties_file: Optional explicit path to temp file

Returns:
    Dictionary with 'name', 'density', 'density_unit'

Example:
    >>> mat = extract_part_material('model.prt')
    >>> print(f"Material: {mat['name']}, Density: {mat['density']}")
    Material: Steel_304, Density: 7.93e-06
```

---

## Mass Extractors

### `PartMassExtractor`

**Module**: `optimization_engine.extractors.extract_part_mass_material`
**Phase**: Phase 1

**Parameters**:

- `prt_file`
- `properties_file` = `None`

**Description**:

```
Class-based extractor for part mass and material with caching.

Use this when you need to extract properties from multiple parts
or want to cache results.

Example:
    >>> extractor = PartMassExtractor('model.prt')
    >>> result = extractor.extract()
    >>> print(result['mass_kg'])
    1.234
```

---

### `extract_part_mass`

**Module**: `optimization_engine.extractors.extract_part_mass_material`
**Phase**: Phase 1

**Parameters**:

- `prt_file`
- `properties_file` = `None`

**Description**:

```
Convenience function to extract just the mass in kg.

Args:
    prt_file: Path to .prt file
    properties_file: Optional explicit path to temp file

Returns:
    Mass in kilograms (float)

Example:
    >>> mass = extract_part_mass('model.prt')
    >>> print(f"Mass: {mass:.3f} kg")
    Mass: 1.234 kg
```

---

### `extract_part_mass_material`

**Module**: `optimization_engine.extractors.extract_part_mass_material`
**Phase**: Phase 1

**Parameters**:

- `prt_file`
- `properties_file` = `None`

**Description**:

```
Extract mass and material properties from NX part file.

This function reads from a temp JSON file that must be created by
running the NX journal: nx_journals/extract_part_mass_material.py

Args:
    prt_file: Path to .prt file (used to locate temp file)
    properties_file: Optional explicit path to _temp_part_properties.json
                    If not provided, looks in same directory as prt_file

Returns:
    Dictionary containing:
    - 'mass_kg': Mass in kilograms (float)
    - 'mass_g': Mass in grams (float)
    - 'volume_mm3': Volume in mm^3 (float)
    - 'surface_area_mm2': Surface area in mm^2 (float)
    - 'center_of_gravity_mm': [x, y, z] in mm (list)
    - 'moments_of_inertia': {'Ixx', 'Iyy', 'Izz', 'unit'} or None
    - 'material': {'name', 'density', 'density_unit'} (dict)
    - 'num_bodies': Number of solid bodies (int)

Raises:
    FileNotFoundError: If prt file or temp properties file not found
    ValueError: If temp file has invalid format or extraction failed

Example:
    >>> result = extract_part_mass_material('model.prt')
    >>> print(f"Mass: {result['mass_kg']:.3f} kg")
    Mass: 1.234 kg
    >>> print(f"Material: {result['material']['name']}")
    Material: Aluminum_6061

Note:
    Before calling this function, you must run the NX journal to
    create the temp file:
    ```
    run_journal.exe extract_part_mass_material.py model.prt
    ```
```

---

## Modal Extractors

### `extract_modal_mass`

**Module**: `optimization_engine.extractors.extract_modal_mass`
**Phase**: Phase 3

**Parameters**:

- `f06_file`
- `mode` = `None`
- `direction` = `all`

**Description**:

```
Extract modal effective mass from F06 file.

Modal effective mass indicates how much of the total mass participates
in each mode for each direction. Important for:
- Base excitation problems
- Seismic analysis
- Random vibration

Args:
    f06_file: Path to the F06 results file
    mode: Mode number to extract (1-indexed). If None, returns all modes.
    direction: Direction(s) to extract:
               'x', 'y', 'z' - single direction
               'all' - all directions (default)
               'total' - sum of all directions

Returns:
    dict: {
        'success': bool,
        'modes': list of mode data (if mode=None),
        'modal_mass_x': float (kg) - effective mass in X,
        'modal_mass_y': float (kg) - effective mass in Y,
        'modal_mass_z': float (kg) - effective mass in Z,
        'modal_mass_rx': float (kg·m²) - rotational mass about X,
        'modal_mass_ry': float (kg·m²) - rotational mass about Y,
        'modal_mass_rz': float (kg·m²) - rotational mass about Z,
        'participation_x': float (0-1) - participation factor X,
        'participation_y': float (0-1) - participation factor Y,
        'participation_z': float (0-1) - participation factor Z,
        'frequency': float (Hz) - natural frequency,
        'cumulative_mass_x': float - cumulative mass fraction X,
        'cumulative_mass_y': float - cumulative mass fraction Y,
        'cumulative_mass_z': float - cumulative mass fraction Z,
        'total_mass': float (kg) - total model mass,
        'error': str or None
    }

Example:
    >>> result = extract_modal_mass("modal_analysis.f06", mode=1)
    >>> if result['success']:
    ...     print(f"Mode 1 frequency: {result['frequency']:.2f} Hz")
    ...     print(f"X participation: {result['participation_x']*100:.1f}%")
```

---

### `get_first_frequency`

**Module**: `optimization_engine.extractors.extract_modal_mass`
**Phase**: Phase 3

**Parameters**:

- `f06_file`

**Description**:

```
Get first natural frequency from F06 file.

Convenience function for optimization constraints.
Returns 0 if extraction fails.

Args:
    f06_file: Path to F06 file

Returns:
    float: First natural frequency in Hz, or 0 on failure
```

---

### `get_modal_mass_ratio`

**Module**: `optimization_engine.extractors.extract_modal_mass`
**Phase**: Phase 3

**Parameters**:

- `f06_file`
- `direction` = `z`
- `n_modes` = `10`

**Description**:

```
Get cumulative modal mass ratio for first n modes.

This indicates what fraction of total mass participates in the
first n modes. Important for determining if enough modes are included.

Args:
    f06_file: Path to F06 file
    direction: Direction ('x', 'y', or 'z')
    n_modes: Number of modes to include

Returns:
    float: Cumulative mass ratio (0-1), or 0 on failure
```

---

## Optical Extractors

### `ZernikeExtractor`

**Module**: `optimization_engine.extractors.extract_zernike`
**Phase**: Phase 1

**Parameters**:

- `op2_path`
- `bdf_path` = `None`
- `displacement_unit` = `mm`
- `n_modes` = `50`
- `filter_orders` = `4`

**Description**:

```
Complete Zernike analysis extractor for telescope mirror optimization.

This class handles:
- Loading OP2 displacement results
- Matching with BDF geometry
- Computing Zernike coefficients and RMS metrics
- Multi-subcase analysis (different gravity orientations)
- Relative metrics between subcases

Example usage in optimization:
    extractor = ZernikeExtractor(op2_file, bdf_file)

    # For single-objective optimization (minimize filtered RMS at 20 deg)
    result = extractor.extract_subcase('20')
    objective = result['filtered_rms_nm']

    # For multi-subcase optimization
    all_results = extractor.extract_all_subcases()
```

---

### `extract_zernike_filtered_rms`

**Module**: `optimization_engine.extractors.extract_zernike`
**Phase**: Phase 1

**Parameters**:

- `op2_file`
- `bdf_file` = `None`
- `subcase` = `1`
- `kwargs`

**Description**:

```
Extract filtered RMS WFE - the primary metric for mirror optimization.

Filtered RMS removes piston, tip, tilt, and defocus (modes 1-4),
which can be corrected by alignment and focus adjustment.

Args:
    op2_file: Path to OP2 file
    bdf_file: Path to BDF geometry (auto-detected if None)
    subcase: Subcase identifier
    **kwargs: Additional arguments for ZernikeExtractor

Returns:
    Filtered RMS WFE in nanometers
```

---

### `extract_zernike_from_op2`

**Module**: `optimization_engine.extractors.extract_zernike`
**Phase**: Phase 1

**Parameters**:

- `op2_file`
- `bdf_file` = `None`
- `subcase` = `1`
- `displacement_unit` = `mm`
- `n_modes` = `50`
- `filter_orders` = `4`

**Description**:

```
Convenience function to extract Zernike metrics from OP2.

This is the main entry point for optimization objectives.

Args:
    op2_file: Path to OP2 results file
    bdf_file: Path to BDF geometry (auto-detected if None)
    subcase: Subcase identifier
    displacement_unit: Unit of displacement in OP2
    n_modes: Number of Zernike modes
    filter_orders: Low-order modes to filter

Returns:
    Dict with:
    - 'global_rms_nm': Global RMS WFE in nanometers
    - 'filtered_rms_nm': Filtered RMS (low orders removed)
    - 'defocus_nm', 'astigmatism_rms_nm', etc.: Individual aberrations
```

---

### `extract_zernike_relative_rms`

**Module**: `optimization_engine.extractors.extract_zernike`
**Phase**: Phase 1

**Parameters**:

- `op2_file`
- `target_subcase`
- `reference_subcase`
- `bdf_file` = `None`
- `kwargs`

**Description**:

```
Extract relative filtered RMS between two subcases.

Useful for analyzing gravity-induced deformation relative to
a reference orientation (e.g., polishing position).

Args:
    op2_file: Path to OP2 file
    target_subcase: Subcase to analyze
    reference_subcase: Reference subcase
    bdf_file: Path to BDF geometry
    **kwargs: Additional arguments for ZernikeExtractor

Returns:
    Relative filtered RMS WFE in nanometers
```

---

## Strain Extractors

### `extract_strain_energy`

**Module**: `optimization_engine.extractors.extract_strain_energy`
**Phase**: Phase 2

**Parameters**:

- `op2_file`
- `subcase` = `1`
- `element_type` = `None`
- `top_n` = `10`

**Description**:

```
Extract strain energy from structural elements.

Strain energy (U) is a measure of the work done to deform the structure:
U = 0.5 * integral(sigma * epsilon) dV

High strain energy density indicates highly stressed regions.

Args:
    op2_file: Path to .op2 file
    subcase: Subcase ID (default 1)
    element_type: Filter by element type (e.g., 'ctetra', 'chexa', 'cquad4')
                 If None, returns total from all elements
    top_n: Number of top elements to return by strain energy

Returns:
    dict: {
        'total_strain_energy': Total strain energy (all elements),
        'mean_strain_energy': Mean strain energy per element,
        'max_strain_energy': Maximum element strain energy,
        'max_energy_element': Element ID with max strain energy,
        'top_elements': List of (element_id, energy) tuples,
        'energy_by_type': Dict of {element_type: total_energy},
        'num_elements': Total element count,
        'subcase': Subcase ID,
        'units': 'N-mm (model units)'
    }

Example:
    >>> result = extract_strain_energy('model.op2')
    >>> print(f"Total strain energy: {result['total_strain_energy']:.2f} N-mm")
    >>> print(f"Highest energy element: {result['max_energy_element']}")
```

---

### `extract_strain_energy_density`

**Module**: `optimization_engine.extractors.extract_strain_energy`
**Phase**: Phase 2

**Parameters**:

- `op2_file`
- `subcase` = `1`
- `element_type` = `ctetra`

**Description**:

```
Extract strain energy density (energy per volume).

Strain energy density is useful for identifying critical regions
and for material utilization optimization.

Args:
    op2_file: Path to .op2 file
    subcase: Subcase ID
    element_type: Element type to analyze

Returns:
    dict: {
        'max_density': Maximum strain energy density,
        'mean_density': Mean strain energy density,
        'total_energy': Total strain energy,
        'units': 'N/mm^2 (MPa equivalent)'
    }

Note:
    This requires element volume data which may not always be available.
    Falls back to energy-only metrics if volume is unavailable.
```

---

### `extract_total_strain_energy`

**Module**: `optimization_engine.extractors.extract_strain_energy`
**Phase**: Phase 2

**Parameters**:

- `op2_file`
- `subcase` = `1`

**Description**:

```
Convenience function to extract total strain energy.

Args:
    op2_file: Path to .op2 file
    subcase: Subcase ID

Returns:
    Total strain energy (N-mm)
```

---

## Stress Extractors

### `extract_max_principal_stress`

**Module**: `optimization_engine.extractors.extract_principal_stress`
**Phase**: Phase 2

**Parameters**:

- `op2_file`
- `subcase` = `1`
- `element_type` = `ctetra`

**Description**:

```
Convenience function to extract maximum principal stress.

Args:
    op2_file: Path to .op2 file
    subcase: Subcase ID
    element_type: Element type

Returns:
    Maximum principal stress value (tension positive)
```

---

### `extract_min_principal_stress`

**Module**: `optimization_engine.extractors.extract_principal_stress`
**Phase**: Phase 2

**Parameters**:

- `op2_file`
- `subcase` = `1`
- `element_type` = `ctetra`

**Description**:

```
Convenience function to extract minimum principal stress.

For solid elements, returns sigma3 (most compressive).
For shell elements, returns sigma2.

Args:
    op2_file: Path to .op2 file
    subcase: Subcase ID
    element_type: Element type

Returns:
    Minimum principal stress value (compression negative)
```

---

### `extract_principal_stress`

**Module**: `optimization_engine.extractors.extract_principal_stress`
**Phase**: Phase 2

**Parameters**:

- `op2_file`
- `subcase` = `1`
- `element_type` = `ctetra`
- `principal` = `max`

**Description**:

```
Extract principal stresses from solid or shell elements.

Principal stresses are the eigenvalues of the stress tensor,
ordered as: sigma1 >= sigma2 >= sigma3 (o1 >= o2 >= o3)

Args:
    op2_file: Path to .op2 file
    subcase: Subcase ID (default 1)
    element_type: Element type ('ctetra', 'chexa', 'cquad4', 'ctria3')
    principal: Which principal stress to return:
        - 'max': Maximum principal (sigma1, tension positive)
        - 'mid': Middle principal (sigma2)
        - 'min': Minimum principal (sigma3, compression negative)
        - 'all': Return all three principals

Returns:
    dict: {
        'max_principal': Maximum principal stress value,
        'min_principal': Minimum principal stress value,
        'mid_principal': Middle principal stress (if applicable),
        'max_element': Element ID with maximum principal,
        'min_element': Element ID with minimum principal,
        'von_mises_max': Max von Mises for comparison,
        'element_type': Element type used,
        'subcase': Subcase ID,
        'units': 'MPa (model units)'
    }

Example:
    >>> result = extract_principal_stress('model.op2', element_type='ctetra')
    >>> print(f"Max tension: {result['max_principal']:.2f} MPa")
    >>> print(f"Max compression: {result['min_principal']:.2f} MPa")
```

---

### `extract_solid_stress`

**Module**: `optimization_engine.extractors.extract_von_mises_stress`
**Phase**: Phase 1

**Parameters**:

- `op2_file`
- `subcase` = `1`
- `element_type` = `ctetra`

**Description**:

```
Extract stress from solid elements.
```

---

## Thermal Extractors

### `extract_heat_flux`

**Module**: `optimization_engine.extractors.extract_temperature`
**Phase**: Phase 3

**Parameters**:

- `op2_file`
- `subcase` = `1`
- `element_type` = `all`

**Description**:

```
Extract element heat flux from thermal analysis OP2 file.

Args:
    op2_file: Path to the OP2 results file
    subcase: Subcase number
    element_type: Element type to extract ('all', 'ctetra', 'chexa', etc.)

Returns:
    dict: {
        'success': bool,
        'max_heat_flux': float (W/mm² or model units),
        'min_heat_flux': float,
        'avg_heat_flux': float,
        'max_element_id': int,
        'element_count': int,
        'unit': str,
        'error': str or None
    }
```

---

### `extract_temperature`

**Module**: `optimization_engine.extractors.extract_temperature`
**Phase**: Phase 3

**Parameters**:

- `op2_file`
- `subcase` = `1`
- `nodes` = `None`
- `return_field` = `False`

**Description**:

```
Extract nodal temperatures from thermal analysis OP2 file.

Args:
    op2_file: Path to the OP2 results file
    subcase: Subcase number to extract (default: 1)
    nodes: Optional list of specific node IDs to extract.
           If None, extracts all nodes.
    return_field: If True, include full temperature field in result

Returns:
    dict: {
        'success': bool,
        'max_temperature': float (K or °C depending on model units),
        'min_temperature': float,
        'avg_temperature': float,
        'max_node_id': int (node with max temperature),
        'min_node_id': int (node with min temperature),
        'node_count': int,
        'temperatures': dict (node_id: temp) - only if return_field=True,
        'unit': str ('K' or 'C'),
        'subcase': int,
        'error': str or None
    }

Example:
    >>> result = extract_temperature("thermal_analysis.op2", subcase=1)
    >>> if result['success']:
    ...     print(f"Max temp: {result['max_temperature']:.1f} K at node {result['max_node_id']}")
    ...     print(f"Temperature range: {result['min_temperature']:.1f} - {result['max_temperature']:.1f} K")
```

---

### `extract_temperature_gradient`

**Module**: `optimization_engine.extractors.extract_temperature`
**Phase**: Phase 3

**Parameters**:

- `op2_file`
- `subcase` = `1`
- `method` = `nodal_difference`

**Description**:

```
Extract temperature gradients from thermal analysis.

Computes temperature gradients based on nodal temperature differences.
This is useful for identifying thermal stress hot spots.

Args:
    op2_file: Path to the OP2 results file
    subcase: Subcase number
    method: Gradient calculation method:
            - 'nodal_difference': Max temperature difference between adjacent nodes
            - 'element_based': Gradient within elements (requires mesh connectivity)

Returns:
    dict: {
        'success': bool,
        'max_gradient': float (K/mm or temperature units/length),
        'avg_gradient': float,
        'temperature_range': float (max - min temperature),
        'gradient_location': tuple (node_id_hot, node_id_cold),
        'error': str or None
    }

Note:
    For accurate gradients, element-based calculation requires mesh connectivity
    which may not be available in all OP2 files. The nodal_difference method
    provides an approximation based on temperature range.
```

---

### `get_max_temperature`

**Module**: `optimization_engine.extractors.extract_temperature`
**Phase**: Phase 3

**Parameters**:

- `op2_file`
- `subcase` = `1`

**Description**:

```
Get maximum temperature from OP2 file.

Convenience function for use in optimization constraints.
Returns inf if extraction fails.

Args:
    op2_file: Path to OP2 file
    subcase: Subcase number

Returns:
    float: Maximum temperature or inf on failure
```

---
