# FEA Results Guide

## Overview

This guide explains how to extract and organize finite element analysis results in OpenBrIM using ParamML expressions. After running FEA analyses, results must be queried and organized for design checks, reports, and code compliance verification.

**Key Concepts:**

* **Result Functions**: ParamML functions that query analysis results (`stress()`, `force()`, `forcePos()`, `forceNeg()`, etc.)
* **Limit State Organization**: Structuring results by AASHTO limit states (Strength, Service, Fatigue, Extreme Event)
* **Envelope Results**: Combined max/min results across multiple load cases
* **Concurrent Forces**: Extracting all force components when one component governs
* **Multi-Station Extraction**: Using `map()` to extract results at multiple locations efficiently

## Core Result Extraction Functions

### 1. Force Extraction Functions

#### `force(elementPath, loadCase, component, station?)`

Extracts a specific force component from analysis results.

**Parameters:**

* `elementPath` (String): Full path to the FE element (use `fullname()` for dynamic paths)
* `loadCase` (String): Load case or combination name
* `component` (String): Force component ('Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz')
* `station` (Number, optional): Station location along element

**Returns:** Number - Force value in the specified component

**Example:**

```xml
<P N="Moment" V="force(Girder.N + '.MainSpan', 'DeadLoad', 'My', 600)"/>
<!-- Gets My moment at station 600 for DeadLoad case -->
```

***

#### `forcePos(component, elementPath, loadCase, station?)`

Extracts the maximum (positive) value for a specific force component.

**Parameters:**

* `component` (String): Force component ('Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz')
* `elementPath` (String): Full path to the FE element
* `loadCase` (String): Load case or combination name
* `station` (Number, optional): Station location

**Returns:** Number - Maximum (positive) force value

**Example:**

```xml
<P N="MaxPositiveMoment" V="forcePos('My', fullname(Girder) + '.Comb', 'LiveLoad', Station)"/>
```

**Related:** `forceNeg()`, `forceFxPosConc()`, `forceFyPosConc()`, `forceFzPosConc()`, `forceMxPosConc()`, `forceMyPosConc()`, `forceMzPosConc()`

***

#### `forceNeg(component, elementPath, loadCase, station?)`

Extracts the minimum (negative) value for a specific force component.

**Parameters:**

* `component` (String): Force component ('Fx', 'Fy', 'Fz', 'Mx', 'My', 'Mz')
* `elementPath` (String): Full path to the FE element
* `loadCase` (String): Load case or combination name
* `station` (Number, optional): Station location

**Returns:** Number - Minimum (negative) force value

**Example:**

```xml
<P N="MaxNegativeMoment" V="forceNeg('My', Girder.N + '.MainSpan', 'DeadLoad', 600)"/>
```

**Related:** `forcePos()`, `forceFxNegConc()`, `forceFyNegConc()`, `forceFzNegConc()`, `forceMxNegConc()`, `forceMyNegConc()`, `forceMzNegConc()`

***

#### Concurrent Force Functions

These functions extract ALL force components when a specific component reaches its maximum/minimum value.

**Function Pattern:**

* `forceFxPosConc(loadCase, element, station, concElement, concStation)` - All forces when Fx is maximum positive
* `forceFxNegConc(loadCase, element, station, concElement, concStation)` - All forces when Fx is maximum negative
* Similar functions for: `Fy`, `Fz`, `Mx`, `My`, `Mz`

**Parameters:**

* `loadCase` (String): Load case or combination name
* `element` (String): Element path for the component being maximized
* `station` (Number): Station for the component being maximized
* `concElement` (String): Element path for concurrent forces extraction
* `concStation` (Number): Station for concurrent forces extraction

**Returns:** Array `[Fx, Fy, Fz, Mx, My, Mz]` - All force components at the concurrent location when the primary component governs

**Example:**

