midas-civil 0.1.4__py3-none-any.whl → 0.1.6__py3-none-any.whl

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.

Potentially problematic release.


This version of midas-civil might be problematic. Click here for more details.

midas_civil/__init__.py CHANGED
@@ -20,6 +20,11 @@ from ._temperature import *
20
20
  from ._tendon import *
21
21
  from ._view import *
22
22
 
23
+ from ._movingload import*
24
+ from ._settlement import*
25
+
26
+
27
+
23
28
  print('')
24
29
  print('*'*20,' MIDAS CIVIL-NX PYTHON LIBRARY 🐍 ','*'*20)
25
30
  print('')
midas_civil/_boundary.py CHANGED
@@ -10,6 +10,16 @@ def convList(item):
10
10
  return item
11
11
 
12
12
 
13
+ # ----- Extend for list of nodes/elems -----
14
+
15
+ def _ADD_Support(self):
16
+ if isinstance(self.NODE,int):
17
+ Boundary.Support.sups.append(self)
18
+ elif isinstance(self.NODE,list):
19
+ for nID in self.NODE:
20
+ Boundary.Support(nID,self.CONST,self.GROUP)
21
+
22
+
13
23
  class Boundary:
14
24
 
15
25
  @classmethod
@@ -67,7 +77,7 @@ class Boundary:
67
77
  self.CONST = string
68
78
  self.GROUP = group
69
79
  self.ID = len(Boundary.Support.sups) + 1
70
- Boundary.Support.sups.append(self)
80
+ _ADD_Support(self)
71
81
 
72
82
  @classmethod
73
83
  def json(cls):
midas_civil/_element.py CHANGED
@@ -1,9 +1,15 @@
1
1
  from ._mapi import *
2
2
  from ._node import *
3
3
  from ._group import _add_elem_2_stGroup
4
+ from ._group import _add_node_2_stGroup
4
5
 
5
6
  import numpy as np
6
7
 
8
+
9
+
10
+
11
+
12
+
7
13
  def _ADD(self):
