NaxToPy 3.2.2
Package for postprocessing FEM results in Python
License: MIT
Requires Python: >=3.9
Keywords: NaxTo, Postprocessing, FEM

[![Idaero](https://img.shields.io/badge/powered%20by-Idaero%20Solutions-299797)](https://idaerosolutions.com)
[![PyPi](https://img.shields.io/pypi/v/NaxToPy?color=ffd500)](https://pypi.org/project/NaxToPy/)
[![Python](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-00699d)](https://www.python.org/downloads/)
![License](https://img.shields.io/badge/license-proprietary-red)
[![MicrosoftStore](https://img.shields.io/badge/Microsoft%20Store-NaxTo-blue?logo=microsoftstore&logoColor=blue&labelColor=lightgrey)](https://apps.microsoft.com/detail/XP9MMH0KDKGRJN?hl=en-US&gl=US)
[![PyPi - Downloads](https://img.shields.io/pypi/dm/NaxToPy?color=dgreen)](https://pypi.org/project/NaxToPy/#files)

![](https://idaerosolutions.com/images/icons/Logo_NaxToPy_Black.svg "NaxToPy")

# NaxToPy

**NaxToPy** is the [**NaxTo**](https://apps.microsoft.com/detail/XP9MMH0KDKGRJN?hl=en-US&gl=US)
library designed for Python, allowing users to read and manipulate FEM analysis
results files from the most common tools: Nastran (op2, xdb, h5), Abaqus (odb), Optistruct (h3d, op2),
and Ansys (rst). It stores these results in a user-friendly Python structure. Additionally, it can
read input files from Nastran (bdf/dat), Optistruct (fem) and Abaqus(inp) and modify their contents.

It can easily be combined with other Python packages, such as Matplotlib or Pandas, providing access
to Python's full coding power for interpreting and processing results without the need to install
additional software beyond NaxTo (see the Download and Homepage links on the left).

**NaxToPy** is a powerful tool for FEM analysis post-processing!

---------------

⚠️**Warning:** To use NaxToPy, [**NaxTo**](https://apps.microsoft.com/detail/XP9MMH0KDKGRJN?hl=en-US&gl=US) must be installed.
This version is compatible with **NaxTo 2025.2**. 
Check in _Programs and Features_ the NaxTo version that is installed.

📘**Note:** If a specific NaxTo version is installed, search the [**NaxToPy History**](https://pypi.org/project/NaxToPy/3.1.2/#history) to find which newer version is compatible with it.


## Installation

If python is installed and `pip` is added to the PATH:

`pip install NaxToPy`

An alternative, if Python is callable from the command line:

`python -m pip install NaxToPy`

For **Visual Studio** users:
- Open "Python Environments" window
- Change the "general information" label to "Packages(Pypi)"
- Write the name of the package and press enter:

- `NaxToPy` + enter

For **Spyder** users:
- If pip is installed: `!pip install NaxToPy`
- If pip is not installed, download and run `get-pip.py` located in  https://bootstrap.pypa.io/get-pip.py . Then, run the
`!pip ...` command
- If no method worked, download the sorce ditribution of the package *NaxToPy* from Test PyPi and the source
distribution of the packages from PyPi *pythonnet*, *clr-loader*, *cffi*, *pycparser*. Copy and paste the five folder in the 
same directory. When ever you want to use the NaxToPy package add the following lines to your script:

      import sys
      sys.path.append("...\directory")
      import NaxToPy as n2p
      
## Updating NaxToPy

If python is callable from the command line:

`python -m pip install -U NaxToPy`

For Visual Studio users:
- Open "Python Environments" window
- Change the "general information" label to "Packages(Pypi)"
- Write the following command on the search bar and press enter:

  `-U NaxToPy` + enter


## Version updates:

To see previous version see the pre-release versions in https://test.pypi.org/project/NaxToPy/

### v.1.0.1
1. Bug Fix: A new dependece is added to support python 3.12
2. Bug Fix: N2PLog.set_directory now works correctly
3. New download page for NaxTo and NaxToPy

### v.1.1.0
1. Bug Fix: PSOLID with material coordinate = -1 is now suppported
2. Now, it is possible to modify the BDF data from Nastran and rewrite the files.

### v.1.1.1
1. New property for the class N2PLoadCase: Solver
2. New fille that allows the user to call the N2P classes. Useful for typing
3. N2PCoord don't have the property PartID any more, as it is considered that Coordinates systems don't have parts/superelements 
4. Method for the connectivity property of N2PNode have been optimized

### v.1.2.0
1. Bug Fix: Property IsTransformable of the N2PComponent class is now right.
2. Bug Fix: When calling the methods .get_nodes(), get_elements(), etc from a Nastran Input File, the user don't have to specify the part.

### v.1.2.1
1. New method to create N2PLoadCase as envelope load case of the selected load cases.
2. The name for derivated load cases is now checked to avoid a repeated name 

### v.1.3.0
1. New class N2PReport. This class allow to create tables of data with the components, incremenets, load cases, etc to generate big reports.
2. Improvement in typing
3. Small changes in the core of the package related to libraries finding and loading.

### v.1.4.0
1. Bug correction for N2PReport. Now it sorts correctly by "LC" or "IDS"
2. N2PLoadCase has a new property: PathFile.

### v.1.5.0
1. A bug is fixed that prevented requesting results on global axes.
2. The typing of some functions is improved.

### v.1.5.1
1. Bug Fix. If the name for a derivated load case is repeated for a second time, the name is changed. 
2. Bug Fix. Now is possible to change the criteria for a new envelope load case.

### v.1.5.2
1. Bug fix: A bug has been resolved that previously prevented the generation of a .log file while executing the N2PtoEXE module.
2. Bug fix: An internal error related to finding the libraries has been resolved.
3. The option to include a splash image in an executable has been added.

### v.1.5.3
1. Bug fix for the EXE generation.
2. Updates in the log messages.

### v.1.5.4
1. Bug Fix: After calling the method get_load_cases(), the new derived cases weren't found. Now they does.
2. N2PLoadCase has now two properties for the ID: OriginalID, that was in the files readed and ID that is the one that is used in NaxToPy. Usually, they are the same.
3. New method new_derived_component() in the class N2PResult that allows to create new N2PComponent based on the original components.
4. New module N2PUpdateFastener. This module updates the stiffness of the CBUSH and CFAST acordint to their properties and shells properties.

### v.1.5.5
1. Bug Fix: Now is possible to call the module N2PUpdateFastener

### v.1.5.6
1. The method new_envelope_loadcase() now has the option to choose the envelope group. Which means the user can ask for
the LoadCases that are critical or the Increment that is critical instead of the value.

### v.2.0.0
1. Changes made to align the library with updates in lower-level dependencies.
2. New internal methods to look for the compatibility with low-level dependencies.
3. The name of the .log is now NaxToPy_Year-Month-Day.log.

### v.2.0.1
1. The compatibility is extended to all NaxTo steps of the same version.
2. The property N2PLoadCase.ActiveIncrement is subtitued by N2PLoadCase.ActiveN2PIncrement.
It uses an object instaed of an int.
3. Update of the examples of some docstrings.

### v.2.1.0
1. Reading a Natran Input File: SPC and SCP1 are now supported.
2. Bug fix. The order in the components in new_report() does not affect now.
3. Formula check in new_derived_loadcase(), new_enevelope_loadcase() and new_derived_component().
4. New optional arguments if n2ptoexe() to add extra libaries, packages or files.

### v.2.1.1
1. Two new methods in N2PModelContent: load_user_coord_sys_from_csv() and set_user_coord_sys().
Also, there is a new property for N2PElement and N2PNode: UserSystemArray. This update allow the
user to define a different coordinate system for each element or node. To ask for the results
in this system, the optional argument `coordsys` must be equal to `-20`.
2. Bug fix: The checking for component and section in new_report() has been fixed. If a comma
appeared in the component or section name, the method failed.

### v.2.1.2
1. Internal change for speeding up the read of NastranInputFiles. Now the Nastran Cards are loaded
when they are asked and not all at once.
2. Improvement in error handling and log writing.
3. The function import_results_from_files() checks if the file exist. If not, it prints an error
but the execution doesn't crash.

### v.2.2.0
1. Feat: New module for fastener analysis: N2PGetFasteners.
2. Feat: New module for fastener analysis: N2PGetLoadFasteners. Calculates forces in joints and bypass forces.
3. Bug fix: When a NaxToPy executable file is used on a machine where NaxTo is installed, the libraries are selected accordingly.
4. Feat: Hidden imports are now allowed in n2ptoexe.
5. Bug fix: Fixed the rotation of the FORCES tensor. Now the QX and QY components (transverse shears) are calculated correctly.
6. Refactor: The dictionary and list for Cards have been replaced with a lazy dictionary and a lazy list, improving execution efficiency.
7. Refactor: Reading the mesh from binary files is now executed in parallel by default, as this approach is more memory-safe.

### v.2.2.1
1. BugFix: The method set_increment() is fixed.
2. BugFix: Several bugfix (not in the result accuracy) are fixed in modules N2PGetFastener and N2PGetLoadsFastener. Several optimizations are included.
3. Feat: Now the method get_load_case() admits a list of int and a list of string and return a list of N2PLoadCase.
4. Refactor: N2P classes use __slots__ for security and optimization.
5. Refactor: Complete refactor of the module that loads the NaxTo libraries.
6. BugFix: in parallel mesh load with a small mesh and lot of results.
7. BugFix: in sequential mesh load in op2.

### v.2.2.2
1. BugFix: Solved an issue in the Nastran Cards Dictionary
2. BugFix: Solved the Prop atribute of an N2PElement in Abaqus
3. Feat: Now is possible to create `N2PCoord` by the user with the `new_coordinate_system()` method.
4. Feat: Now is possible to add to `element_nodal()` a list of N2PElement to unshew only the nodes of these elements.
5. Feat: Now is possible to ask for results in a list of elements or nodes using the optional argument `filter_list`.
6. Feat: When the user provides a coordinate system and two vectors (v1, v2) to specify the output results, the information
is redundant. The coordinate system will prevail.
7. Feat: New properties supported: PBUSH, PFAST, PMASS, PELAS, PGAP, PWELD
8. BugFix: The method get_elements_attached() is fixed so when there are MPC connectors with the same ID.

### v.2.2.3
1. Requirement: Now NaxToPy require the package [**h5py**](https://pypi.org/project/h5py/).
2. Feat: N2PGetLoadFastener now can use PAG method and display format.
3. BugFix: Some bugs are solved in N2PGetFastener and N2PGetLoadFastener.
4. Feat: N2PGetLoadFastener can export results in HDF5 format.
5. BugFix: The filtering in the method get_result_by_LCs_Incr() in elements when results are in Corner Data is fixed.

### v.3.0.0
1. Feat: Now it is supported more properties from Nastran: PBAR, PBARL, PBEAM, PBEAML, PBUSH, PWELD, PELAS, PFAST, PMASS, PGAP. They are kept as N2PBeam, N2PBeamL, N2PBush, N2PWeld, N2PElas, N2PFast, N2PMass, N2PGap.
2. Feat: Now it is supported more properties from Abaqus: *BEAM SECTION and *BEAM GENERAL SECTION as N2PBeamL and N2PBeam.
3. Feat: Overloaded `get_result_by_LCs_Incr()` to accept a list of components. It load multiple components and load cases of the same result in parallel, improving efficiency.
4. Feat: New property N2PComp.EqQBenMatrix that returns the equivalent stifness matrix for bending. 
5. Feat: Added `N2PComp.EqMemProps` and `N2PComp.EqBenProps` properties to return equivalent engineering values (Ex, Ey, G, and ν) for membrane and bending behavior, respectively.
6. Feat: Added two new methods in `N2PModelContent`: `get_material()` and `get_property()` to search easelly for materials and properties.
7. Feat: new method in `N2PModelContent`: `get_elements_filtered()`. It returns a list of `N2PElement` that matches a material, property, part or type-element.
8. Feat: New checks in the results methods to avoid invalid parameters.

### v.3.1.0
1. Feat: New optional argument in `load_model()` called **loadconnectors**. True by default.
2. Feat: New module N2PNeuber to obtain stresses using the Neuber method.
3. Feat: New module N2PSandwich to calculate sandwich structures failure modes.
4. Feat: New module N2PCompositeFailure for evaluating structural failure in laminates.
5. Feat: New module N2PEdgeDelamination  to obtain interlaminar stresses and RF from edge delamination.
6. Feat: New module N2PCalculatorRFJoints manages the Reserve Factor (RF) calculation process of the joints obtained through the modules N2PGetFasteners and N2PGetLoadFasteners.
7. Feat: New module N2PUpdateFastener provides methods to update rivet and bolt stiffness and generate a new FEM Input File (.bdf, .fem, .dat, etc.) file with the updated data.
8. BugFix: Several bugs are fixed in N2PGetFastener and N2PGetLoadFastener modules.
9. Feat: Extra information in the log when the NaxToPy is running from a executable.
10. Feat: `N2PLoadModelContent.SetList` is now an encapsulated property.
11. Refactor: the method `N2PLoadModelContent.get_result_by_LCs_Incr()` is optimized.

### v.3.1.1
1. BugFix: Small error fixed in `N2PNeuber`.
2. Feat: New Failure criteria in `N2PCompositeFailure` -> Fiber Mode Concept
3. BugFix: The property `LevelList` of the abstract class `N2PLog` is now an attribute to be compatible with Python 3.13.
4. Feat: New class `N2PropMisc` for properties that are not supported.
5. BugFix: Small errors in `N2PGetFasteners`.
6. BugFix: Several errors are fixed for properties and materials when reading **InputFileAbaqus** (inp) and **Abaqus** (odb).
7. Feat: Now, when a executable is created, if the version of NaxTo of the exe matches the instaled, it will use the **installed** NaxTo libraries. If the version doesn't match or NaxTo is not installed, **exe** NaxTo libraries will be used.
8. BugFix: the keyword `THRU` is now supported in the bulk data card `SPC1` when reading from a Nastran Input File.

### v.3.1.2
1. BugFix: Changes to fix the Mat IDs attributes in N2Property from Abaqus files.
2. Refactor: Updated vectorised method for N2PCompositeFailure module.
3. Docs: Improved documentation in some methods.

### v.3.2.0
1. Refactor: `N2PGetFasteners` and `N2PGetLoadFasteners`: Improvement in warning and error messages and documentation
2. Refactor: `N2PNastranInputData`: The Nastran input file reading libraries (Bulk Data Files) have been updated, and this class has been adapted to the new changes, which improve memory management and file loading speed.
3. Refactor: `NaxToPy.load_model()`: Improved file type selection (binary or text) and identification of which Solver type they belong to (`"InputFileNastran"`, `"InputFileAbaqus"`).
4. Refactor: `N2PModelContent.get_result_by_LCs_Incr()`: Now, if the requested result or component does not exist in one of the load case-increment cases, the key-value pair is returned in the dictionary, but with the value set to a numpy array filled with "nan", instead of omitting the key from the dictionary.
5. Refactor: `N2PCompositeFailure`: Improved module efficiency by vectorizing calculations and added a new failure criterion, FMC - Fiber Mode Concept, which is compatible with FirstPly and PlyByPly.
6. Feat: `N2PCoefficientsFinder`: New NaxToPy module that detects and defines linear dependencies between rows of a given matrix.
7. Feat: `N2PNastranInputData.find_cards()`: New method that replaces the old `get_cards_by_field()`. Allows searching for cards with various filter types efficiently.
8. Feat: `N2PNastranInputData.get_failed_cards()`: New method that allows retrieving cards that are poorly formatted or have reading errors when opening a Nastran input file (.bdf).
9. Feat: `N2PNastranInputData.create_card()`: New method that allows creating Nastran cards completely from scratch, which will be added to the end of the Nastran input file once the `rebuild_file()` command is executed.

### v.3.2.1
1. BugFix: Derived components are now founded right while using `get_result_by_LCs_Incr()`.
2. BugFix: All sections are now founded right while using `get_result_by_LCs_Incr()`.
3. BugFix: Now symbols like "\" or "-" are supported as part of the name of Components and Load Cases while creating new derived Components and Derived Load Cases.

### v.3.2.2
1. BugFix: Logs message are not printed double when the buffer is called several times.
2. BugFix: `get_load_case()` now returns correctly the load cases if it is called before and after calling `import_results_from_files()`.
3. Refactor: New structure for the h5 files generated by N2PNeuber module.
4. BugFix: MCID in CQUAD4 and CTRIA3 are now correctly readed from a bdf file.

# Documentation

**NaxToPy** is a package developed by Idaero Solutions© as a part of the **NaxTo** software.

NaxToPy only use four dependeces:
- NumPy: https://numpy.org/
- PythonNET: https://pythonnet.github.io/
- Setuptools: https://setuptools.pypa.io/en/latest/index.html
- HDF5: https://www.h5py.org/

## Supported Files

### Result files:
- **Nastran:** .op2, .h5, .xdb
- **Optistruct:** .op2, .h3d
- **Abaqus:** .odb
- **Ansys:** .rst, .rth(beta)

### Input files:
- **Nastran** (.bdf)
- **Optistruct** (.fem)
- **Abaqus** (.inp)

## Initialize your model

Load your model:

```python
# results_fem.py
import NaxToPy as N2P

path = "results_fem.op2"

model = N2P.load_model(path)
```

## Load mesh items

```python
# results_fem.py

# Load a list with all the nodes (as N2PNode object) of the model
nodes = model.get_nodes()

# Load the nodes in the list [1, 2, 3] (as a list of N2PNode objects)
nodelist = model.get_nodes([1, 2, 3]) 

# Load the node with the id 1000 (as a N2PNode object)
node1000 = model.get_nodes(1000)

# Load a list with all the elements (as N2PElement object) of the model
element = model.get_elements()

# Load the elements in the list [10, 20, 30] (as a list of N2PElement objects)
elementlist = model.get_nodes([10, 20, 30])

# Load the connectors as N2PConnector:
connectorslist = model.get_connectors()

# Load the coordinate systems of the model:
coordslist = model.get_coords()
```
## Add your own messages to the .log

```python
# results_fem.py

N2P.N2PLog.Info.user("INFO-1000: Running results_fem.py")
```

## Look for LoadCases, Results and Components

```python
# results_fem.py

# Load the list of load cases as N2PLoadCase object
loadcaseslist = model.LoadCases

# Look for the Load Case with the name pressure
pressure_lc = model.get_load_case("pressure")

# Change the active increment (by default is the last one):
pressure_lc.ActiveN2PIncrement = pressure_lc.get_increment(10)

# Look for all results
all_results = pressure_lc.Results

# Look for the Result with the name DISPLACEMENT
displacement = pressure_lc.get_result("DISPLACEMENT")

# Load all the components of the result
all_components = displacement.Components

# Look for the component X:
x_coord = displacement.get_component("X")
```

## Load the result data as a list

```python
# results_fem.py

# Obtain the result array as a list for a component
x_list = x_coord.get_result_list()[0]
```

## Load the result data as a NumPy array

```python
# results_fem.py

# Call the get_result_ndarray method of a N2PComponent to obtain a numpy array
# with the results of the component.
x_df = x_coord.get_result_ndarray()
```

## Create an executable file of your code
Using a different script:
```python
# extra_script.py

import NaxToPy as N2P
path1 = "results_fem.py"
path2 = "results_fem_abaqus.py"

N2P.n2ptoexe(path1, console=True, solver="NASTRAN")
N2P.n2ptoexe(path2, console=True, solver="ABAQUS", abaqusversion=["2021", "2022"])
```

## Create your own functions to work with other python packages:
Private function that generates the proper index for a data frame using the elemnts or nodes ids:
```python
# results_fem.py

import pandas as pd

def _index_dataframe(model: "N2PModelContent", component: "N2PComponent", sections, aveSections, cornerData, aveNodes,
                     variation, realPolar, coordsys, v1, v2) -> pd.Index:
    """ Function that returns the proper index for each component asked
    """
    # It is look if there is one part or several's:
    parts = len(model.Parts) - (model.Solver == "Abaqus")

    # Then the result array and where there results are placed is obtained
    on_items = component.get_result_ndarray(sections, aveSections, cornerData, aveNodes,
                                            variation, realPolar, coordsys, v1, v2)[1]

    # The ids and the index are selected. It takes into account where the results are and the number of parts
    if on_items == "NODES":
        nodes = model.get_nodes()
        ids = [(nodo.PartID, nodo.ID) if parts > 1 else nodo.ID for nodo in nodes]
        indexname = ["Part", "Grid"] if parts > 1 else ["Grid"]

    elif on_items == "ELEMENTS":
        elements = model.get_elements()
        connectors = model.get_connectors()
        ids = [(element.PartID, element.ID) if parts > 1 else element.ID for element in elements] + \
              [(co.PartID, co.ID) if parts > 1 else co.ID for con in connectors for co in (con if isinstance(con, list) else [con])]
        indexname = ["Part", "Element"] if parts > 1 else ["Element"]

    elif on_items == "ELEMENT NODAL":
        ids = model.elementnodal().values()
        indexname = ["Part", "Grid", "Element"]

    else:
        return None

    # If there are several parts, or it is corner data, MultiIndex is used:
    if isinstance(ids[0], tuple):
        index = pd.MultiIndex.from_tuples(ids, names=indexname)
    else:
        index = ids

    return index
```
Function that generates a DataFrame with the results of a component
```python
# results_fem.py

def dataframe_result(model: "N2PModelContent", component: "N2PComponent",sections=None, aveSections=-1, cornerData=False,
                     aveNodes=-1, variation=100, realPolar=0, coordsys: int = -1000,
                     v1: tuple = (1,0,0), v2: tuple = (0,1,0)) -> pd.DataFrame:
    """Function that returns as a dataframe of pandas the result array of a component
    """

    # DataFrame generation
    return pd.DataFrame(data={component.Name:
                              component.get_result_ndarray(sections, aveSections, cornerData, aveNodes, variation,
                                                           realPolar, coordsys, v1, v2)[0]},
                        index=_index_dataframe(model, component, sections, aveSections, cornerData, aveNodes, variation,
                                               realPolar, coordsys, v1, v2),
                        columns=[component.Name])
```
Function that generates a DataFrame for all the components of a result
```python
# results_fem.py

def dataframe_results(model: "N2PModelContent", result: "N2PResult", sections=None, aveSections=-1, cornerData=False,
                     aveNodes=-1, variation=100, realPolar=0, coordsys: int = -1000,
                     v1: tuple = (1,0,0), v2: tuple = (0,1,0)) -> pd.DataFrame:
    """Function that generates a DataFrame of pandas with all the components of a result. It uses dataframe_result.
    It uses sequential computing.
    """
    return pd.DataFrame(data={component.Name:
                                  component.get_result_ndarray(sections, aveSections, cornerData, aveNodes, variation,
                                                               realPolar, coordsys, v1, v2)[0]
                                                               for component in result.Components.values()},
                        index=_index_dataframe(model, next(iter(result.Components.values())), sections, aveSections,
                                               cornerData, aveNodes, variation, realPolar, coordsys, v1, v2),
                        columns=[component.Name for component in result.Components.values()])
```

##
For more documentation visit https://idaerosolutions.com/Home/NaxToPy

Complete NaxToPy documentation at: https://www.idaerosolutions.com/NaxToDocumentation/NaxToPy/3.1.0/index.html

# License

See the license in Python\Lib\site-packages\NaxToPy-{version}.dist-info\LICENSE or executing the command `python -m pip show NaxToPy`

-------------

<p align="center">  <img src="https://www.idaerosolutions.com/images/web/Idaero.png" alt="Idaero Icon" width=200></p><div align="center">© 2025 Idaero Solutions S.L. All rights reserved.</div>