```xml
<!-- Get all forces at midspan when Fx at midspan is maximum positive -->
<P N="ConcurrentForces" V="forceFxPosConc('StrengthI_Max', Girder.N, 600, Girder.N, 600)"/>
<!-- Result: [Fx_max, Fy_concurrent, Fz_concurrent, Mx_concurrent, My_concurrent, Mz_concurrent] -->

<!-- Get forces at quarterspan when moment at midspan is maximum -->
<P N="ConcurrentAtQuarter" V="forceMyPosConc('StrengthI_Max', Girder.N, 600, Girder.N, 300)"/>
<!-- Result: All forces at station 300 when My at station 600 is maximum -->
```

**Use Cases:**

* Design checks requiring concurrent forces (e.g., P-M interaction)
* Extracting shear when moment governs
* Combined stress calculations

***

### 2. Stress Extraction Functions

#### `stress(loadCase, element, station?)`

Extracts stress components from analysis results.

**Parameters:**

* `loadCase` (String): Load case or combination name
* `element` (String): Element path or identifier
* `station` (Number, optional): Station location

**Returns:** Array `[σxx, σyy, σzz, τxy, τyz, τzx]` - Stress tensor components

**Example:**

```xml
<P N="StressResults" V="stress('ServiceI_Max', FEComp_Description, Station)"/>
<P N="NormalStress" V="stress('ServiceI_Max', FEComp_Description, Station)[0]"/>
```

**Note:** Stress results depend on element type and location (integration points, nodes, etc.)

***

### 3. Displacement Extraction Functions

#### `disp(node, loadCase, component)`

Extracts nodal displacement for a specific component.

**Parameters:**

* `node` (String): Node name or path
* `loadCase` (String): Load case or combination name
* `component` (String): Displacement component ('Tx', 'Ty', 'Tz', 'Rx', 'Ry', 'Rz')

**Returns:** Number - Displacement value

**Example:**

```xml
<P N="VerticalDeflection" V="disp('MidspanNode', 'LiveLoad', 'Tz')"/>
```

**Related:** `dispX()`, `dispY()`, `dispZ()` - Component-specific functions

***

## Result Organization Patterns

### 1. Multi-Station Extraction

Use `map()` to extract results at multiple stations efficiently.

**Pattern:**

```xml
<P N="StationList" V="[0, 300, 600, 900, 1200]"/>
<P N="MomentsAtStations" V="map(StationList, force(ElementPath, LoadCase, 'My', x))"/>
```

**Nested Pattern - Multiple Load Cases at Multiple Stations:**

```xml
<P N="StationList" V="[0, 300, 600, 900, 1200]"/>
<P N="LoadCaseList" V="[LC1, LC2, LC3]"/>

<!-- Result structure: [[station1 results], [station2 results], ...] -->
<!-- Each station: [[case1 result], [case2 result], ...] -->
<P N="ResultsGrid" V="map(StationList, j =>
    map(LoadCaseList, force(x.N, ElementPath, 'My', j))
)"/>
```

***

### 2. Limit State Organization

AASHTO LRFD limit states should be organized hierarchically.

**Structure:**

```xml
<O N="Results" T="Group">
  <O N="UnfactoredResults" T="Group">
    <!-- Results from individual unfactored load cases -->
  </O>

  <O N="FactoredResults" T="Group">
    <!-- Results from factored load combinations -->
  </O>

  <O N="GoverningResults" T="Group">
    <!-- Min/max across all combinations -->
  </O>

  <O N="EnvelopeResults" T="Group">
    <!-- Envelope combinations -->
  </O>
</O>
```

***

### 3. Unfactored Results Pattern

Extract results from individual load cases grouped by limit state.

**Example:**

