Phase 1 - Session Bootstrap: - Add .claude/ATOMIZER_CONTEXT.md as single entry point for new sessions - Add study state detection and task routing Phase 2 - Code Deduplication: - Add optimization_engine/base_runner.py (ConfigDrivenRunner) - Add optimization_engine/generic_surrogate.py (ConfigDrivenSurrogate) - Add optimization_engine/study_state.py for study detection - Add optimization_engine/templates/ with registry and templates - Studies now require ~50 lines instead of ~300 Phase 3 - Skill Consolidation: - Add YAML frontmatter metadata to all skills (versioning, dependencies) - Consolidate create-study.md into core/study-creation-core.md - Update 00_BOOTSTRAP.md, 01_CHEATSHEET.md, 02_CONTEXT_LOADER.md Phase 4 - Self-Expanding Knowledge: - Add optimization_engine/auto_doc.py for auto-generating documentation - Generate docs/generated/EXTRACTORS.md (27 extractors documented) - Generate docs/generated/TEMPLATES.md (6 templates) - Generate docs/generated/EXTRACTOR_CHEATSHEET.md Phase 5 - Subagent Implementation: - Add .claude/commands/study-builder.md (create studies) - Add .claude/commands/nx-expert.md (NX Open API) - Add .claude/commands/protocol-auditor.md (config validation) - Add .claude/commands/results-analyzer.md (results analysis) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1028 lines
25 KiB
Markdown
1028 lines
25 KiB
Markdown
# 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
|
|
```
|
|
|
|
---
|