3. Results#
3.1 Results Structure#
"""
In this code it's shown how the results are organized in Load Cases, Increments, Results, Components and Sections.
N2PModelContent
│
└───N2PLoadCase
│
├───N2PIncrement
└───N2PResult
│
└───N2PComponent
│
└───N2PSection
"""
import NaxToPy as n2p
model = n2p.load_model(r"C:\Data\models\subcase\subcase_17500.op2")
# Inside a N2PModelContent (model), there is a list of N2PLoadCases
lcs = model.LoadCases
# A specific load case can be retrieved using its id
lc_17500 = model.get_load_case(17500)
# A N2PLoadcase has a dictionary of N2PResults and a list of N2PIncrements
results = lc_17500.Results
incrs = lc_17500.Increments
# Each load case has an active increment. By default is the last one
active_incr = lc_17500.ActiveN2PIncrement
incr_1 = lc_17500.get_increments(1)
# The active increment of the load case can be changed. Equivalent method
lc_17500.set_increment(1)
lc_17500.ActiveN2PIncrement = incr_1
# To select a N2PResult use the next method:
stresses = lc_17500.get_result("STRESSES")
# Each result has a dictionary of components
comps = stresses.Components
# To select a component:
xx = stresses.get_component("XX")
# Each component has a list of sections
sections = xx.Sections
# All in one line:
z1 = model.get_load_case(17500).set_increment(1).get_result("STRESSES").get_component("XX").Sections[0]
3.2 Asking for Results#
"""
Obtain results in NaxToPy there are two options.
1. From N2PComponent using get_result_ndarray()
2. From N2PModelContent using get_result_by_LCs_Incr()
"""
import NaxToPy as n2p
# Load a N2PModelContent
model = n2p.load_model(r"C:\Data\models\subcase\subcase_17500.op2")
model.import_results_from_files([
r"C:\Data\models\subcase\subcase_17501.op2",
r"C:\Data\models\subcase\subcase_17502.op2",
r"C:\Data\models\subcase\subcase_17503.op2"
])
# Get a N2PComponent
x = model.get_load_case(17500).get_result("DISPLACEMENTS").get_component("X")
# Get the array of displacements in x. IT IS A TUPLE!
x_results = x.get_result_ndarray()
x_array = x_results[0] # In position 0 of the tuple is the actual array
x_position = x_results[1] # In the position 1 is the location of the results
# get_result_ndarray() can have multiple optional arguments for asking the results in different ways:
xx = model.get_load_case(17500).get_result("STRESSES").get_component("XX")
xx.get_result_ndarray(sections=["Z1, Z2"], aveSections=-3, cornerData=False, coordsys=-1)
# The arguments may be:
# - The sections where the results are needed
# - The type of average if several sections are asked
# - If results are in corner data (element-nodal)
# - If corner data is asked, aveNodes and variation set the relationship of the results in the nodes
# - The coordinate system can be set selecting using the id of one of the existing coordinates, the material
# coordinate system (-1), the global coordinate system (0), an user defined in that moment (-10 and setting v1, v2)
# or a user defined system set with the method N2PModelContent.
# - v1 and v2 set a user defined coordinate system. v1 is x axis and v2 set the xt plane
model.get_load_case(17500).get_result("STRESSES").get_component("XY").get_result_ndarray(coordsys=-10, v1=(0,0,-1), v2=(0,0.5,0.5))
# Using a different user defined coordinate system for each element:
model.set_user_coord_sys(
[ [39900000,0,1,0,0,0,1,0],
[39900001,0,0.3,0.2,0,0,1,0],
[39900002,0,0,1,0,1,1,0],
[39900003,0,2,0,1,0.4,1,3] ],
"ELEMENTS"
)
model.get_load_case(17500).get_result("STRESSES").get_component("YY").get_result_ndarray(coordsys=-20)
# The second way to call the result arrays is using get_result_by_LCs_Incr(). This N2PModelContent method
# is really useful when there are lots of load cases, as it can load them in parallel.
# Select the loadcase-increment needed:
lcs_incr = [(17500, 1),(17501, 1),(17502, 1),(17503, 1)]
# Call the method. It requires a result (only one result) and a component or a list of components
result = model.get_result_by_LCs_Incr(lcs_incr, "STRESSES", "XX")
results = model.get_result_by_LCs_Incr(lcs_incr, "STRESSES", ["XX", "XY", "YY"])
# They return a dictionary with the results asked
# Optional arguments are the same as get_result_ndarray()
results_mat = model.get_result_by_LCs_Incr(lcs_incr, "STRESSES", ["XX", "XY", "YY"], coordsys=-1)
3.3 Load Case Combination#
"""
The script shows how to generate derived load cases. These load cases can be:
- Combination of load cases
- Envelope of load cases
"""
import NaxToPy as n2p
model = n2p.load_model(r"C:\Data\models\subcase\subcase_17500.op2")
model.import_results_from_files([
r"C:\Data\models\subcase\subcase_17501.op2",
r"C:\Data\models\subcase\subcase_17502.op2",
r"C:\Data\models\subcase\subcase_17503.op2"
])
print(model.LoadCases)
# To create a new derived load case by combination of them. It requires two arguments:
# - name: A str for the name of the load case
# - formula: a str with the combination of the load cases. Each load case is introduced using
# <> and inside <> LCXX:FRYY where XX is the id of the loadcase and YY the id of the increment/frame
# operations are applied to this "variables".
dlc_1 = model.new_derived_loadcase("Derived-1", "<LC17500:FR1>+2*<LC17501:FR1>+0.5*<LC17502:FR1>")
# There are python tools to write it faster and eficiently. Imagine LC 17500 is the thermal and the
# other are the mechanical. As i want ultimate combination y multiply by 1.5 only mechanical:
ultimate_lcs = list()
for lc in model.LoadCases[1:]:
ultimate_lcs.append(model.new_derived_loadcase(f"{lc.ID}_UL", f"1.5*<LC{lc.ID}:FR:1>+<LC17500:FR:1>"))
# The id of the derived loadcase will be negative and are created internally. Derived load cases only have
# one increment, with id 0.
# Now it can be used as an original load case:
x = dlc_1.get_result("DISPLACEMENTS").get_component("X").get_result_ndarray()
derived_derived_lc = model.new_derived_loadcase("Derived-1", "<LC-1:FR0>+<LC17501:FR1>") # Id -1 and increment 0
yy = model.get_result_by_LCs_Incr((-1, 0), "STRESSES", "YY")
print(model.LoadCases)
# To create an envelope load case it requires two arguments (name, formula) plus two optional (criteria, envelgroup).
# formula is similar to a combination loadcase but the lc_incr are separated by commas. The criteria may be the ExtremeMax
# (selects max absolute, by default), max, min, range nad ExtremeMin. envelgroup set if the results must be the critical value,
# the critical load case or the critical increment.
env = model.new_envelope_loadcase("env_1", "<LC17500:FR1>,<LC17501:FR1>", criteria="ExtremeMax", envelgroup="ByContour")
# using python tools is easy to build long formulas. Formula with all the loadcases (including combination ones)
formula = ",".join([f"<LC{lc.ID}:FR{lc.N2ActiveIncrement.ID}>" for lc in model.LoadCases])
env2_val = model.new_envelope_loadcase("env_2", formula, envelgroup="ByContour")
env3_val = model.new_envelope_loadcase("env_3", formula, envelgroup="ByLoadCaseID")
results = env3_val.get_result("STRESSES").get_component("VON_MISES_DERIVED").get_result_ndarray()
final_resuts = model.get_load_case(results[0][10])
# Now they can be use as any other load case
env2_val.get_result("STRESSES").get_component("XX").get_result_ndarray()[0]
env3_val.get_result("STRESSES").get_component("XX").get_result_ndarray()[0]
3.4 Derived Components#
"""Derived components can be cretaed using existing ones"""
import NaxToPy as n2p
model = n2p.load_model(r"C:\Data\models\subcase\subcase_17500.op2")
model.import_results_from_files([
r"C:\Data\models\subcase\subcase_17501.op2",
r"C:\Data\models\subcase\subcase_17502.op2",
r"C:\Data\models\subcase\subcase_17503.op2"
])
lc_17500 = model.LoadCases[0]
stresses = lc_17500.get_result("STRESSES")
# The derived components are created from a N2PResult. It requires a name and the formula.
# In the formula, the base components are selected using <> and placing inside "CPMT_" plus
# the name of the result, plus ":" plus the name of the component.
stresses.new_derived_component("vonmisses", "sqrt(<CMPT_STRESSES:XX>^2+<CMPT_STRESSES:YY>^2-<CMPT_STRESSES:XX>*<CMPT_STRESSES:YY>+3*<CMPT_STRESSES:XY>^2)")
# Now this component can be used as the originals are used
vonmisses = stresses.get_component("vonmisses").get_result_ndarray()
# Derived components are really useful in the case of envelope load cases. This is cause if the original component
# VON_MISSES is asked in a envelope load case it will return the maximum of the von mises, what it is wrong. The
# value is conservative, but not true, because the actual value requires to calculate the maximum of the base components
# of the stress tensor (XX, XY, YY in the plane) and then with those values calculate the von mises.
formula = ",".join([f"<LC{lc.ID}:FR{lc.N2ActiveIncrement.ID}>" for lc in model.LoadCases])
env_val = model.new_envelope_loadcase("env", formula, envelgroup="ByContour")
stresses_env = env_val.get_result("STRESSES")
vonmisses_env = stresses_env.new_derived_component("vonmisses_env", "sqrt(<CMPT_STRESSES:XX>^2+<CMPT_STRESSES:YY>^2-<CMPT_STRESSES:XX>*<CMPT_STRESSES:YY>+3*<CMPT_STRESSES:XY>^2)")
vonmisses_array = vonmisses_env.get_result_ndarray()
© 2025 Idaero Solutions S.L.
All rights reserved. This document is licensed under the terms of the LICENSE of the NaxToPy package.