```xml
<O N="UnfactoredCases" T="Group">
  <!-- Extract unique load cases from limit state table -->
  <P N="Str1CaseList" V="iif(DesignComb.StrengthI.EQ.NULL, [], DesignComb.StrengthI.SortedStateList)"/>
  <P N="Srv1CaseList" V="iif(DesignComb.ServiceI.EQ.NULL, [], DesignComb.ServiceI.SortedStateList)"/>

  <!-- Combine and deduplicate -->
  <P N="AllCaseList" V="filter([Str1CaseList, Srv1CaseList], length(x) != 0)"/>
  <P N="FilteredAllCases" V="removedup(mergel(map(AllCaseList, j => map(j, [x[0], x[1], x[4]]))), x[0])"/>
</O>

<O N="UnfactoredResults" T="Group">
  <!-- Extract results for all cases at all stations -->
  <P N="R_AllCasesPos" V="map(StationList, j =>
      map(FilteredAllCases, iif(x[0].EQ.NULL,
          [[NULL,NULL,NULL,NULL,NULL,NULL], NULL],
          [stress(x.N + CoreCombName, FEComp_Description, j), x[1], x[2]]
      ))
  )"/>

  <!-- Results by limit state -->
  <P N="R_Str1CasesPos" V="map(StationList, j =>
      map(Str1CaseList, iif(x[0].EQ.NULL,
          [[NULL,NULL,NULL,NULL,NULL,NULL], NULL],
          [stress(x[0].N + CoreCombName, FEComp_Description, j), x[1], x[4]]
      ))
  )"/>
</O>
```

**Result Structure:**

```
[Station1, Station2, Station3, ...]
Each Station: [[Case1 Result], [Case2 Result], ...]
Each Case Result: [[σxx, σyy, σzz, τxy, τyz, τzx], LoadTypeEnum, EnumDescription]
```

***

### 4. Factored Results Pattern

Extract results from factored load combinations (max and min envelopes).

**Example:**

```xml
<O N="FactoredCases" T="Group">
  <O N="str1" T="Group" Guard="StrengthI == 1">
    <P N="str1Max_LC" V="DesignComb.strength1max"/>
    <P N="str1Min_LC" V="DesignComb.strength1min"/>
  </O>
  <O N="srv1" T="Group" Guard="ServiceI == 1">
    <P N="srv1Max_LC" V="DesignComb.service1max"/>
    <P N="srv1Min_LC" V="DesignComb.service1min"/>
  </O>
</O>

<O N="FactoredResults" T="Group">
  <O N="str1" T="Group" Guard="StrengthI == 1">
    <P N="R_str1PosMax" V="map(StationList, iif(str1Max_LC == NULL,
        [NULL,NULL,NULL,NULL,NULL,NULL],
        stress(str1Max_LC, FEComp_Description, x)
    ))"/>

    <P N="R_str1PosMin" V="map(StationList, iif(str1Min_LC == NULL,
        [NULL,NULL,NULL,NULL,NULL,NULL],
        stress(str1Min_LC, FEComp_Description, x)
    ))"/>
  </O>
</O>
```

***

### 5. Governing Results Pattern

Extract the absolute min/max across multiple load combinations.

**Example:**

```xml
<O N="GoverningResults" T="Group">
  <O N="str1" T="Group" Guard="StrengthI == 1">
    <!-- Component-wise min across all Strength I combinations -->
    <P N="R_str1GoverningMin" V="map(R_str1PosMax, j =>
        map(j, k => min(k, R_str1PosMin[ji][ki]))
    )"/>

    <!-- Component-wise max across all Strength I combinations -->
    <P N="R_str1GoverningMax" V="map(R_str1PosMax, j =>
        map(j, k => max(k, R_str1PosMin[ji][ki]))
    )"/>
  </O>

  <!-- Overall strength envelope across all strength limit states -->
  <O N="str" T="Group" Guard="StrengthI == 1 || StrengthII == 1 || ...">
    <P N="R_strGoverningMin" V="map(StationList, iif(strEnv_LC == NULL,
        [NULL,NULL,NULL,NULL,NULL,NULL],
        stress(strEnv_LC, FEComp_Description, x)
    ))"/>

    <P N="R_strGoverningMax" V="map(StationList, iif(strEnv_LC == NULL,
        [NULL,NULL,NULL,NULL,NULL,NULL],
        stress(strEnv_LC, FEComp_Description, x)
    ))"/>
  </O>
</O>
```