8
14
  """
9
15
  Adds an element to the main list. If the ID is 0, it auto-increments.
@@ -32,13 +38,17 @@ def _ADD(self):
32
38
  Element.ids.append(int(self.ID))
33
39
 
34
40
  # ------------ Group assignment -----------------------
35
- if self._GROUP == '' :
41
+ if self._GROUP == "" :
36
42
  pass
37
43
  elif isinstance(self._GROUP, list):
38
44
  for gpName in self._GROUP:
39
45
  _add_elem_2_stGroup(self.ID,gpName)
46
+ for nd in self.NODE:
47
+ _add_node_2_stGroup(nd,gpName)
40
48
  elif isinstance(self._GROUP, str):
41
49
  _add_elem_2_stGroup(self.ID,self._GROUP)
50
+ for nd in self.NODE:
51
+ _add_node_2_stGroup(nd,self._GROUP)
42
52
 
43
53
 
44
54
 
@@ -117,17 +127,17 @@ def _JS2Obj(id, js):
117
127
  t_limit = js.get('T_LIMIT')
118
128
 
119
129
  if elem_type == 'BEAM':
120
- Element.Beam(args['node'][0], args['node'][1], args['mat'], args['sect'], args['angle'], args['id'])
130
+ Element.Beam(args['node'][0], args['node'][1], args['mat'], args['sect'], args['angle'], '', args['id'])
121
131
  elif elem_type == 'TRUSS':
122
- Element.Truss(args['node'][0], args['node'][1], args['mat'], args['sect'], args['angle'], args['id'])
132
+ Element.Truss(args['node'][0], args['node'][1], args['mat'], args['sect'], args['angle'],'', args['id'])
123
133
  elif elem_type == 'PLATE':
124
- Element.Plate(args['node'], args['stype'], args['mat'], args['sect'], args['angle'], args['id'])
134
+ Element.Plate(args['node'], args['stype'], args['mat'], args['sect'], args['angle'], '', args['id'])
125
135
  elif elem_type == 'TENSTR':
126
- Element.Tension(args['node'][0], args['node'][1], args['stype'], args['mat'], args['sect'], args['angle'], args['id'], non_len, cable_type, tens, t_limit)
136
+ Element.Tension(args['node'][0], args['node'][1], args['stype'], args['mat'], args['sect'], args['angle'], '', args['id'], non_len, cable_type, tens, t_limit)
127
137
  elif elem_type == 'COMPTR':
128
- Element.Compression(args['node'][0], args['node'][1], args['stype'], args['mat'], args['sect'], args['angle'], args['id'], tens, t_limit, non_len)
138
+ Element.Compression(args['node'][0], args['node'][1], args['stype'], args['mat'], args['sect'], args['angle'], '', args['id'], tens, t_limit, non_len)
129
139
  elif elem_type == 'SOLID':
130
- Element.Solid(nodes=args['node'], mat=args['mat'], sect=args['sect'], id=args['id'])
140
+ Element.Solid(nodes=args['node'], mat=args['mat'], sect=args['sect'],group='', id=args['id'])
131
141
 
132
142
 
133
143
  class _common:
@@ -516,10 +526,179 @@ class Element:
516
526
  _ADD(self)
517
527
 
518
528
 
529
+ #-----------------------------------------------Stiffness Scale Factor------------------------------
519
530
 
531
+ class StiffnessScaleFactor:
532
+
533
+ data = []
534
+
535
+ def __init__(self,
536
+ element_id,
537
+ area_sf: float = 1.0,
538
+ asy_sf: float = 1.0,
539
+ asz_sf: float = 1.0,
540
+ ixx_sf: float = 1.0,
541
+ iyy_sf: float = 1.0,
542
+ izz_sf: float = 1.0,
543
+ wgt_sf: float = 1.0,
544
+ group: str = "",
545
+ id: int = None):
546
+ """
547
+ element_id: Element ID(s) where scale factor is applied (can be int or list)
548
+ area_sf: Cross-sectional area scale factor
549
+ asy_sf: Effective Shear Area scale factor (y-axis)
550
+ asz_sf: Effective Shear Area scale factor (z-axis)
551
+ ixx_sf: Torsional Resistance scale factor (x-axis)
552
+ iyy_sf: Area Moment of Inertia scale factor (y-axis)
553
+ izz_sf: Area Moment of Inertia scale factor (z-axis)
554
+ wgt_sf: Weight scale factor
555
+ group: Group name (default "")
556
+ id: Scale factor ID (optional, auto-assigned if None)
557
+
558
+ Examples:
559
+ StiffnessScaleFactor(908, area_sf=0.5, asy_sf=0.6, asz_sf=0.7,
560
+ ixx_sf=0.8, iyy_sf=0.8, izz_sf=0.9, wgt_sf=0.95)
561
+
562
+ """
563
+
564
+ # Check if group exists, create if not
565
+ if group != "":
566
+ chk = 0
567
+ a = [v['NAME'] for v in Group.Boundary.json()["Assign"].values()]
568
+ if group in a:
569
+ chk = 1
570
+ if chk == 0:
571
+ Group.Boundary(group)
572
+
573
+ # Handle element_id as single int or list
574
+ if isinstance(element_id, (list, tuple)):
575
+ self.ELEMENT_IDS = list(element_id)
576
+ else:
577
+ self.ELEMENT_IDS = [element_id]
578
+
579
+ self.AREA_SF = area_sf
580
+ self.ASY_SF = asy_sf
581
+ self.ASZ_SF = asz_sf
582
+ self.IXX_SF = ixx_sf
583
+ self.IYY_SF = iyy_sf
584
+ self.IZZ_SF = izz_sf
585
+ self.WGT_SF = wgt_sf
586
+ self.GROUP_NAME = group
587
+
588
+ # Auto-assign ID if not provided
589
+ if id is None:
590
+ self.ID = len(Element.StiffnessScaleFactor.data) + 1
591
+ else:
592
+ self.ID = id
593
+
594
+ # Add to static list
595
+ Element.StiffnessScaleFactor.data.append(self)
596
+
597
+ @classmethod
598
+ def json(cls):
599
+ """
600
+ Converts StiffnessScaleFactor data to JSON format
601
+ """
602
+ json_data = {"Assign": {}}
603
+
604
+ for scale_factor in cls.data:
605
+ # Create scale factor item
606
+ scale_factor_item = {
607
+ "ID": scale_factor.ID,
608
+ "AREA_SF": scale_factor.AREA_SF,
609
+ "ASY_SF": scale_factor.ASY_SF,
610
+ "ASZ_SF": scale_factor.ASZ_SF,
611
+ "IXX_SF": scale_factor.IXX_SF,
612
+ "IYY_SF": scale_factor.IYY_SF,
613
+ "IZZ_SF": scale_factor.IZZ_SF,
614
+ "WGT_SF": scale_factor.WGT_SF,
615
+ "GROUP_NAME": scale_factor.GROUP_NAME
616
+ }
617
+
618
+ # Assign to each element ID
619
+ for element_id in scale_factor.ELEMENT_IDS:
620
+ if str(element_id) not in json_data["Assign"]:
621
+ json_data["Assign"][str(element_id)] = {"ITEMS": []}
622
+
623
+ json_data["Assign"][str(element_id)]["ITEMS"].append(scale_factor_item)
624
+
625
+ return json_data
626
+
627
+ @classmethod
628
+ def create(cls):
629
+ """
630
+ Sends all StiffnessScaleFactor data to the API
631
+ """
632
+ MidasAPI("PUT", "/db/essf", cls.json())
633
+
634
+ @classmethod
635
+ def get(cls):
636
+ """
637
+ Retrieves StiffnessScaleFactor data from the API
638
+ """
639
+ return MidasAPI("GET", "/db/essf")
640
+
641
+ @classmethod
642
+ def sync(cls):
643
+ """
644
+ Updates the StiffnessScaleFactor class with data from the API
645
+ """
646
+ cls.data = []
647
+ response = cls.get()
648
+
649
+ if response != {'message': ''}:
650
+ processed_ids = set() # To avoid duplicate processing
651
+
652
+ for element_data in response.get("ESSF", {}).items():
653
+ for item in element_data.get("ITEMS", []):
654
+ scale_factor_id = item.get("ID", 1)
655
+
656
+ # Skip if already processed (for multi-element scale factors)
657
+ if scale_factor_id in processed_ids:
658
+ continue
659
+
660
+ # Find all elements with the same scale factor ID
661
+ element_ids = []
662
+ for eid, edata in response.get("ESSF", {}).items():
663
+ for eitem in edata.get("ITEMS", []):
664
+ if eitem.get("ID") == scale_factor_id:
665
+ element_ids.append(int(eid))
666
+
667
+ # Create StiffnessScaleFactor object
668
+ Element.StiffnessScaleFactor(
669
+ element_id=element_ids if len(element_ids) > 1 else element_ids[0],
670
+ area_sf=item.get("AREA_SF", 1.0),
671
+ asy_sf=item.get("ASY_SF", 1.0),
672
+ asz_sf=item.get("ASZ_SF", 1.0),
673
+ ixx_sf=item.get("IXX_SF", 1.0),
674
+ iyy_sf=item.get("IYY_SF", 1.0),
675
+ izz_sf=item.get("IZZ_SF", 1.0),
676
+ wgt_sf=item.get("WGT_SF", 1.0),
677
+ group=item.get("GROUP_NAME", ""),
678
+ id=scale_factor_id
679
+ )
680
+
681
+ processed_ids.add(scale_factor_id)
682
+
683
+ @classmethod
684
+ def delete(cls):
685
+ """
686
+ Deletes all stiffness scale factors from the database and resets the class.
687
+ """
688
+ cls.data = []
689
+ return MidasAPI("DELETE", "/db/essf")
520
690
 
521
691
 
522
692
 
523
693
 
694
+ # ---- GET ELEMENT OBJECT FROM ID ----------
524
695
 
696
+ def elemByID(elemID:int) -> Element:
697
+ ''' Return Element object with the input ID '''
698
+ for elem in Element.elements:
699
+ if elem.ID == elemID:
700
+ return elem
701
+
702
+ print(f'There is no element with ID {elemID}')
703
+ return None
525
704
 
midas_civil/_group.py CHANGED
@@ -3,8 +3,30 @@ from ._mapi import *
3
3
 
4
4
 
5
5
 
6
+
7
+
6
8
  # ----------- HELPER FUNCTION -----------
7
- # -------- ADD ELEMENT TO STRUCTURE GROUP -------
9
+ # -------- RETRIEVE NODE / ELEMENT FROM STRUCTURE GROUP -------
10
+
11
+ def nodesInGroup(groupName:str) -> list | int:
12
+ ''' Returns Node ID list in a Structure Group '''
13
+ for i in Group.Structure.Groups:
14
+ if i.NAME == groupName:
15
+ return i.NLIST
16
+ print('⚠️ Structure group not found !')
17
+ return []
18
+
19
+
20
+ def elemsInGroup(groupName:str) -> list:
21
+ ''' Returns Element ID list in a Structure Group '''
22
+ for i in Group.Structure.Groups:
23
+ if i.NAME == groupName:
24
+ return i.ELIST
25
+ print('⚠️ Structure group not found !')
26
+ return []
27
+
28
+
29
+ # -------- ADD ELEMENT TO STRUCTURE GROUP -------
8
30
 
9
31
  def _add_elem_2_stGroup(elemID,groupName):
10
32
  up = 0
@@ -19,7 +41,6 @@ def _add_elem_2_stGroup(elemID,groupName):
19
41
 
20
42
 
21
43
  def _add_node_2_stGroup(nodeID,groupName):
22
- up = 0
23
44
  if groupName in Group.Structure._names:
24
45
  for i in Group.Structure.Groups:
25
46
  if i.NAME == groupName:
midas_civil/_load.py CHANGED
@@ -2,6 +2,28 @@ from ._mapi import *
2
2
  from ._model import *
3
3
  from ._group import *
4
4
 
5
+
6
+
7
+ # ----- Extend for list of nodes/elems -----
8
+
9
+ def _ADD_NodalLoad(self):
10
+ if isinstance(self.NODE,int):
11
+ Load.Nodal.data.append(self)
12
+ elif isinstance(self.NODE,list):
13
+ for nID in self.NODE:
14
+ Load.Nodal(nID,self.LCN,self.LDGR,self.FX,self.FY,self.FZ,self.MX,self.MY,self.MZ,self.ID)
15
+
16
+
17
+ def _ADD_BeamLoad(self):
18
+ if isinstance(self.ELEMENT,int):
19
+ Load.Beam.data.append(self)
20
+ elif isinstance(self.ELEMENT,list):
21
+ for eID in self.ELEMENT:
22
+ Load.Beam(eID,self.LCN,self.LDGR,self.VALUE,self.DIRECTION,self.ID,self.D,self.P,self.CMD,self.TYPE,self.USE_ECCEN,self.USE_PROJECTION,
23
+ self.ECCEN_DIR,self.ECCEN_TYPE,self.IECC,self.JECC,self.USE_H,self.I_H,self.J_H)
24
+
25
+
26
+
5
27
  #11 Class to define Load Cases:
6
28
  class Load_Case:
7
29
  """Type symbol (Refer Static Load Case section in the Onine API Manual, Load Case names.
@@ -177,7 +199,9 @@ class Load:
177
199
  self.MZ = MZ
178
200
  if id == "": id = len(Load.Nodal.data) + 1
179
201
  self.ID = id
180
- Load.Nodal.data.append(self)
202
+
203
+ _ADD_NodalLoad(self)
204
+ # Load.Nodal.data.append(self)
181
205
 
182
206
  @classmethod
183
207
  def json(cls):
@@ -228,9 +252,9 @@ class Load:
228
252
  #19 Class to define Beam Loads:
229
253
  class Beam:
230
254
  data = []
231
- def __init__(self, element: int, load_case: str, value: float, load_group: str = "", direction: str = "GZ",
255
+ def __init__(self, element, load_case: str, load_group: str = "", value: float=0, direction: str = "GZ",
232
256
  id = "", D = [0, 1, 0, 0], P = [0, 0, 0, 0], cmd = "BEAM", typ = "UNILOAD", use_ecc = False, use_proj = False,
233
- eccn_dir = "LZ", eccn_type = 1, ieccn = 0, jeccn = 0.0000195, adnl_h = False, adnl_h_i = 0, adnl_h_j = 0.0000195):
257
+ eccn_dir = "LZ", eccn_type = 1, ieccn = 0, jeccn = 0, adnl_h = False, adnl_h_i = 0, adnl_h_j = 0):
234
258
  """
235
259
  element: Element Number
236
260
  load_case (str): Load case name
@@ -276,7 +300,7 @@ class Load:
276
300
  if cmd not in ("BEAM", "LINE", "TYPICAL"): cmd = "BEAM"
277
301
  if typ not in ("CONLOAD", "CONMOMENT", "UNILOAD", "UNIMOMENT","PRESSURE"): typ = "UNILOAD"
278
302
  if use_ecc == False:
279
- if ieccn != 0 or jeccn != 0.0000195: use_ecc = True
303
+ if ieccn != 0 or jeccn != 0: use_ecc = True
280
304
  self.ELEMENT = element
281
305
  self.LCN = load_case
282
306
  self.LDGR = load_group
@@ -289,7 +313,7 @@ class Load:
289
313
  self.ECCEN_TYPE = eccn_type
290
314
  self.ECCEN_DIR = eccn_dir
291
315
  self.IECC = ieccn
292
- if jeccn == 0.0000195:
316
+ if jeccn == 0:
293
317
  self.JECC = 0
294
318
  self.USE_JECC = False
295
319
  else:
@@ -299,7 +323,7 @@ class Load:
299
323
  self.P = P
300
324
  self.USE_H = adnl_h
301
325
  self.I_H = adnl_h_i
302
- if adnl_h == 0.0000195:
326
+ if adnl_h == 0:
303
327
  self.USE_JH = False
304
328
  self.J_H = 0
305
329
  else:
@@ -309,7 +333,8 @@ class Load:
309
333
  if id == "":
310
334
  id = len(Load.Beam.data) + 1
311
335
  self.ID = id
312
- Load.Beam.data.append(self)
336
+ _ADD_BeamLoad(self)
337
+ # Load.Beam.data.append(self)
313
338
 
314
339
  @classmethod
315
340
  def json(cls):
@@ -368,23 +393,23 @@ class Load:
368
393
  for i in a['BMLD'].keys():
369
394
  for j in range(len(a['BMLD'][i]['ITEMS'])):
370
395
  if a['BMLD'][i]['ITEMS'][j]['USE_ECCEN'] == True and a['BMLD'][i]['ITEMS'][j]['USE_ADDITIONAL'] == True:
371
- Load.Beam(i,a['BMLD'][i]['ITEMS'][j]['LCNAME'], a['BMLD'][i]['ITEMS'][j]['P'][0], a['BMLD'][i]['ITEMS'][j]['GROUP_NAME'],
396
+ Load.Beam(i,a['BMLD'][i]['ITEMS'][j]['LCNAME'], a['BMLD'][i]['ITEMS'][j]['GROUP_NAME'], a['BMLD'][i]['ITEMS'][j]['P'][0],
372
397
  a['BMLD'][i]['ITEMS'][j]['DIRECTION'], a['BMLD'][i]['ITEMS'][j]['ID'], a['BMLD'][i]['ITEMS'][j]['D'], a['BMLD'][i]['ITEMS'][j]['P'],
373
398
  a['BMLD'][i]['ITEMS'][j]['CMD'], a['BMLD'][i]['ITEMS'][j]['TYPE'], a['BMLD'][i]['ITEMS'][j]['USE_ECCEN'], a['BMLD'][i]['ITEMS'][j]['USE_PROJECTION'],
374
399
  a['BMLD'][i]['ITEMS'][j]['ECCEN_DIR'], a['BMLD'][i]['ITEMS'][j]['ECCEN_TYPE'], a['BMLD'][i]['ITEMS'][j]['I_END'], a['BMLD'][i]['ITEMS'][j]['J_END'],
375
400
  a['BMLD'][i]['ITEMS'][j]['USE_ADDITIONAL'], a['BMLD'][i]['ITEMS'][j]['ADDITIONAL_I_END'], a['BMLD'][i]['ITEMS'][j]['ADDITIONAL_J_END'])
376
401
  elif a['BMLD'][i]['ITEMS'][j]['USE_ECCEN'] == False and a['BMLD'][i]['ITEMS'][j]['USE_ADDITIONAL'] == True:
377
- Load.Beam(i,a['BMLD'][i]['ITEMS'][j]['LCNAME'], a['BMLD'][i]['ITEMS'][j]['P'][0], a['BMLD'][i]['ITEMS'][j]['GROUP_NAME'],
402
+ Load.Beam(i,a['BMLD'][i]['ITEMS'][j]['LCNAME'], a['BMLD'][i]['ITEMS'][j]['GROUP_NAME'], a['BMLD'][i]['ITEMS'][j]['P'][0],
378
403
  a['BMLD'][i]['ITEMS'][j]['DIRECTION'], a['BMLD'][i]['ITEMS'][j]['ID'], a['BMLD'][i]['ITEMS'][j]['D'], a['BMLD'][i]['ITEMS'][j]['P'],
379
404
  a['BMLD'][i]['ITEMS'][j]['CMD'], a['BMLD'][i]['ITEMS'][j]['TYPE'], a['BMLD'][i]['ITEMS'][j]['USE_ECCEN'], a['BMLD'][i]['ITEMS'][j]['USE_PROJECTION'],
380
405
  adnl_h = a['BMLD'][i]['ITEMS'][j]['USE_ADDITIONAL'], adnl_h_i = a['BMLD'][i]['ITEMS'][j]['ADDITIONAL_I_END'], adnl_h_j = a['BMLD'][i]['ITEMS'][j]['ADDITIONAL_J_END'])
381
406
  elif a['BMLD'][i]['ITEMS'][j]['USE_ECCEN'] == True and a['BMLD'][i]['ITEMS'][j]['USE_ADDITIONAL'] == False:
382
- Load.Beam(i,a['BMLD'][i]['ITEMS'][j]['LCNAME'], a['BMLD'][i]['ITEMS'][j]['P'][0], a['BMLD'][i]['ITEMS'][j]['GROUP_NAME'],
407
+ Load.Beam(i,a['BMLD'][i]['ITEMS'][j]['LCNAME'], a['BMLD'][i]['ITEMS'][j]['GROUP_NAME'], a['BMLD'][i]['ITEMS'][j]['P'][0],
383
408
  a['BMLD'][i]['ITEMS'][j]['DIRECTION'], a['BMLD'][i]['ITEMS'][j]['ID'], a['BMLD'][i]['ITEMS'][j]['D'], a['BMLD'][i]['ITEMS'][j]['P'],
384
409
  a['BMLD'][i]['ITEMS'][j]['CMD'], a['BMLD'][i]['ITEMS'][j]['TYPE'], a['BMLD'][i]['ITEMS'][j]['USE_ECCEN'], a['BMLD'][i]['ITEMS'][j]['USE_PROJECTION'],
385
410
  a['BMLD'][i]['ITEMS'][j]['ECCEN_DIR'], a['BMLD'][i]['ITEMS'][j]['ECCEN_TYPE'], a['BMLD'][i]['ITEMS'][j]['I_END'], a['BMLD'][i]['ITEMS'][j]['J_END'])
386
411
  else:
387
- Load.Beam(i,a['BMLD'][i]['ITEMS'][j]['LCNAME'], a['BMLD'][i]['ITEMS'][j]['P'][0], a['BMLD'][i]['ITEMS'][j]['GROUP_NAME'],
412
+ Load.Beam(i,a['BMLD'][i]['ITEMS'][j]['LCNAME'], a['BMLD'][i]['ITEMS'][j]['GROUP_NAME'],a['BMLD'][i]['ITEMS'][j]['P'][0],
388
413
  a['BMLD'][i]['ITEMS'][j]['DIRECTION'], a['BMLD'][i]['ITEMS'][j]['ID'], a['BMLD'][i]['ITEMS'][j]['D'], a['BMLD'][i]['ITEMS'][j]['P'],
389
414
  a['BMLD'][i]['ITEMS'][j]['CMD'], a['BMLD'][i]['ITEMS'][j]['TYPE'], a['BMLD'][i]['ITEMS'][j]['USE_ECCEN'], a['BMLD'][i]['ITEMS'][j]['USE_PROJECTION'])
390
415
 
@@ -521,12 +546,13 @@ class Load:
521
546
 
522
547
  class NodalMass:
523
548
  """Creates nodal mass and converts to JSON format.
524
- Example: NodalMass(1.5, 2.0, 3.0, 0.1, 0.2, 0.3)
549
+ Example: NodalMass(1, 1.5, 2.0, 3.0, 0.1, 0.2, 0.3)
525
550
  """
526
551
  data = []
527
-
528
- def __init__(self, mX, mY=0, mZ=0, rmX=0, rmY=0, rmZ=0):
552
+
553
+ def __init__(self, node_id, mX, mY=0, mZ=0, rmX=0, rmY=0, rmZ=0):
529
554
  """
555
+ node_id (int): Node ID where the mass is applied (Required)
530
556
  mX (float): Translational Lumped Mass in GCS X-direction (Required)
531
557
  mY (float): Translational Lumped Mass in GCS Y-direction. Defaults to 0
532
558
  mZ (float): Translational Lumped Mass in GCS Z-direction. Defaults to 0
@@ -534,6 +560,7 @@ class Load:
534
560
  rmY (float): Rotational Mass Moment of Inertia about GCS Y-axis. Defaults to 0
535
561
  rmZ (float): Rotational Mass Moment of Inertia about GCS Z-axis. Defaults to 0
536
562
  """
563
+ self.NODE_ID = node_id
537
564
  self.MX = mX
538
565
  self.MY = mY
539
566
  self.MZ = mZ
@@ -547,10 +574,8 @@ class Load:
547
574
  def json(cls):
548
575
  json_data = {"Assign": {}}
549
576
 
550
- # Use the last added mass data (or first if only one exists)
551
- if cls.data:
552
- mass_obj = cls.data[-1] # Get the most recent mass object
553
- json_data["Assign"]["1"] = {
577
+ for mass_obj in cls.data:
578
+ json_data["Assign"][mass_obj.NODE_ID] = {
554
579
  "mX": mass_obj.MX,
555
580
  "mY": mass_obj.MY,
556
581
  "mZ": mass_obj.MZ,
@@ -567,23 +592,24 @@ class Load:
567
592
 
568
593
  @classmethod
569
594
  def get(cls):
570
- return MidasAPI("GET", "/db/nmas")
595
+ MidasAPI("GET", "/db/nmas")
571
596
 
572
597
  @classmethod
573
598
  def delete(cls):
574
599
  cls.data = []
575
- return MidasAPI("DELETE", "/db/nmas")
600
+ MidasAPI("DELETE", "/db/nmas")
576
601
 
577
602
  @classmethod
578
603
  def sync(cls):
579
604
  cls.data = []
580
605
  response = cls.get()
581
606
 
582
- if response != {'message': ''}:
607
+ if response and response != {'message': ''}:
583
608
  nmas_data = response.get('NMAS', {})
584
- if "1" in nmas_data:
585
- item_data = nmas_data["1"]
609
+
610
+ for node_id, item_data in nmas_data.items():
586
611
  Load.NodalMass(
612
+ node_id=int(node_id),
587
613
  mX=item_data.get('mX'),
588
614
  mY=item_data.get('mY'),
589
615
  mZ=item_data.get('mZ'),
midas_civil/_mapi.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import requests
2
2
  import sys
3
+ import winreg
3
4
 
4
5
 
5
6
  def Midas_help():
@@ -8,6 +9,8 @@ def Midas_help():
8
9
  print("| HELP MANUAL : https://midas-rnd.github.io/midasapi-python/ |")
9
10
  print("---"*22,"\n")
10
11
 
12
+
13
+
11
14
  class MAPI_PRODUCT:
12
15
  product = "civil"
13
16
 
@@ -19,16 +22,26 @@ class MAPI_PRODUCT:
19
22
 
20
23
  class MAPI_KEY:
21
24
  """MAPI key from Civil NX.\n\nEg: MAPI_Key("eadsfjaks568wqehhf.ajkgj345")"""
22
- data = []
25
+ data = ""
23
26
 
24
27
  def __init__(self, mapi_key:str):
25
- MAPI_KEY.data = []
26
- self.KEY = mapi_key
27
- MAPI_KEY.data.append(self.KEY)
28
+ MAPI_KEY.data = mapi_key
28
29
 
29
30
  @classmethod
30
31
  def get_key(cls):
31
- my_key = MAPI_KEY.data[-1]
32
+ if MAPI_KEY.data == "":
33
+ try:
34
+ key_path = r"Software\\MIDAS\\CVLwNX_US\\CONNECTION"
35
+ registry_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_READ)
36
+ value = winreg.QueryValueEx(registry_key, "Key")
37
+ my_key = value[0]
38
+ print(' 🔑 MAPI KEY is not defined. MAPI-KEY is taken from Registry entry.')
39
+ MAPI_KEY(my_key)
40
+ except:
41
+ print(f"🔑 MAPI KEY is not defined. Click on Apps > API Settings to copy the MAPI Key.")
42
+ sys.exit(0)
43
+ else:
44
+ my_key = MAPI_KEY.data
32
45
  return my_key
33
46
  #---------------------------------------------------------------------------------------------------------------
34
47
 
midas_civil/_model.py CHANGED
@@ -10,6 +10,9 @@ from ._section import *
10
10
  from ._material import *
11
11
  from ._thickness import *
12
12
 
13
+ from ._tendon import *
14
+ from ._result import *
15
+
13
16
  class Model:
14
17
 
15
18
  #4 Function to check analysis status & perform analysis if not analyzed
@@ -238,6 +241,9 @@ class Model:
238
241
  Group.create()
239
242
  Boundary.create()
240
243
  Load.create()
244
+ Tendon.create()
245
+
246
+ LoadCombination.create()
241
247
 
242
248
 
243
249