NaxToPy 2.0.1__tar.gz → 2.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. {naxtopy-2.0.1/src/NaxToPy.egg-info → naxtopy-2.1.1}/PKG-INFO +16 -2
  2. {naxtopy-2.0.1 → naxtopy-2.1.1}/README.md +15 -1
  3. {naxtopy-2.0.1 → naxtopy-2.1.1}/pyproject.toml +1 -1
  4. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PComponent.py +7 -0
  5. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PElement.py +15 -0
  6. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PModelInputData.py +164 -11
  7. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PNode.py +15 -0
  8. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PProperty.py +3 -0
  9. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PResult.py +16 -5
  10. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Constants/Constants.py +4 -4
  11. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Errors/N2PLog.py +350 -0
  12. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/N2PModelContent.py +122 -4
  13. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Modules/N2PtoEXE/N2PtoEXE.py +26 -2
  14. naxtopy-2.1.1/src/NaxToPy/Modules/__init__.py +2 -0
  15. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/user_functions.txt +2 -0
  16. {naxtopy-2.0.1 → naxtopy-2.1.1/src/NaxToPy.egg-info}/PKG-INFO +16 -2
  17. naxtopy-2.0.1/src/NaxToPy/Modules/__init__.py +0 -2
  18. {naxtopy-2.0.1 → naxtopy-2.1.1}/LICENSE +0 -0
  19. {naxtopy-2.0.1 → naxtopy-2.1.1}/setup.cfg +0 -0
  20. {naxtopy-2.0.1 → naxtopy-2.1.1}/setup.py +0 -0
  21. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/AllClasses.py +0 -0
  22. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PConnector.py +0 -0
  23. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PCoord.py +0 -0
  24. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PFreeBody.py +0 -0
  25. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PIncrement.py +0 -0
  26. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PLoadCase.py +0 -0
  27. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PMaterial.py +0 -0
  28. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PReport.py +0 -0
  29. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PSection.py +0 -0
  30. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/N2PSet.py +0 -0
  31. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/ProgresBar.py +0 -0
  32. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Classes/__init__.py +0 -0
  33. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Constants/__init__.py +0 -0
  34. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Constants/librerias.py +0 -0
  35. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Errors/N2PColors.py +0 -0
  36. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Errors/N2PFileHandler.py +0 -0
  37. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Errors/__init__.py +0 -0
  38. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Reference_Finder/__Reference_Finder.py +0 -0
  39. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/Reference_Finder/__init__.py +0 -0
  40. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/_AuxFunc/_NetToPython.py +0 -0
  41. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/_AuxFunc/__init__.py +0 -0
  42. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Core/__init__.py +0 -0
  43. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Modules/Fasteners/N2PUpdateFastener.py +0 -0
  44. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Modules/Fasteners/__init__.py +0 -0
  45. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Modules/N2PEnvelope/N2PEnvelope.py +0 -0
  46. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Modules/N2PEnvelope/__init__.py +0 -0
  47. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/Modules/N2PtoEXE/__init__.py +0 -0
  48. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/NaxToPy.ico +0 -0
  49. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy/__init__.py +0 -0
  50. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy.egg-info/SOURCES.txt +0 -0
  51. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy.egg-info/dependency_links.txt +0 -0
  52. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy.egg-info/requires.txt +0 -0
  53. {naxtopy-2.0.1 → naxtopy-2.1.1}/src/NaxToPy.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: NaxToPy
3
- Version: 2.0.1
3
+ Version: 2.1.1
4
4
  Summary: Package for postprocessing FEM results in Python
5
5
  Home-page: https://www.idaerosolutions.com/Home/NaxToPy
6
6
  Download-URL: https://apps.microsoft.com/detail/XP9MMH0KDKGRJN?hl=en-US&gl=US
@@ -147,7 +147,7 @@ links on the left).
147
147
  **NaxToPy** is a powerful tool for FEM analysis post-processing!
148
148
 
149
149
  **CAUTION:** To use NaxToPy, [**NaxTo**](https://apps.microsoft.com/detail/XP9MMH0KDKGRJN?hl=en-US&gl=US) must be installed.
150
- This version is compatible with **NaxTo 2024.1**. It is compatible with all the steps of this version (2024.1.0, 2024.1.1, 2024.1.2, etc.).
150
+ This version is compatible with **NaxTo 2024.2**. It is compatible with all the steps of this version (2024.2.0, 2024.2.1, 2024.2.2, etc.).
151
151
  Check in _Programs and Features_ the NaxTo version that is installed.
152
152
 
153
153
  ## Installation
@@ -269,6 +269,20 @@ the LoadCases that are critical or the Increment that is critical instead of the
269
269
  It uses an object instaed of an int.
270
270
  3. Update of the examples of some docstrings.
271
271
 
272
+ ### v.2.1.0
273
+ 1. Reading a Natran Input File: SPC and SCP1 are now supported.
274
+ 2. Bug fix. The order in the components in new_report() does not affect now.
275
+ 3. Formula check in new_derived_loadcase(), new_enevelope_loadcase() and new_derived_component().
276
+ 4. New optional arguments if n2ptoexe() to add extra libaries, packages or files.
277
+
278
+ ### v.2.1.1
279
+ 1. Two new methods in N2PModelContent: load_user_coord_sys_from_csv() and set_user_coord_sys().
280
+ Also there is a new property for N2PElement and N2PNode: UserSystemArray. This update allow the
281
+ user to define a different coordinate system for each element or node. To ask for the results
282
+ in this system, the optional argument `coordsys` must be equal to `-20`.
283
+ 2. Bug fix: The checking for component and section in new_report() has been fixed. If a comma
284
+ appeared in the component or section name, the method failed.
285
+
272
286
  # Documentation
273
287
 
274
288
  **NaxToPy** is a package developed by Idaero Solutions© as a part of the **NaxTo** software.
@@ -23,7 +23,7 @@ links on the left).
23
23
  **NaxToPy** is a powerful tool for FEM analysis post-processing!
24
24
 