**Sorting Pattern for Concurrent Forces:**

```xml
<!-- Find governing based on primary component (e.g., Fx) -->
<P N="R_str1GoverningMin" V="map(StationList, j =>
    sort([R_str1PosMax[ji], R_str1NegMax[ji], R_str1PosMin[ji], R_str1NegMin[ji]], x[0])[0]
)"/>

<P N="R_str1GoverningMax" V="map(StationList, j =>
    sort([R_str1PosMax[ji], R_str1NegMax[ji], R_str1PosMin[ji], R_str1NegMin[ji]], x[0])[3]
)"/>
```

***

### 6. Concurrent Force Extraction Pattern

Extract all force components when one component governs.

**Pattern:**

```xml
<O N="UnfactoredResults" T="Group">
  <!-- Extract concurrent forces when Fx governs (positive) -->
  <P N="R_FxPosConc" V="map(StationList, j =>
      map(LoadCaseList, iif(x[0] == NULL,
          [[NULL,NULL,NULL,NULL,NULL,NULL], NULL],
          [forceFxPosConc(x[0].N + CoreCombName, FEComp_Description, j, FEComp_Description, j), x[1], x[4]]
      ))
  )"/>

  <!-- Extract concurrent forces when Fx governs (negative) -->
  <P N="R_FxNegConc" V="map(StationList, j =>
      map(LoadCaseList, iif(x[0] == NULL,
          [[NULL,NULL,NULL,NULL,NULL,NULL], NULL],
          [forceFxNegConc(x[0].N + CoreCombName, FEComp_Description, j, FEComp_Description, j), x[1], x[4]]
      ))
  )"/>
</O>

<O N="FactoredResults" T="Group">
  <!-- Concurrent forces for factored max combination -->
  <P N="R_str1FxPosMax" V="map(StationList, iif(str1Max_LC == NULL,
      [NULL,NULL,NULL,NULL,NULL,NULL],
      forceFxPosConc(str1Max_LC, FEComp_Description, x, FEComp_Description, x)
  ))"/>

  <!-- Concurrent forces for factored min combination -->
  <P N="R_str1FxPosMin" V="map(StationList, iif(str1Min_LC == NULL,
      [NULL,NULL,NULL,NULL,NULL,NULL],
      forceFxPosConc(str1Min_LC, FEComp_Description, x, FEComp_Description, x)
  ))"/>
</O>
```

**Result Structure:**

```
[Station1, Station2, Station3, ...]
Each Station: [Fx, Fy, Fz, Mx, My, Mz]
```

Where `Fx` is the governing (max or min) value, and Fy, Fz, Mx, My, Mz are concurrent values.

***

## Complete Extraction Object Example

### Stress Extraction Object

