Skip to main content

FEMAP neutral file parser

  • Free software: MIT license

Features and limitations

Parse and render FEMAP neutral files. For now, three blocks are interpreted:

  • Block 100 “Neutral File Header”

  • Block 450 “Output Sets”

  • Block 451 “Output Data Vectors”

Usage

To use FEMAP neutral Parser in a project:

>>> from femap_neutral_parser import Parser

To instantiate a new parser, just pass a file path:

>>> neu = Parser("tests/data/mystran_00.NEU")

To have a list of available blocks:

>>> neu.available_blocks()
{'header': 100, 'output_sets': 450, '_output_vectors': 451}

Or maybe in a more human-friendly way is to use info() method, which prints available results and outputs:

>>> neu.info()
<BLANKLINE>
Analysis
========
 * subcase 1: Analyse. NASTRAN SPC 1 - lc1. test (MYSTRAN::Static)
 * subcase 2: Analyse. NASTRAN SPC 1 - lc2. test (MYSTRAN::Static)
<BLANKLINE>
Outputs
=======
access to one of them using `._output_vectors[<title>][<SubcaseID>]['record']
<BLANKLINE>
 * displacements::t_total -> RSS translation
 * displacements::t1 -> T1 translation
 * displacements::t2 -> T2 translation
 * ...
 * cbar_stress::min_comb_a -> BAR EndA Min Stress
 * cbar_stress::min_comb_b -> BAR EndB Min Stress

Access available blocs by attribute:

>>> from pprint import pprint as pp
>>> pp(neu.output_sets)
{1: {'anal_type': 'Static',
     'from_prog': 'Unknown',
     'integer_format': None,
     'notes': '',
     'process_type': None,
     'title': 'Analyse. NASTRAN SPC 1 - lc1. test',
     'value': 0.0},
 2: {'anal_type': 'Static',
     'from_prog': 'Unknown',
     'integer_format': None,
     'notes': '',
     'process_type': None,
     'title': 'Analyse. NASTRAN SPC 1 - lc2. test',
     'value': 0.0}}

Low-level data access

Under the hood, output vectors (block451) are organized as nested dictionaries [<vector title>][<LCID>]:

>>> pp(neu._output_vectors["displacements::t_total"][2])
{'abs_max': 2.578386,
 'calc_warn': True,
 'cent_total': True,
 'comp_dir': 1,
 'component_vec': [10002.0,
                   10003.0,
                   10004.0,
                   0.0,
                   0.0,
                   0.0,
                   0.0,
                   0.0,
                   0.0,
                   0.0],
 'id_max': 7,
 'id_min': 1,
 'max_val': 2.578386,
 'min_val': 0.0,
 'record': array([( 1, 0.000000e+00), ( 2, 2.045391e-01), ( 3, 0.000000e+00),
       ( 4, 1.468270e-02), ( 5, 9.231050e-05), ( 6, 6.276400e-01),
       ( 7, 2.578386e+00), ( 8, 1.025100e-01), ( 9, 2.578363e+00),
       (10, 1.916094e+00), (11, 1.100510e+00), (12, 2.389742e+00)],
      dtype=[('NodeID', '<i8'), ('displacements::t_total', '<f8')]),
 'vecID': 10001}

Aggregated Outputs

Slightly highest level than _output_vectors access, aggregated output is available using Parser.vectors() method. For example, to get all outputs for translations vectors:

>>> arr = neu.vectors(("displacements::t1", "displacements::t2", "displacements::t3"))
>>> arr
rec.array([( 1,  0.        , 0.,  0.000000e+00, 1),
           ( 2, -0.1870816 , 0.,  0.000000e+00, 1),
           ...
           (11,  0.        , 0., -1.100510e+00, 2),
           (12,  0.        , 0., -2.389742e+00, 2)],
          dtype=[('NodeID', '<i8'), ('displacements::t1', '<f8'), ('displacements::t2', '<f8'), ('displacements::t3', '<f8'), ('SubcaseID', '<i8')])

Returned value is a numpy structured array (https://numpy.org/doc/stable/user/basics.rec.html). If Pandas is available, you can request to have a DataFrame instead:

>>> neu.vectors(("displacements::t1", "displacements::t2", "displacements::t3"), asdf=True)
                   displacements::t1  displacements::t2  displacements::t3
SubcaseID NodeID
1         1       0.000000       0.0  0.000000
          2      -0.187082       0.0  0.000000
...
          11      0.000000       0.0 -0.956073
          12      0.000000       0.0 -1.602912
2         1       0.000000       0.0  0.000000
          2      -0.204539       0.0  0.000000
...
          11      0.000000       0.0 -1.100510
          12      0.000000       0.0 -2.389742

You can also request sub-cases IDs, or request raw headers:

>>> neu.vectors(("displacements::t1", "displacements::t2", "displacements::t3"), asdf=True, raw=True,
...              SubcaseIDs=2)
                  T1 translation  T2 translation  T3 translation
SubcaseID NodeID
2         1             0.000000             0.0        0.000000
          2            -0.204539             0.0        0.000000
...
          11            0.000000             0.0       -1.100510
          12            0.000000             0.0       -2.389742

High-Level access

At highest level, you can use the get method that already organize vectors for you:

>>> neu.get(what="displacements", asdf=True)
                        t1   t2        t3        r1        r2            r3
SubcaseID NodeID
1         1       0.000000  0.0  0.000000 -0.000432  0.008923  4.699029e-03
          2      -0.187082  0.0  0.000000  0.000432  0.008923  4.666047e-03
...
2         1       0.000000  0.0  0.000000 -0.000007  0.009755  5.137517e-03
          2      -0.204539  0.0  0.000000  0.000007  0.009755  5.101457e-03
...
          11      0.000000  0.0 -1.100510  0.000000  0.010988  1.006013e-06
          12      0.000000  0.0 -2.389742  0.000000  0.004149  1.360364e-08

One can get the list of high-level shortcuts using Parser.get_vectors() which will return a set of available headers:

>>> neu.get_vectors() == {
... 'elem_gpf',
... 'force_vectors',
... 'displacements',
... 'summed_gpf',
... 'mpc_forces',
... 'constraint_gpf',
... 'cbar_force',
... 'cbar_stress',
... 'cbush_force',
... 'cbush_stress',
... 'cbar_ms',
... 'applied_gpf',
... 'spc_forces',
... 'cbeam_force'
... }
True

Requirements

Beside Python>=3.8, only numpy is required. numpy arrays are released as https://numpy.org/doc/stable/user/basics.rec.html, which makes conversions to Pandas a breeze.

If Pandas is installed (which is advised), the asdf parameters are valid.

Testing

For testing, making docs or coding, all the dev requirements are provided in requirements_dev.txt.

From a blank virtual environment, clone this repo:

git clone https://framagit.org/numenic/femap_neutral_parser.git

Create a Python virtual environment, and activate it:

python -m venv fnp
source fnp/bin/activate

Install requirements:

cd femap_neutral_parser
pip install -r requirements.txt  # install numpy
pip install -r requirements_dev.txt
pip install -e .  # install femap-neutral-parser in new venv

Now testing:

make test  # or make coverage

Building docs:

make docs

History

0.8.3 (2021-09-12)

Major internal refactoring

  • output_vectors becomes internal (_output_vectors). The recommended ways to access data is now Parser.vectors() or Parser.get() at a higher level.

  • no more autotranslate initialisation parameter. Everything is harmonized under the hood.

0.6.0 (2021-07-12)

  • add engineering shortcuts

  • harmonize NodeID and SubcaseID with pynastran

  • vectors are now case insensible

0.5.0 (2021-04-16)

  • improve parsing speed on large files

0.4.0 (2021-04-16)

add:

  • Parser.info()

  • Parser.vectors()

0.3.0 (2021-04-16)

  • add Parser.info() and Parser.vectors()

  • update documentation

  • add info() doprint option

0.2.0 - 0.3.0 (2021-04-16)

  • Update Documentation

0.1.0 (2021-03-24)

First release on PyPI.

Metadata

Release files for femap-neutral-parser 0.14.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for femap-neutral-parser 0.14.0
File Size Uploaded Provenance
femap_neutral_parser-0.14.0.tar.gz 46.4 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for femap-neutral-parser 0.14.0
File Interpreter ABI Platform
femap_neutral_parser-0.14.0-py2.py3-none-any.whl Python 2, Python 3 none any Details

Total release size: 70.0 kB

Release files / femap_neutral_parser-0.14.0.tar.gz

Download URL femap_neutral_parser-0.14.0.tar.gz
Size 46.4 kB
Tags Source
SHA-256 checksum
How to use checksums
ca6ac11ef2ff8631826c74256243ec223ff51921f97b174106618b19cfa22877
BLAKE2b-256 checksum
How to use checksums
5847cf59bd64d8a41acfdff9468cbc0e98c0e1b7e4fa68688a0e717edcea6dd8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.1 CPython/3.8.13

Release files / femap_neutral_parser-0.14.0-py2.py3-none-any.whl

Download URL femap_neutral_parser-0.14.0-py2.py3-none-any.whl
Size 23.6 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
d1267761da9d84bf16afbd0fa7aee13c0059306a5441705d9f2a9246663a30ef
BLAKE2b-256 checksum
How to use checksums
66f37ba082357c8f27581e934177cb9f545ad5f3d13f410766fd8dd87f13fe00
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.1 CPython/3.8.13

Security for femap-neutral-parser 0.14.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page