25
25
  **CAUTION:** To use NaxToPy, [**NaxTo**](https://apps.microsoft.com/detail/XP9MMH0KDKGRJN?hl=en-US&gl=US) must be installed.
26
- This version is compatible with **NaxTo 2024.1**. It is compatible with all the steps of this version (2024.1.0, 2024.1.1, 2024.1.2, etc.).
26
+ This version is compatible with **NaxTo 2024.2**. It is compatible with all the steps of this version (2024.2.0, 2024.2.1, 2024.2.2, etc.).
27
27
  Check in _Programs and Features_ the NaxTo version that is installed.
28
28
 
29
29
  ## Installation
@@ -145,6 +145,20 @@ the LoadCases that are critical or the Increment that is critical instead of the
145
145
  It uses an object instaed of an int.
146
146
  3. Update of the examples of some docstrings.
147
147
 
148
+ ### v.2.1.0
149
+ 1. Reading a Natran Input File: SPC and SCP1 are now supported.
150
+ 2. Bug fix. The order in the components in new_report() does not affect now.
151
+ 3. Formula check in new_derived_loadcase(), new_enevelope_loadcase() and new_derived_component().
152
+ 4. New optional arguments if n2ptoexe() to add extra libaries, packages or files.
153
+
154
+ ### v.2.1.1
155
+ 1. Two new methods in N2PModelContent: load_user_coord_sys_from_csv() and set_user_coord_sys().
156
+ Also there is a new property for N2PElement and N2PNode: UserSystemArray. This update allow the
157
+ user to define a different coordinate system for each element or node. To ask for the results
158
+ in this system, the optional argument `coordsys` must be equal to `-20`.
159
+ 2. Bug fix: The checking for component and section in new_report() has been fixed. If a comma
160
+ appeared in the component or section name, the method failed.
161
+
148
162
  # Documentation
149
163
 
150
164
  **NaxToPy** is a package developed by Idaero Solutions© as a part of the **NaxTo** software.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "NaxToPy"
7
- version = "2.0.1"
7
+ version = "2.1.1"
8
8
  license = {file = "LICENSE"}
9
9
  authors = [ { name = "Idaero Solutions", email = "manuel.sanchez@idaerosolutions.com" }, ]
10
10
  requires-python = ">=3.9"
@@ -122,6 +122,7 @@ class N2PComponent:
122
122
  0 : Global,
123
123
  -1 : Material Coordinate System,
124
124
  -10 : User defined,
125
+ -20 : Element/Node User Defined,
125
126
  >0 : Solver ID of the Predefined Coordinate System.
126
127
 
127
128
  v1: tuple -> Optional.
@@ -214,6 +215,7 @@ class N2PComponent:
214
215
  0 : Global,
215
216
  -1 : Material Coordinate System,
216
217
  -10 : User defined,
218
+ -20 : Element/Node User Defined,
217
219
  >0 : Solver ID of the Predefined Coordinate System.
218
220
 
219
221
  v1: tuple -> Optional.
@@ -287,6 +289,7 @@ class N2PComponent:
287
289
  # 0 : Global,
288
290
  # -1 : Material Coordinate System,
289
291
  # -10 : User defined,
292
+ # -20 : Element/Node User Defined,
290
293
  # >0 : Solver ID of the Predefined Coordinate System.
291
294
  #
292
295
  # v1: tuple
@@ -442,6 +445,10 @@ class N2PComponent:
442
445
  resultsParameters = N2ParamInputResults.structResults(0)
443
446
  resultsParameters.coordSys = coordsys
444
447
 
448
+ elif coordsys == -20:
449
+ resultsParameters = N2ParamInputResults.structResults(0)
450
+ resultsParameters.coordSys = coordsys
451
+
445
452
  else:
446
453
  N2PLog.Error.E220()
447
454
  return (-1, 'NO RESULTS')
@@ -128,6 +128,21 @@ class N2PElement:
128
128
  return [all_centroids[iid, i] for i in range(3)]
129
129
  # ------------------------------------------------------------------------------------------------------------------
130
130
 
131
+ # Metodo para el sistema de usuario del elemento -------------------------------------------------------------------
132
+ @property
133
+ def UserSystemArray(self) -> list[float, ...]:
134
+ """
135
+ Returns list with the position of the three vectors that define the user system of the element:
136
+ [x1, x2, x3, y1, y2, y3, z1, z2, z3]
137
+
138
+ If no user systems for elements are defined yet, it returns None.
139
+ """
140
+ user_system_array = self.__model__._N2PModelContent__vzmodel.ElementUserCoordinateSystems
141
+ if not user_system_array:
142
+ return None
143
+ return [user_system_array[self.InternalID, i] for i in range(9)]
144
+ # ------------------------------------------------------------------------------------------------------------------
145
+
131
146
  # Special Method for Object Representation -------------------------------------------------------------------------
132
147
  def __repr__(self):
133
148
  return f"N2PElement({self.ID}, \'{self.PartID}\')"
@@ -12415,18 +12415,168 @@ class RSPLINE(N2PCard):
12415
12415
  self.__cardinfo.C[i] = val
12416
12416
 
12417
12417
 
12418
+ class SPC(N2PCard):
12419
+
12420
+ def __init__(self, cardinfo):
12421
+ super().__init__(cardinfo)
12422
+ self.__cardinfo = cardinfo
12423
+
12424
+ @property
12425
+ def CharName(self) -> str:
12426
+ """
12427
+ Card code (SPC)
12428
+ """
12429
+ return self.__cardinfo.CharName
12430
+
12431
+ @CharName.setter
12432
+ def CharName(self, value: str) -> None:
12433
+ self.__cardinfo.CharName = value
12434
+
12435
+ @property
12436
+ def SID(self) -> int:
12437
+ """
12438
+ Identification number of the single-point constraint set
12439
+ """
12440
+ return self.__cardinfo.SID
12441
+
12442
+ @SID.setter
12443
+ def SID(self, value: int) -> None:
12444
+ self.__cardinfo.SID = value
12445
+
12446
+ @property
12447
+ def G1(self) -> int:
12448
+ """
12449
+ Grid point identification number of connection points. (Integer > 0)
12450
+ GA
12451
+ """
12452
+ return self.__cardinfo.G1
12453
+
12454
+ @G1.setter
12455
+ def G1(self, value: int) -> None:
12456
+ self.__cardinfo.G1 = value
12457
+
12458
+ @property
12459
+ def C1(self) -> int:
12460
+ """
12461
+ C1
12462
+ """
12463
+ return self.__cardinfo.C1
12464
+
12465
+ @C1.setter
12466
+ def C1(self, value: int) -> None:
12467
+ self.__cardinfo.C1 = value
12468
+
12469
+
12470
+ @property
12471
+ def D1(self) -> float:
12472
+ """
12473
+ D1: enforced motion for components C1 at G1
12474
+ """
12475
+ return self.__cardinfo.D1
12476
+
12477
+ @D1.setter
12478
+ def D1(self, value: float) -> None:
12479
+ self.__cardinfo.D1 = value
12480
+
12481
+ @property
12482
+ def G2(self) -> int:
12483
+ """
12484
+ Grid point identification number of connection points. (Integer > 0)
12485
+ GA
12486
+ """
12487
+ return self.__cardinfo.G2
12488
+
12489
+ @G2.setter
12490
+ def G2(self, value: int) -> None:
12491
+ self.__cardinfo.G2 = value
12492
+
12493
+ @property
12494
+ def C2(self) -> int:
12495
+ """
12496
+ C2
12497
+ """
12498
+ return self.__cardinfo.C2
12499
+
12500
+ @C2.setter
12501
+ def C2(self, value: int) -> None:
12502
+ self.__cardinfo.C2 = value
12503
+
12504
+
12505
+ @property
12506
+ def D2(self) -> float:
12507
+ """
12508
+ D2: enforced motion for components C2 at G2
12509
+ """
12510
+ return self.__cardinfo.D2
12511
+
12512
+ @D2.setter
12513
+ def D2(self, value: float) -> None:
12514
+ self.__cardinfo.D2 = value
12515
+
12516
+
12517
+ class SPC1(N2PCard):
12518
+
12519
+ def __init__(self, cardinfo):
12520
+ super().__init__(cardinfo)
12521
+ self.__cardinfo = cardinfo
12522
+
12523
+ @property
12524
+ def CharName(self) -> str:
12525
+ """
12526
+ Card code (SPC1)
12527
+ """
12528
+ return self.__cardinfo.CharName
12529
+
12530
+ @CharName.setter
12531
+ def CharName(self, value: str) -> None:
12532
+ self.__cardinfo.CharName = value
12533
+
12534
+ @property
12535
+ def SID(self) -> int:
12536
+ """
12537
+ Identification number of the single-point constraint set
12538
+ """
12539
+ return self.__cardinfo.SID
12540
+
12541
+ @SID.setter
12542
+ def SID(self, value: int) -> None:
12543
+ self.__cardinfo.SID = value
12544
+
12545
+ @property
12546
+ def C(self) -> int:
12547
+ """
12548
+ Component numbers: 123456
12549
+ """
12550
+ return self.__cardinfo.C
12551
+
12552
+ @C.setter
12553
+ def C(self, value: int) -> None:
12554
+ self.__cardinfo.C = value
12555
+
12556
+
12557
+ @property
12558
+ def Grids(self) -> list[int, ...]:
12559
+ """
12560
+ Grid or scalar point identification numbers
12561
+ """
12562
+ return self.__cardinfo.NodeArray
12563
+
12564
+ @C.setter
12565
+ def Grids(self, value: list[int, ...]) -> None:
12566
+ self.__cardinfo.NodeArray = value
12567
+
12418
12568
  # Diccionario con todas clases.
12419
12569
  CONSTRUCTDICT = {"CBAR": CBAR,
12420
- "CBEAM": CBEAM,
12421
- "CBUSH": CBUSH,
12422
- "CELAS1": CELAS1,
12423
- "CELAS2": CELAS2,
12424
- "CELAS3": CELAS3,
12425
- "CELAS4": CELAS4,
12426
- "CFAST": CFAST,
12427
- "CHEXA_NASTRAN": CHEXANAS,
12428
- "CHEXA_OPTISTRUCT": CHEXAOPT,
12429
- "CONM2": CONM2,
12570
+ "CBEAM": CBEAM,
12571
+ "CBUSH": CBUSH,
12572
+ "CELAS1": CELAS1,
12573
+ "CELAS2": CELAS2,
12574
+ "CELAS3": CELAS3,
12575
+ "CELAS4": CELAS4,
12576
+ "CFAST": CFAST,
12577
+ "CHEXA_NASTRAN": CHEXANAS,
12578
+ "CHEXA_OPTISTRUCT": CHEXAOPT,
12579
+ "CONM2": CONM2,
12430
12580
  "CORD1C": CORD1C,
12431
12581
  "CORD1R": CORD1R,
12432
12582
  "CORD1S": CORD1S,
@@ -12485,4 +12635,7 @@ CONSTRUCTDICT = {"CBAR": CBAR,
12485
12635
  "RBE2": RBE2,
12486
12636
  "RBE3": RBE3,
12487
12637
  "RSPLINE": RSPLINE,
12488
- "UNSUPPORTED": N2PCard}
12638
+ "SPC": SPC,
12639
+ "SPC1": SPC1,
12640
+ "UNSUPPORTED": N2PCard
12641
+ }
@@ -148,6 +148,21 @@ class N2PNode:
148
148
  return [celllist[cell_iid] for cell_iid in cs_list]
149
149
  # ---------------------------------------------------------------------------------------------
150
150
 
151
+ # Metodo para el sistema de usuario del nodo -----------------------------------------------------------------------
152
+ @property
153
+ def UserSystemArray(self) -> list[float, ...]:
154
+ """
155
+ Returns list with the position of the three vectors that define the user system of the node:
156
+ [x1, x2, x3, y1, y2, y3, z1, z2, z3]
157
+
158
+ If no user systems for nodes are defined yet, it returns None.
159
+ """
160
+ user_system_array = self.__model__._N2PModelContent__vzmodel.NodeUserCoordinateSystems
161
+ if not user_system_array:
162
+ return None
163
+ return [user_system_array[self.InternalID, i] for i in range(9)]
164
+ # ------------------------------------------------------------------------------------------------------------------
165
+
151
166
  # Special Method for Object Representation -------------------------------------------------------------------------
152
167
  def __repr__(self):
153
168
  return f"N2PNode({self.ID}, \'{self.PartID}\')"
@@ -180,6 +180,9 @@ class N2PComp(N2PProperty):
180
180
  def QMatrix(self,i) -> np.ndarray:
181
181
  """
182
182
  Returns the lamina stiffness matrix (Q-Bar) as a numpy 2D array
183
+ | σx | | ε |
184
+ | σy | = [Q]*| ε |
185
+ | τxy| | γ/2 |
183
186
 
184
187
  """
185
188
 
@@ -1,6 +1,8 @@
1
1
  from NaxToPy.Core.Classes.N2PComponent import N2PComponent
2
2
  from NaxToPy.Core.Errors.N2PLog import N2PLog
3
3
  from NaxToModel import N2Component
4
+ from NaxToModel import N2ArithmeticSolver
5
+ from NaxToModel import N2ErrorWarnningHandling
4
6
  from System.Collections.Generic import List
5
7
 
6
8
 
@@ -162,17 +164,17 @@ class N2PResult:
162
164
 
163
165
  The `Result|Component` must have this structure: `<CMPT_Result:Component>` or `<CMPTD:Component>`.
164
166
 
165
- Examples:
166
- - formula = "<0.5*CMPT_DISPLACEMENTS:MAGNITUDE_D>+2*<CMPT_DISPLACEMENTS:MAGNITUDE_R>"
167
- - formula = "(<CMPTD:Example>-2*<CMPT_DISPLACEMENTS:MAGNITUDE_R>)^2"
168
- - formula = "sqrt(<CMPT_STRESSES:XX>^2+<CMPT_STRESSES:YY>^2-<CMPT_STRESSES:XX>*<CMPT_STRESSES:YY>+3*<CMPT_STRESSES:XY>^2)"
169
-
170
167
  Args:
171
168
  name (str): The name of the component.
172
169
  formula (str): String containing the Result:Component intended to be used and the arithmetic operations.
173
170
 
174
171
  Returns:
175
172
  N2PComponent: Derived load case.
173
+
174
+ Examples:
175
+ >>> N2PResult.new_derived_component("dev_comp1", formula="<0.5*CMPT_DISPLACEMENTS:MAGNITUDE_D>+2*<CMPT_DISPLACEMENTS:MAGNITUDE_R>")
176
+ >>> N2PResult.new_derived_component("dev_comp2", formula="(<CMPTD:Example>-2*<CMPT_DISPLACEMENTS:MAGNITUDE_R>)^2"
177
+ >>> N2PResult.new_derived_component("dev_comp3", formula="sqrt(<CMPT_STRESSES:XX>^2+<CMPT_STRESSES:YY>^2-<CMPT_STRESSES:XX>*<CMPT_STRESSES:YY>+3*<CMPT_STRESSES:XY>^2)")
176
178
  """
177
179
 
178
180
  # Recuperamos la instancia N2ModelModelContent
@@ -192,6 +194,15 @@ class N2PResult:
192
194
  # Call the method that recalculate the data.
193
195
  new_d_comp.RecalculateCMPTInfo2Formule()
194
196
 
197
+ # Este metodo de N2ArithmeticSolver en NaxToModel comprueba que la formula introducida es correcta.
198
+ # Devuelve False si está mal y True si está bien.
199
+ err = N2ArithmeticSolver.CheckExpression(new_d_comp.Formula, mc, N2ArithmeticSolver.ExpressionType.COMPONENT)
200
+ if int(err) == 0:
201
+ pass
202
+ else:
203
+ N2PLog.Error.E230(formula, (formula, str(N2ErrorWarnningHandling.GetDescription(err).upper())) ) # error
204
+ return "ERROR"
205
+
195
206
  # The N2PComponent is instanced and added to the dictionary of derived loadcases:
196
207
  self.__derived_comps__[new_d_comp.Name] = N2PComponent(new_d_comp.Name, new_d_comp.Sections, self)
197
208
 
@@ -1,14 +1,14 @@
1
1
  """Constants of the NaxToPy package"""
2
2
 
3
3
  # NaxToPy Version
4
- VERSION = "2.0.1"
4
+ VERSION = "2.1.1"
5
5
 
6
6
  # Supported for Naxto:
7
- NAXTO_VERSION = '2024R1'
8
- NAXTO_STEP = "2"
7
+ NAXTO_VERSION = '2024R2'
8
+ NAXTO_STEP = "1"
9
9
 
10
10
  # Assembly version of NaxToModel.dll
11
- VIZZER_COMPATIBILITY = ("4.1.0.0", "4.1.0.1", "4.1.0.2")
11
+ VIZZER_COMPATIBILITY = ("4.2.0.0", "4.2.0.1")
12
12
  """Tuple with the compatible versions of NaxToModel.dll"""
13
13
 
14
14
  # PYTHON EXTERNO ----------------------------------------------------------------------------------
@@ -192,6 +192,41 @@ class N2PLog(ABC):
192
192
  """
193
193
  message = f"D504: Model loading time: {current_time-tinit} s"
194
194
  N2PLog._N2PLog__logger.info(message)
195
+
196
+ @staticmethod
197
+ def D600(current_time, tinit) -> None:
198
+ """ Information given for result obtention time.
199
+ """
200
+ message = f"D600: Result obtention time: {current_time - tinit} s"
201
+ N2PLog._N2PLog__logger.info(message)
202
+
203
+ @staticmethod
204
+ def D601(current_time, tinit) -> None:
205
+ """ Information given for fasteners obtention time.
206
+ """
207
+ message = f"D601: Fasteners obtention time: {current_time - tinit} s"
208
+ N2PLog._N2PLog__logger.info(message)
209
+
210
+ @staticmethod
211
+ def D602(current_time, tinit) -> None:
212
+ """ Information given for fasteners analysis time.
213
+ """
214
+ message = f"D602: Fasteners analysis time: {current_time - tinit} s"
215
+ N2PLog._N2PLog__logger.info(message)
216
+
217
+ @staticmethod
218
+ def D603(current_time, tinit) -> None:
219
+ """ Information given for fasteners attachments obtention time.
220
+ """
221
+ message = f"D603: Fasteners attachments obtention time: {current_time - tinit} s"
222
+ N2PLog._N2PLog__logger.info(message)
223
+
224
+ @staticmethod
225
+ def D604(current_time, tinit) -> None:
226
+ """ Information given for fasteners whole calculation time.
227
+ """
228
+ message = f"D604: Fasteners whole calculation time: {current_time - tinit} s"
229
+ N2PLog._N2PLog__logger.info(message)
195
230
  # ------------------------------------------------------------------------------------------------------------------
196
231
 
197
232
  ############################################ INFO ################################################################
@@ -341,7 +376,19 @@ own information message. Use the following structure as a standard message (I +
341
376
  N2PLog._N2PLog__logger.info(message)
342
377
 
343
378
 
379
+ @staticmethod
380
+ def I500() -> None:
381
+ """ Information given when the ID list is empty.
382
+ """
383
+ message = f"I500: All load cases will be studied because no ID list was given."
384
+ N2PLog._N2PLog__logger.info(message)
344
385
 
386
+ @staticmethod
387
+ def I501() -> None:
388
+ """ Information given when the ID list is empty.
389
+ """
390
+ message = f"I501: All fasteners will be studied because no ID list was given."
391
+ N2PLog._N2PLog__logger.info(message)
345
392
  # ------------------------------------------------------------------------------------------------------------------
346
393
 
347
394
  ########################################### WARNING ##############################################################
@@ -471,6 +518,146 @@ own information message. Use the following structure as a standard message (I +
471
518
  message = f"W301: the name for the new load case already exist. It has been rename to '{name}'"
472
519
  N2PLog._N2PLog__logger.warning(message)
473
520
 
521
+
522
+ @staticmethod
523
+ def W500(listids) -> None:
524
+ """ Warning raised when a CBUSH or CBAR has not a defined Diameter.
525
+ """
526
+ message = f"W500: Fasteners {listids} have not a defined Diameter and are either CBUSH or CBAR. The input diameter needs to be used"
527
+ N2PLog._N2PLog__logger.warning(message)
528
+
529
+ @staticmethod
530
+ def W501(bolt) -> None:
531
+ """ Warning raised when a CBUSH is defined with coincident nodes.
532
+ """
533
+ message = f"W501: CBUSH {bolt.ID} is discarded for the study because it is defined with coincident nodes"
534
+ N2PLog._N2PLog__logger.warning(message)
535
+
536
+ @staticmethod
537
+ def W502(bolt) -> None:
538
+ """ Warning raised when a CFAST is defined as PROP.
539
+ """
540
+ message = f"W502: CFAST {bolt.ID} ignored: defined as PROP."
541
+ N2PLog._N2PLog__logger.warning(message)
542
+
543
+ @staticmethod
544
+ def W503(bolt) -> None:
545
+ """ Warning raised when a Fastener property is not found.
546
+ """
547
+ message = f"W503: Fastener {bolt.ID} ignored: property not found."
548
+ N2PLog._N2PLog__logger.warning(message)
549
+
550
+ @staticmethod
551
+ def W504(bolt) -> None:
552
+ """ Warning raised when a Fastener plates are not found.
553
+ """
554
+ message = f"W504: Fastener {bolt.ID} ignored: plates not found."
555
+ N2PLog._N2PLog__logger.warning(message)
556
+
557
+ @staticmethod
558
+ def W505(bolt) -> None:
559
+ ''' Warning raised when a fastener element is not found.
560
+ '''
561
+ message = f"W505: Fastener {bolt.ID} skipped. Element not found."
562
+ N2PLog._N2PLog__logger.warning(message)
563
+
564
+ @staticmethod
565
+ def W506(bolt) -> None:
566
+ ''' Warning raised when a fastener intersection with the plate is not found.
567
+ '''
568
+ message = f"W506: Fastener {bolt.ID} ignored: intersection with the plate not found."
569
+ N2PLog._N2PLog__logger.warning(message)
570
+
571
+ @staticmethod
572
+ def W507(bolt) -> None:
573
+ ''' Warning raised when different types of properties found in the same joined plate elements.
574
+ '''
575
+ message = f"W507: Different types of properties found in the same joined plate elements: not consistent. Fastener {bolt.ID} ignored."
576
+ N2PLog._N2PLog__logger.warning(message)
577
+
578
+ @staticmethod
579
+ def W508(bolt) -> None:
580
+ ''' Warning raised when direction of elements 1D wrt connected plates not consistent.
581
+ '''
582
+ message = f"W508: Direction of elements 1D wrt connected plates not consistent. Fastener {bolt.ID} ignored."
583
+ N2PLog._N2PLog__logger.warning(message)
584
+
585
+ @staticmethod
586
+ def W509(bolt) -> None:
587
+ ''' Warning raised when different type of elements 1D in the same bolt.
588
+ '''
589
+ message = f"W509: Different type of elements 1D in the same bolt: not consistent. Fastener {bolt.ID} ignored."
590
+ N2PLog._N2PLog__logger.warning(message)
591
+
592
+ @staticmethod
593
+ def W510(listids) -> None:
594
+ ''' Warning raised when a fastener has not a provided head position.
595
+ '''
596
+ message = f"W510: Fasteners {listids} have not a provided head position, so the inner element 1D order is set indistinctly."
597
+ N2PLog._N2PLog__logger.warning(message)
598
+
599
+ @staticmethod
600
+ def W511() -> None:
601
+ ''' Warning raised when calculation using the results in the centroid.
602
+ '''
603
+ message = f"W511: Calculation using the results in the centroid may not be as precise as when Corner Data used."
604
+ N2PLog._N2PLog__logger.warning(message)
605
+
606
+ @staticmethod
607
+ def W512(plate, bolt) -> None:
608
+ ''' Warning raised when element not found.
609
+ '''
610
+ message = f"W512: Skipping plate {plate.ID} of bolt {bolt.ID}. Element not found."
611
+ N2PLog._N2PLog__logger.warning(message)
612
+
613
+ @staticmethod
614
+ def W513(bolt) -> None:
615
+ ''' Warning raised when intersection point with plate not defined.
616
+ '''
617
+ message = f"W513: Intersection point with plate not defined. Bypass calculation skipped in fastener {bolt.ID}."
618
+ N2PLog._N2PLog__logger.warning(message)
619
+
620
+ @staticmethod
621
+ def W514(bolt) -> None:
622
+ ''' Warning raised when normal to plate not defined.
623
+ '''
624
+ message = f"W514: Normal to plate not defined. Bypass calculation skipped in fastener {bolt.ID}."
625
+ N2PLog._N2PLog__logger.warning(message)
626
+
627
+ @staticmethod
628
+ def W515(bolt) -> None:
629
+ ''' Warning raised when distance to edge not defined.
630
+ '''
631
+ message = f"W515: Distance to edge not defined. Bypass calculation skipped in fastener {bolt.ID}."
632
+ N2PLog._N2PLog__logger.warning(message)
633
+
634
+ @staticmethod
635
+ def W516(bolt) -> None:
636
+ ''' Warning raised when no plate elements found.
637
+ '''
638
+ message = f"W516: No plate elements found. Bypass calculation skipped in fastener {bolt.ID}."
639
+ N2PLog._N2PLog__logger.warning(message)
640
+
641
+ @staticmethod
642
+ def W517() -> None:
643
+ ''' Warning raised when a plate is not an ARPlate.
644
+ '''
645
+ message = f"W517: Plate omitted. Incorrect class: Should be ARPlate."
646
+ N2PLog._N2PLog__logger.warning(message)
647
+
648
+ @staticmethod
649
+ def W518() -> None:
650
+ ''' Warning raised when a fastener is not an AR1DElement.
651
+ '''
652
+ message = f"W518: Fastener omitted. Incorrect class: Should be AR1DElement."
653
+ N2PLog._N2PLog__logger.warning(message)
654
+
655
+ @staticmethod
656
+ def W519(elem) -> None:
657
+ ''' Warning raised when a element is not CQUAD4 nor CTRIA3.
658
+ '''
659
+ message = f"W519: Element {elem.ID} is not CQUAD4 nor CTRIA3."
660
+ N2PLog._N2PLog__logger.warning(message)
474
661
  # ------------------------------------------------------------------------------------------------------------------
475
662
 
476
663
  ############################################ ERROR ###############################################################
@@ -581,6 +768,13 @@ own information message. Use the following structure as a standard message (I +
581
768
  message = f"E112: THE WINDOWS REGISTER COULDN'T BE MODIFIED. ERROR: {er}"
582
769
  N2PLog._N2PLog__logger.error(message)
583
770
 
771
+ @staticmethod
772
+ def E113(file) -> None:
773
+ """ Error raised when the Windows Register couldn't be modified
774
+ """
775
+ message = f"E113: THE FILE {file} DOESN'T EXIST OR COULDN'T BE FOUND"
776
+ N2PLog._N2PLog__logger.error(message)
777
+
584
778
  @staticmethod
585
779
  def E201(*args) -> None:
586
780
  ''' Error raised when the id of the node is not in the node dictionary.
@@ -783,6 +977,34 @@ own information message. Use the following structure as a standard message (I +
783
977
  message = f"E227: THE PROPERTY ID {-rep_id} IS REPEATED. ONE WILL BE SAVE WITH THE SIGN CHANGE"
784
978
  N2PLog._N2PLog__logger.error(message)
785
979
 
980
+ @staticmethod
981
+ def E228(formula, vz_msg) -> None:
982
+ ''' Error raised when the formula introduced for a new derived loadcase is wrong
983
+ '''
984
+ message = f"E228: THE FORMULA INTRODUCED TO CREATE A DERIVED LOAD CASE \"{formula}\" IS WRONG: {vz_msg}"
985
+ N2PLog._N2PLog__logger.error(message)
986
+
987
+ @staticmethod
988
+ def E229(formula, vz_msg) -> None:
989
+ ''' Error raised when the formula introduced for a new envelope loadcase is wrong
990
+ '''
991
+ message = f"E229: THE FORMULA INTRODUCED TO CREATE A ENVELOPE LOAD CASE \"{formula}\" IS WRONG: {vz_msg}"
992
+ N2PLog._N2PLog__logger.error(message)
993
+
994
+ @staticmethod
995
+ def E230(formula, vz_msg) -> None:
996
+ ''' Error raised when the formula introduced for a new derived component is wrong
997
+ '''
998
+ message = f"E230: THE FORMULA INTRODUCED TO CREATE DERIVED COMPONENT \"{formula}\" IS WRONG: {vz_msg}"
999
+ N2PLog._N2PLog__logger.error(message)
1000
+
1001
+ @staticmethod
1002
+ def E231() -> None:
1003
+ ''' Error raised when the argument "where" of load_user_coord_sys_from_csv is not "NODES" or "ELEMENTS"
1004
+ '''
1005
+ message = f"E231: THE ARGUMENT 'where' MUST BE 'ELEMENTS' OR 'NODES'"
1006
+ N2PLog._N2PLog__logger.error(message)
1007
+
786
1008
  @staticmethod
787
1009
  def E300(args) -> None:
788
1010
  ''' Error raised when the program fail to save the model (as a N2PModelContent object).
@@ -907,6 +1129,128 @@ own information message. Use the following structure as a standard message (I +
907
1129
  message = f"E311: YOUNG MODULUS COULD NOT BE FOUND FOR PROPERTY {propID}"
908
1130
  N2PLog._N2PLog__logger.error(message)
909
1131
 
1132
+
1133
+
1134
+ @staticmethod
1135
+ def E500() -> None:
1136
+ ''' Error raised when an element not found correctly when trying to create plates.
1137
+ '''
1138
+ message = f"E500: Element not found correctly or not supported."
1139
+ N2PLog._N2PLog__logger.error(message)
1140
+
1141
+ @staticmethod
1142
+ def E501() -> None:
1143
+ ''' Error raised when a prop not found correctly or it is not supported.
1144
+ '''
1145
+ message = f"E501: Property not found correctly or not supported."
1146
+ N2PLog._N2PLog__logger.error(message)
1147
+
1148
+ @staticmethod
1149
+ def E502() -> None:
1150
+ ''' Error raised when a mat not found correctly or it is not supported.
1151
+ '''
1152
+ message = f"E502: Material not found correctly or not supported."
1153
+ N2PLog._N2PLog__logger.error(message)
1154
+
1155
+ @staticmethod
1156
+ def E503(bolt) -> None:
1157
+ ''' Error raised when fastener is said to have the Head in a middle element1D.
1158
+ '''
1159
+ message = f"E503: Bad definition of fastener {bolt.ID}: said to have the Head in a middle element1D."
1160
+ N2PLog._N2PLog__logger.error(message)
1161
+
1162
+ @staticmethod
1163
+ def E504() -> None:
1164
+ ''' Error raised when load cases/s are not found.
1165
+ '''
1166
+ message = f"E504: Load cases/s not found."
1167
+ N2PLog._N2PLog__logger.error(message)
1168
+
1169
+ @staticmethod
1170
+ def E505(bolt) -> None:
1171
+ ''' Error raised when a fastener is not connected to 2 plates.
1172
+ '''
1173
+ message = f"E505: Fastener {bolt.ID} was not computed because it is not connected to 2 plates."
1174
+ N2PLog._N2PLog__logger.error(message)
1175
+
1176
+ @staticmethod
1177
+ def E506(bolt) -> None:
1178
+ ''' Error raised when a fastener diameter is not defined.
1179
+ '''
1180
+ message = f"E506: Diameter not defined. Bypass calculation skipped for fastener {bolt.ID}."
1181
+ N2PLog._N2PLog__logger.error(message)
1182
+
1183
+ @staticmethod
1184
+ def E507(bolt) -> None:
1185
+ ''' Error raised when iterations > max_iter.
1186
+ '''
1187
+ message = f"E507: Unable to calculate bypass loads in fastener {bolt.ID} because iterations > max_iter."
1188
+ N2PLog._N2PLog__logger.error(message)
1189
+
1190
+ @staticmethod
1191
+ def E508(bolt) -> None:
1192
+ ''' Error raised when there is a problem with the geometry of the fastener.
1193
+ '''
1194
+ message = f"E508: Fastener {bolt.ID} was not computed because there is a problem with its geometry."
1195
+ N2PLog._N2PLog__logger.error(message)
1196
+
1197
+ @staticmethod
1198
+ def E509(bolt) -> None:
1199
+ ''' Error raised when no forces were correctly retrieved.
1200
+ '''
1201
+ message = f"E509: Fastener {bolt.ID} discarded because no forces were correctly retrieved."
1202
+ N2PLog._N2PLog__logger.error(message)
1203
+
1204
+ @staticmethod
1205
+ def E510() -> None:
1206
+ ''' Error raised when there is an error in the isoparametric transformation.
1207
+ '''
1208
+ message = f"E510: Cannot obtain u and v in isoparametric transformation."
1209
+ N2PLog._N2PLog__logger.error(message)
1210
+
1211
+ @staticmethod
1212
+ def E511() -> None:
1213
+ ''' Error raised when elements are not supported in interpolation.
1214
+ '''
1215
+ message = f"E511: Interpolation only supported for triangular and quadrilateral elements."
1216
+ N2PLog._N2PLog__logger.error(message)
1217
+
1218
+ @staticmethod
1219
+ def E512() -> None:
1220
+ ''' Error raised when the number of components of the vector and the reference systems are not multiple of 3
1221
+ in the rotation.'''
1222
+ message = f"E512: The number of components of the vector and the reference systems must be multiple of 3."
1223
+ N2PLog._N2PLog__logger.error(message)
1224
+
1225
+ @staticmethod
1226
+ def E513() -> None:
1227
+ ''' Error raised when the type is not supported.'''
1228
+ message = f"E513: Not supported type. Not serializing."
1229
+ N2PLog._N2PLog__logger.error(message)
1230
+
1231
+ @staticmethod
1232
+ def E514() -> None:
1233
+ ''' Error raised when trying to serialize something that is not a list.'''
1234
+ message = f"E514: Can only serialize lists. Not serializing."
1235
+ N2PLog._N2PLog__logger.error(message)
1236
+
1237
+ @staticmethod
1238
+ def E515() -> None:
1239
+ ''' Error raised when trying to deserialize something that is not a list.'''
1240
+ message = f"E515: Not supported type. Not deserializing."
1241
+ N2PLog._N2PLog__logger.error(message)
1242
+
1243
+ @staticmethod
1244
+ def E516() -> None:
1245
+ ''' Error raised when trying to deserialize something that is not a list.'''
1246
+ message = f"E516: Can only deserialize lists. Not deserializing."
1247
+ N2PLog._N2PLog__logger.error(message)
1248
+
1249
+ @staticmethod
1250
+ def E517(listids) -> None:
1251
+ ''' Error raised when having fasteners with wrong diameter.'''
1252
+ message = f"E517: Fasteners {listids} will not be calculated because they have a wrong or no diameter definition."
1253
+ N2PLog._N2PLog__logger.error(message)
910
1254
  ########################################### CRITICAL #############################################################
911
1255
  class Critical:
912
1256
  """Class with all the critical errors.
@@ -1046,6 +1390,12 @@ own information message. Use the following structure as a standard message (I +
1046
1390
  message = "C200: NUMPY PACKAGE COULDN\'T BE INSTALLED. PLEASE, INSATALL IT MANUALY."
1047
1391
  N2PLog._N2PLog__logger.critical(message)
1048
1392
 
1393
+ @staticmethod
1394
+ def C500() -> None:
1395
+ """ Critical error raised when numpy couldn't be installed.
1396
+ """
1397
+ message = "C500: SOLVER NOT SUPPORTED."
1398
+ N2PLog._N2PLog__logger.critical(message)
1049
1399
  # ------------------------------------------------------------------------------------------------------------------
1050
1400
 
1051
1401
  ####################################################################################################################
@@ -4,6 +4,8 @@ from NaxToModel.Classes import N2AdjacencyFunctions
4
4
  from NaxToModel.Classes import N2FreeEdges
5
5
  from NaxToModel import EnvelopGroup
6
6
  from NaxToModel import EnvelopCriteria
7
+ from NaxToModel import N2ArithmeticSolver
8
+ from NaxToModel import N2ErrorWarnningHandling
7
9
  from NaxToPy.Core.Classes.N2PLoadCase import N2PLoadCase
8
10
  from NaxToPy.Core.Classes.N2PIncrement import N2PIncrement
9
11
  from NaxToPy.Core.Classes.N2PElement import N2PElement
@@ -19,6 +21,7 @@ from NaxToPy.Core.Classes.N2PSet import N2PSet
19
21
  from NaxToPy.Core.Classes.N2PModelInputData import *
20
22
  from NaxToPy.Core.Constants.Constants import BINARY_EXTENSIONS
21
23
  from NaxToPy.Core.Classes.N2PReport import N2PReport
24
+ from NaxToPy.Core._AuxFunc._NetToPython import _numpytonet
22
25
 
23
26
 
24
27
  import time
@@ -28,7 +31,7 @@ import os
28
31
  import array
29
32
  import System
30
33
  from collections import OrderedDict
31
- from typing import Union, overload
34
+ from typing import Union, overload, Literal
32
35
  from itertools import chain
33
36
 
34
37
 
@@ -73,6 +76,8 @@ class N2PModelContent:
73
76
  self.__material_coord_sys = None
74
77
  self.__cells_list = None # Lista con N2PElement y N2PConnector
75
78
  self.__connectivity_dict = {}
79
+ self.__element_user_coord_systems = []
80
+ self.__node_user_coord_systems = []
76
81
 
77
82
  if (solver is None) and (solver != "InputFileNastran") and (solver != "Binary"):
78
83
  t1 = time.time()
@@ -1156,6 +1161,15 @@ class N2PModelContent:
1156
1161
  # Método de N2LoadCase que pone todoo en su sitio
1157
1162
  cs_lc.RecalculateLCInfo2Formule()
1158
1163
 
1164
+ # Este metodo de N2ArithmeticSolver en NaxToModel comprueba que la formula introducida es correcta.
1165
+ # Devuelve False si está mal y True si está bien.
1166
+ err = N2ArithmeticSolver.CheckExpression(cs_lc.Formula, self.__vzmodel, N2ArithmeticSolver.ExpressionType.LOAD_CASE)
1167
+ if int(err) == 0:
1168
+ pass
1169
+ else:
1170
+ N2PLog.Error.E228(formula, str(N2ErrorWarnningHandling.GetDescription(err).upper())) # error
1171
+ return "ERROR"
1172
+
1159
1173
  # Se transforma el caso de carga de NaxToModel en un N2PLoadCase de python
1160
1174
  py_lc = N2PLoadCase(cs_lc.ID, cs_lc.IDOriginal, cs_lc.Increments, cs_lc.IncrementsNumberList, cs_lc.IsComplex,
1161
1175
  cs_lc.TypeLoadCase, cs_lc.Name, cs_lc.Results, cs_lc.SolutionType, cs_lc.Solver, self, cs_lc)
@@ -1242,6 +1256,15 @@ class N2PModelContent:
1242
1256
  # Método de N2LoadCase que pone todoo en su sitio
1243
1257
  cs_lc.RecalculateLCInfo2Formule()
1244
1258
 
1259
+ # Este metodo de N2ArithmeticSolver en NaxToModel comprueba que la formula introducida es correcta.
1260
+ # Devuelve False si está mal y True si está bien.
1261
+ err = N2ArithmeticSolver.CheckExpression(cs_lc.Formula, self.__vzmodel, N2ArithmeticSolver.ExpressionType.LOAD_CASE)
1262
+ if int(err) == 0:
1263
+ pass
1264
+ else:
1265
+ N2PLog.Error.E229(formula, str(N2ErrorWarnningHandling.GetDescription(err).upper())) # error
1266
+ return "ERROR"
1267
+
1245
1268
  # Se transforma el caso de carga de NaxToModel en un N2PLoadCase de python
1246
1269
  py_lc = N2PLoadCase(cs_lc.ID, cs_lc.IDOriginal, cs_lc.Increments, cs_lc.IncrementsNumberList, cs_lc.IsComplex,
1247
1270
  cs_lc.TypeLoadCase, cs_lc.Name, cs_lc.Results, cs_lc.SolutionType, cs_lc.Solver, self, cs_lc)
@@ -1331,6 +1354,7 @@ class N2PModelContent:
1331
1354
  0 : Global,
1332
1355
  -1 : Material Coordinate System,
1333
1356
  -10 : User defined,
1357
+ -20 : Element/Node User Defined,
1334
1358
  >0 : Solver ID of the Predefined Coordinate System.
1335
1359
 
1336
1360
  v1: tuple -> Optional.
@@ -1349,10 +1373,10 @@ class N2PModelContent:
1349
1373
  # Here it is checkd if the components, the loadcases and the result exist and the formula is right
1350
1374
  try:
1351
1375
  lcs = [int(lc.split(":")[0][3:]) for lc in lc_incr.split(",")]
1352
- components = [c.split(":")[0][1:] for c in componentssections.split(",")]
1376
+ components = [c.split(":")[0][1:] for c in componentssections.split(">,")]
1353
1377
  for lc in lcs:
1354
- all_comps = chain(self.get_load_case(lc).get_result(result).Components.keys(),
1355
- self.get_load_case(lc).get_result(result).DerivedComponents.keys())
1378
+ all_comps = list(self.get_load_case(lc).get_result(result).Components.keys()) + \
1379
+ list(self.get_load_case(lc).get_result(result).DerivedComponents.keys())
1356
1380
  if not all(c in all_comps for c in components):
1357
1381
  N2PLog.Error.E312(lc, result)
1358
1382
  return "ERROR"
@@ -1422,6 +1446,7 @@ class N2PModelContent:
1422
1446
  0 : Global,
1423
1447
  -1 : Material Coordinate System,
1424
1448
  -10 : User defined,
1449
+ -20 : Element/Node User Defined,
1425
1450
  >0 : Solver ID of the Predefined Coordinate System.
1426
1451
 
1427
1452
  v1: tuple
@@ -1461,6 +1486,99 @@ class N2PModelContent:
1461
1486
 
1462
1487
  # ------------------------------------------------------------------------------------------------------------------
1463
1488
 
1489
+ ####################################################################################################################
1490
+ ##################################### User Coordinate Systems #############################################
1491
+ ####################################################################################################################
1492
+ def load_user_coord_sys_from_csv(self, path: str, where: Literal["NODES", "ELEMENTS"]) -> None:
1493
+ """Method that loads a coordinate system for each node/element as a user coordinate system from a CSV file.
1494
+
1495
+ The user can define a different system for each element or node and ask for results in that system using the
1496
+ optional argument "coordsys=-20"
1497
+
1498
+ The structure of the csv must have the node/element identification, and the coordinates of the vectors v1 and v2
1499
+ that generates the system: x = v1; z = v1^v2; y = z^v1. The structure for elements and nodes must be:
1500
+
1501
+ node_id_1,part_id_1,x11,y11,z11,x12,y12,z12
1502
+
1503
+ user_system_elements_example.csv:
1504
+ 1001,0,1,0,0,0,1,0\n
1505
+ 1002,0,0.3,0.2,0,0,1,0\n
1506
+ 1003,0,0,1,0,1,1,0\n
1507
+ 1004,0,2,0,1,0.4,1,3\n
1508
+
1509
+ Warnings:
1510
+ If a CSV is loaded and the another is loaded, the previous information will be deleted.
1511
+
1512
+ Args:
1513
+ path: path for a CSV.
1514
+ where: "NODES"|"ELEMENTS". The user coordinate systems are for the nodes or the elements.
1515
+
1516
+ Examples:
1517
+ >>> N2PModelContent.load_user_coord_sys_from_csv(path="user_system_elements_example.csv", where="ELEMENTS")
1518
+ >>> N2PModelContent.load_user_coord_sys_from_csv("node_sys.csv", "NODES")
1519
+ """
1520
+ if where.upper() == "ELEMENTS":
1521
+ self.__vzmodel.ReadCSVUserElementCoordinateSystems(path)
1522
+ elif where.upper() == "NODES":
1523
+ self.__vzmodel.ReadCSVUserNodeCoordinateSystems(path)
1524
+ else:
1525
+ N2PLog.Error.E231()
1526
+ raise ValueError("INVALID ARGUMENT. where should be 'ELEMENTS' or 'NODES'")
1527
+ # ------------------------------------------------------------------------------------------------------------------
1528
+
1529
+ # Sets User Coordinate Systems -------------------------------------------------------------------------------------
1530
+ def set_user_coord_sys(self, array2d: Union[list, np.ndarray], where: Literal["NODES", "ELEMENTS"]) -> None:
1531
+ """Method that sets a coordinate system for each node/element as a user coordinate system using an array defined
1532
+ by the user.
1533
+
1534
+ The user can define a different system for each element or node and ask for results in that system using the
1535
+ optional argument "coordsys=-20"
1536
+
1537
+ The structure of the array must have the node/element identification, and the coordinates of the vectors v1 and v2
1538
+ that generates the system: x = v1; z = v1^v2; y = z^v1. The structure for elements and nodes must be:
1539
+
1540
+ [ [node_id_1,part_id_1,x11,y11,z11,x12,y12,z12], [node_id_2,part_id_2,x21,y21,z21,x22,y22,z22], ... ]
1541
+
1542
+ user_system_elements_example.csv:
1543
+ [ [1001,0,1,0,0,0,1,0], [1002,0,0.3,0.2,0,0,1,0], [1003,0,0,1,0,1,1,0], [1004,0,2,0,1,0.4,1,3] ]
1544
+
1545
+ Warnings:
1546
+ If an array is passed to this method and the another is passed, the previous information will be deleted.
1547
+
1548
+ Args:
1549
+ array2d: list|np.ndarray. The array can be a list of list or a two dymensional array of numpy with the type float
1550
+ where: "NODES"|"ELEMENTS". The user coordinate systems are for the nodes or the elements.
1551
+
1552
+ Examples:
1553
+ >>> array_ele = [ [1001,0,1,0,0,0,1,0], [1002,0,0.3,0.2,0,0,1,0], [1003,0,0,1,0,1,1,0],
1554
+ >>> ... [1004,0,2,0,1,0.4,1,3] ]
1555
+ >>> array_node = np.array([ [2001,0,1,0,0,0,1,0], [2002,0,0.3,0.2,0,0,1,0], [2003,0,0,1,0,1,1,0],
1556
+ >>> ... [2004,0,2,0,1,0.4,1,3] ], dtype=float)
1557
+ >>>
1558
+ >>> N2PModelContent.set_user_coord_sys(array2d=array_ele, where="ELEMENTS")
1559
+ >>> N2PModelContent.set_user_coord_sys(array_node, "NODES")
1560
+ """
1561
+
1562
+ if isinstance(array2d, list):
1563
+ array2d = np.array(array2d)
1564
+
1565
+ rows = array2d.shape[0]
1566
+ cols = array2d.shape[1]
1567
+ cs_array = System.Array.CreateInstance(System.Object, rows, cols)
1568
+
1569
+ for i in range(rows):
1570
+ for j in range(cols):
1571
+ cs_array[i, j] = array2d[i, j]
1572
+
1573
+ if where.upper() == "ELEMENTS":
1574
+ self.__vzmodel.SetElementUserCoordinateSystems(cs_array)
1575
+ elif where.upper() == "NODES":
1576
+ self.__vzmodel.SetNodeUserCoordinateSystems(cs_array)
1577
+ else:
1578
+ N2PLog.Error.E231()
1579
+ raise ValueError("INVALID ARGUMENT. where should be 'ELEMENTS' or 'NODES'")
1580
+ # ------------------------------------------------------------------------------------------------------------------
1581
+
1464
1582
  ####################################################################################################################
1465
1583
  ####################################### ElementsCoordSys ##################################################
1466
1584
  ####################################################################################################################
@@ -114,7 +114,7 @@ def __list_ext_libs(libs_path, solver, abq_ver) -> list[str]:
114
114
 
115
115
  # Funcion principal que usa PyInstaller para generar el .exe -----------------------------------------------------------
116
116
  def n2ptoexe(path: str, console: bool = True, solver: str = "ALL", abaqusversion: list[str] = None,
117
- splash: str="") -> None:
117
+ splash: str = "", extra_packages: list[str] = None, extra_files: list[str] = None) -> None:
118
118
  """Function that creates .exe files of programs that use NaxToPy
119
119
 
120
120
  Args:
@@ -133,6 +133,17 @@ def n2ptoexe(path: str, console: bool = True, solver: str = "ALL", abaqusversion
133
133
  splash: str -> Optional. Path to the splash image. If used, the user must introduce pyi_splash.close() at the
134
134
  beginning of the execution of the module. Import pyi_splash first. The splash image will appear during the
135
135
  .exe unpacking. Image should be png and smaller than 500x500 pixels.
136
+ extra_packages: list[str] -> If some packages are not imported correctly by the function, they can be added
137
+ manually. An example of a package that usually fails is 'sv_ttk'.
138
+ extra_files: list[str] -> Lis of path of extra dll, images or other files the user want to add the exe. The
139
+ files will be saved in the ./bin directory inside the exe. To acces to the files
140
+ use: path_file = os.path.join(sys._MEIPASS, r"bin\mylib.dll")
141
+
142
+ Examples:
143
+ >>> n2ptoexe(r"C:\Scripts\myscript1.py")
144
+ >>> n2ptoexe(r"C:\Scripts\myscript2.py", console=False, solver="NASTRAN")
145
+ >>> n2ptoexe(r"C:\Scripts\myscript3.py", console=True, solver="OPTISTRUCT", splash=r"C:\Scripts\mysplash.jpg")
146
+ >>> n2ptoexe(r"C:\Scripts\myscript4.py", extra_packages=["sv_ttk"], extra_files=[r"C:\Scripts\icon.png"])
136
147
  """
137
148
 
138
149
  # 0 ) Genera el archivo .log y añade los logs de la importación ------------------------------------------------
@@ -164,7 +175,7 @@ def n2ptoexe(path: str, console: bool = True, solver: str = "ALL", abaqusversion
164
175
  consl = "-w"
165
176
  else:
166
177
  N2PLog.Critical.C104()
167
- # sys.exit("C104: THE ARGUMENT CONSOLE MUST BE A BOOLEAN: True | False")
178
+ raise Exception()
168
179
 
169
180
 
170
181
  if __busca_n2p(path):
@@ -187,6 +198,19 @@ def n2ptoexe(path: str, console: bool = True, solver: str = "ALL", abaqusversion
187
198
  if splash:
188
199
  pyinstaller_cmd += ['--splash', splash]
189
200
 
201
+ if extra_files:
202
+ for file in extra_files:
203
+ if os.path.isfile(file):
204
+ pass
205
+ else:
206
+ N2PLog.Error.E113(file)
207
+ raise Exception()
208
+ pyinstaller_cmd += ["--add-data", f"{file};./bin"]
209
+
210
+ if extra_packages:
211
+ for package in extra_packages:
212
+ pyinstaller_cmd += ["--collect-data", package]
213
+
190
214
  PyIns.run(pyinstaller_cmd)
191
215
  N2PLog.Info.I201(os.getcwd())
192
216
  else:
@@ -84,6 +84,7 @@ def dataframe_result(model: "N2PModelContent", component: "N2PComponent",section
84
84
  0 : Global,
85
85
  -1 : Material Coordinate System,
86
86
  -10 : User defined,
87
+ -20 : Element/Node User Defined,
87
88
  >0 : Solver ID of the Predefined Coordinate System.
88
89
 
89
90
  v1: tuple -> Optional.
@@ -151,6 +152,7 @@ def dataframe_results(model: "N2PModelContent", result: "N2PResult", sections=No
151
152
  0 : Global,
152
153
  -1 : Material Coordinate System,
153
154
  -10 : User defined,
155
+ -20 : Element/Node User Defined,
154
156
  >0 : Solver ID of the Predefined Coordinate System.
155
157
 
156
158
  v1: tuple -> Optional.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: NaxToPy
3
- Version: 2.0.1
3
+ Version: 2.1.1
4
4
  Summary: Package for postprocessing FEM results in Python
5
5
  Home-page: https://www.idaerosolutions.com/Home/NaxToPy
6
6
  Download-URL: https://apps.microsoft.com/detail/XP9MMH0KDKGRJN?hl=en-US&gl=US
@@ -147,7 +147,7 @@ links on the left).
147
147
  **NaxToPy** is a powerful tool for FEM analysis post-processing!
148
148
 
149
149
  **CAUTION:** To use NaxToPy, [**NaxTo**](https://apps.microsoft.com/detail/XP9MMH0KDKGRJN?hl=en-US&gl=US) must be installed.
150
- This version is compatible with **NaxTo 2024.1**. It is compatible with all the steps of this version (2024.1.0, 2024.1.1, 2024.1.2, etc.).
150
+ This version is compatible with **NaxTo 2024.2**. It is compatible with all the steps of this version (2024.2.0, 2024.2.1, 2024.2.2, etc.).
151
151
  Check in _Programs and Features_ the NaxTo version that is installed.
152
152
 
153
153
  ## Installation
@@ -269,6 +269,20 @@ the LoadCases that are critical or the Increment that is critical instead of the
269
269
  It uses an object instaed of an int.
270
270
  3. Update of the examples of some docstrings.
271
271
 
272
+ ### v.2.1.0
273
+ 1. Reading a Natran Input File: SPC and SCP1 are now supported.
274
+ 2. Bug fix. The order in the components in new_report() does not affect now.
275
+ 3. Formula check in new_derived_loadcase(), new_enevelope_loadcase() and new_derived_component().
276
+ 4. New optional arguments if n2ptoexe() to add extra libaries, packages or files.
277
+
278
+ ### v.2.1.1
279
+ 1. Two new methods in N2PModelContent: load_user_coord_sys_from_csv() and set_user_coord_sys().
280
+ Also there is a new property for N2PElement and N2PNode: UserSystemArray. This update allow the
281
+ user to define a different coordinate system for each element or node. To ask for the results
282
+ in this system, the optional argument `coordsys` must be equal to `-20`.
283
+ 2. Bug fix: The checking for component and section in new_report() has been fixed. If a comma
284
+ appeared in the component or section name, the method failed.
285
+
272
286
  # Documentation
273
287
 
274
288
  **NaxToPy** is a package developed by Idaero Solutions© as a part of the **NaxTo** software.
@@ -1,2 +0,0 @@
1
- from .Fasteners.N2PUpdateFastener import Union
2
-
File without changes
File without changes
File without changes
File without changes
File without changes