```xml
<O N="OBPBase_FECompositeStressExtraction" T="Project">
  <O N="Inputs" T="Group">
    <P N="DesignComb_Input" V="NULL" T="OBPAASHTOLimitStateTable" Role="Input"/>
    <P N="FEComp_Description" V="|Object_Input.N+FEDesc|" T="Text" Role="Input"/>
    <P N="StationList_Input" V="[50*12, 75*12]" Role="Input" UT="Length"/>
  </O>

  <O N="UnfactoredCases" T="Group">
    <!-- Extract case lists from limit state table -->
    <P N="Str1CaseList" V="iif(DesignComb_Input.StrengthI_Input == NULL,
        [], DesignComb_Input.StrengthI_Input.SortedStateList)"/>
    <P N="Srv1CaseList" V="iif(DesignComb_Input.ServiceI_Input == NULL,
        [], DesignComb_Input.ServiceI_Input.SortedStateList)"/>

    <!-- Combine and deduplicate -->
    <P N="AllCaseList" V="filter([Str1CaseList, Srv1CaseList, ...], length(x) != 0)"/>
    <P N="FilteredAllCases" V="removedup(mergel(map(AllCaseList, j => map(j, [x[0], x[1], x[4]]))), x[0])"/>
    <P N="CoreCombName" V="DesignComb_Input.CaseName"/>
  </O>

  <O N="FactoredCases" T="Group">
    <P N="str1Max_LC" V="DesignComb_Input.strength1max"/>
    <P N="str1Min_LC" V="DesignComb_Input.strength1min"/>
    <P N="srv1Max_LC" V="DesignComb_Input.service1max"/>
    <P N="srv1Min_LC" V="DesignComb_Input.service1min"/>
  </O>

  <O N="UnfactoredResults" T="Group">
    <P N="R_Str1CasesPos" V="map(StationList_Input, j =>
        map(Str1CaseList, iif(x[0] == NULL,
            [[NULL,NULL,NULL,NULL,NULL,NULL], NULL],
            [stress(x[0].N + CoreCombName, FEComp_Description, j), x[1], x[4]]
        ))
    )"/>
  </O>

  <O N="FactoredResults" T="Group">
    <P N="R_str1PosMax" V="map(StationList_Input, iif(str1Max_LC == NULL,
        [NULL,NULL,NULL,NULL,NULL,NULL],
        stress(str1Max_LC, FEComp_Description, x)
    ))"/>

    <P N="R_str1PosMin" V="map(StationList_Input, iif(str1Min_LC == NULL,
        [NULL,NULL,NULL,NULL,NULL,NULL],
        stress(str1Min_LC, FEComp_Description, x)
    ))"/>
  </O>

  <O N="GoverningResults" T="Group">
    <P N="R_str1GoverningMin" V="map(R_str1PosMax, j =>
        map(j, k => min(k, R_str1PosMin[ji][ki]))
    )"/>

    <P N="R_str1GoverningMax" V="map(R_str1PosMax, j =>
        map(j, k => max(k, R_str1PosMin[ji][ki]))
    )"/>
  </O>
</O>
```

***

### Force Extraction Object

```xml
<O N="OBPBase_FECompositeForceExtractionPerLimitState" T="Project">
  <O N="Inputs" T="Group">
    <P N="DesignComb_Input" V="NULL" T="OBPAASHTOLimitStateTable" Role="Input"/>
    <P N="FEComp_Description" V="|Object_Input.N+FEDesc|" T="Text" Role="Input"/>
    <P N="StationList_Input" V="[50*12, 75*12]" Role="Input" UT="Length"/>
    <P N="ComputeFor" V="0" D="[ConcurrentFx=1/ConcurrentFy=2/.../ConcurrentMz=6]" Role="Input"/>
    <P N="StrengthI" V="0" D="[No=0/Yes=1]" Role="Input"/>
    <P N="ServiceI" V="0" D="[No=0/Yes=1]" Role="Input"/>
  </O>

  <!-- Extract concurrent forces when Fx governs -->
  <O T="Group" Guard="ComputeFor == 1">
    <O N="UnfactoredResults" T="Group">
      <O N="str1" T="Group" Guard="StrengthI == 1">
        <P N="R_Str1CasesPos" V="map(StationList_Input, j =>
            map(Str1CaseList, iif(x[0] == NULL,
                [[NULL,NULL,NULL,NULL,NULL,NULL], NULL],
                [forceFxPosConc(x[0].N + CoreCombName, FEComp_Description, j, FEComp_Description, j), x[1], x[4]]
            ))
        )"/>

        <P N="R_Str1CasesNeg" V="map(StationList_Input, j =>
            map(Str1CaseList, iif(x[0] == NULL,
                [[NULL,NULL,NULL,NULL,NULL,NULL], NULL],
                [forceFxNegConc(x[0].N + CoreCombName, FEComp_Description, j, FEComp_Description, j), x[1], x[4]]
            ))
        )"/>
      </O>
    </O>

    <O N="FactoredResults" T="Group">
      <O N="str1" T="Group" Guard="StrengthI == 1">
        <P N="R_str1PosMax" V="map(StationList_Input, iif(str1Max_LC == NULL,
            [NULL,NULL,NULL,NULL,NULL,NULL],
            forceFxPosConc(str1Max_LC, FEComp_Description, x, FEComp_Description, x)
        ))"/>

        <P N="R_str1NegMax" V="map(StationList_Input, iif(str1Max_LC == NULL,
            [NULL,NULL,NULL,NULL,NULL,NULL],
            forceFxNegConc(str1Max_LC, FEComp_Description, x, FEComp_Description, x)
        ))"/>
      </O>
    </O>

    <O N="GoverningResults" T="Group">
      <O N="str1" T="Group" Guard="StrengthI == 1">
        <!-- Sort by Fx (index 0) to find governing -->
        <P N="R_str1GoverningMin" V="map(StationList_Input, j =>
            sort([R_str1PosMax[ji], R_str1NegMax[ji], R_str1PosMin[ji], R_str1NegMin[ji]], x[0])[0]
        )"/>

        <P N="R_str1GoverningMax" V="map(StationList_Input, j =>
            sort([R_str1PosMax[ji], R_str1NegMax[ji], R_str1PosMin[ji], R_str1NegMin[ji]], x[0])[3]
        )"/>
      </O>
    </O>
  </O>
</O>
```

***

## Advanced Patterns

### 1. Conditional Result Extraction

Use guards to extract only required limit states:

```xml
<O N="FactoredResults" T="Group">
  <O N="str1" T="Group" Guard="StrengthI == 1">
    <!-- Only extracted if StrengthI is enabled -->
    <P N="R_str1Max" V="..."/>
  </O>

  <O N="str2" T="Group" Guard="StrengthII == 1">
    <!-- Only extracted if StrengthII is enabled -->
    <P N="R_str2Max" V="..."/>
  </O>
</O>
```

***

### 2. NULL Handling

Always check for NULL before extracting:

```xml
<P N="Result" V="map(StationList, iif(LoadCase == NULL,
    [NULL,NULL,NULL,NULL,NULL,NULL],  <!-- Return NULL array if no load case -->
    stress(LoadCase, Element, x)       <!-- Extract if load case exists -->
))"/>
```

***

### 3. Using atstation() with Result Functions

Evaluate station-dependent results at specific locations:

```xml
<P N="MomentAtMidspan" V="atstation(600, forceM(Girder.N, LoadCase))"/>
```

***

### 4. Result Data Structure Indexing

Access specific components from result arrays:

```xml
<!-- Stress array: [σxx, σyy, σzz, τxy, τyz, τzx] -->
<P N="NormalStressX" V="StressResults[0]"/>
<P N="ShearStressXY" V="StressResults[3]"/>

<!-- Force array: [Fx, Fy, Fz, Mx, My, Mz] -->
<P N="Axial" V="ForceResults[0]"/>
<P N="Moment" V="ForceResults[5]"/>
```

***

## Best Practices

### 1. Performance Optimization

**Use StaticParams for repeated extractions:**

```xml
<O T="Repeat" N="StationResults" S="0" E="length(Stations)-1" I="1" CTRL="i" i="0"
   StaticParams="[LoadCase, Element, DesignComb]">
  <P N="Station" V="Stations[i]"/>
  <P N="Result" V="stress(LoadCase, Element, Station)"/>
</O>
```

**Cache commonly used results:**

```xml
<P N="CachedResults" V="map(StationList, stress(LoadCase, Element, x))"/>
<!-- Reuse CachedResults instead of re-extracting -->
<P N="MaxStress" V="max(map(CachedResults, x[0]))"/>
```

***

### 2. Organize by Hierarchy

```
Results
├── UnfactoredResults
│   ├── ByLimitState
│   │   ├── Strength I
│   │   ├── Service I
│   │   └── ...
│   └── AllCases
├── FactoredResults
│   ├── Strength I (Max/Min)
│   ├── Service I (Max/Min)
│   └── ...
├── GoverningResults
│   ├── Per Limit State
│   └── Overall Envelope
└── EnvelopeResults
```

***

### 3. Document Result Structures

Use comments to clarify complex nested structures:

```xml
<!-- Result structure:
     [Station1, Station2, Station3, ...]
     Each Station: [[Case1], [Case2], ...]
     Each Case: [[Forces], LoadTypeEnum, Description]
     Forces: [Fx, Fy, Fz, Mx, My, Mz] -->
<P N="Results" V="map(...)"/>
```

***

### 4. Error Checking

Check for NULL results before using:

```xml
<P N="SafeExtraction" V="iif(LoadCase == NULL || Element == NULL,
    [NULL,NULL,NULL,NULL,NULL,NULL],
    stress(LoadCase, Element, Station)
)"/>
```

***

### 5. Unit Consistency

Ensure consistent units in result extraction:

```xml
<P N="Moment_kipft" V="forceM(Element, LoadCase, Station)" UT="Moment" UC="Default"/>
```

***

## Common Pitfalls

### 1. Incorrect Element Paths

**Problem:** Element path doesn't match FEA model

```xml
<!-- Wrong - missing fullname() -->
<P N="Force" V="force(Girder, LoadCase, 'Fx', Station)"/>

<!-- Correct - use fullname() for dynamic paths -->
<P N="Force" V="force(fullname(Girder) + '.Comb', LoadCase, 'Fx', Station)"/>
```

***

### 2. Missing CoreCombName

**Problem:** Load case names don't include combination suffix

```xml
<!-- Wrong - incomplete load case name -->
<P N="Result" V="stress(x[0].N, Element, Station)"/>

<!-- Correct - append CoreCombName -->
<P N="Result" V="stress(x[0].N + CoreCombName, Element, Station)"/>
```

***

### 3. Index Errors in Nested Maps

**Problem:** Using wrong index variable in nested maps

```xml
<!-- Wrong - reusing 'i' -->
<P N="Results" V="map(Stations, i => map(Cases, stress(x, Element, i)))"/>

<!-- Correct - use 'ji' for outer index in inner map -->
<P N="Results" V="map(Stations, j => map(Cases, stress(x, Element, Stations[ji])))"/>
```

***

### 4. Concurrent Force Confusion

**Problem:** Using wrong concurrent location

```xml
<!-- Wrong - same station for both -->
<P N="Wrong" V="forceMyPosConc(LoadCase, Girder, 600, Girder, 600)"/>
<!-- This gives concurrent forces AT station 600 when My AT station 600 is max -->

<!-- May be correct depending on use case - concurrent at different location -->
<P N="Different" V="forceMyPosConc(LoadCase, Girder, 600, Girder, 300)"/>
<!-- This gives concurrent forces AT station 300 when My AT station 600 is max -->
```

***

## Summary

OpenBrIM FEA result extraction uses ParamML functions to query analysis outputs and organize them for design checks:

**Core Functions:**

* `force()`, `forcePos()`, `forceNeg()` - Force/moment extraction
* `forceFxPosConc()`, `forceMyNegConc()`, etc. - Concurrent force extraction
* `stress()` - Stress component extraction
* `disp()`, `dispX()`, `dispY()`, `dispZ()` - Displacement extraction

**Organization Patterns:**

* Multi-station extraction using `map()`
* Hierarchical limit state organization (Unfactored, Factored, Governing, Envelope)
* Conditional extraction with guards
* NULL handling for missing load cases

**Best Practices:**

* Use `fullname()` for dynamic element paths
* Cache results to avoid redundant extractions
* Use `StaticParams` in repeats for performance
* Document complex result structures
* Check for NULL before extraction
* Maintain unit consistency

**Common Use Cases:**

* Stress/force extraction at design stations
* Concurrent forces for interaction checks
* Envelope results across multiple load combinations
* Limit state compliance verification
* Governing results for design reports

By following these patterns, AI agents can efficiently extract and organize FEA results for bridge design code checks and documentation.
