midas-civil 0.1.5__py3-none-any.whl → 0.1.7__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 +2 -0
- midas_civil/_boundary.py +11 -1
- midas_civil/_construction.py +565 -1
- midas_civil/_element.py +179 -0
- midas_civil/_group.py +5 -2
- midas_civil/_load.py +51 -23
- midas_civil/_mapi.py +57 -11
- midas_civil/_model.py +3 -0
- midas_civil/_node.py +14 -1
- midas_civil/_result.py +1 -1
- midas_civil/_section.py +137 -3
- midas_civil/_temperature.py +30 -0
- midas_civil/_tendon.py +19 -0
- midas_civil/_view.py +5 -0
- {midas_civil-0.1.5.dist-info → midas_civil-0.1.7.dist-info}/METADATA +1 -1
- midas_civil-0.1.7.dist-info/RECORD +27 -0
- midas_civil-0.1.5.dist-info/RECORD +0 -27
- {midas_civil-0.1.5.dist-info → midas_civil-0.1.7.dist-info}/WHEEL +0 -0
- {midas_civil-0.1.5.dist-info → midas_civil-0.1.7.dist-info}/licenses/LICENSE +0 -0
- {midas_civil-0.1.5.dist-info → midas_civil-0.1.7.dist-info}/top_level.txt +0 -0
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.
|
|
@@ -37,8 +43,12 @@ def _ADD(self):
|
|
|
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
|
|
|
@@ -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
|
@@ -8,18 +8,21 @@ from ._mapi import *
|
|
|
8
8
|
# ----------- HELPER FUNCTION -----------
|
|
9
9
|
# -------- RETRIEVE NODE / ELEMENT FROM STRUCTURE GROUP -------
|
|
10
10
|
|
|
11
|
-
def
|
|
11
|
+
def nodesInGroup(groupName:str) -> list | int:
|
|
12
12
|
''' Returns Node ID list in a Structure Group '''
|
|
13
13
|
for i in Group.Structure.Groups:
|
|
14
14
|
if i.NAME == groupName:
|
|
15
15
|
return i.NLIST
|
|
16
|
+
print('⚠️ Structure group not found !')
|
|
16
17
|
return []
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
|
|
20
|
+
def elemsInGroup(groupName:str) -> list:
|
|
19
21
|
''' Returns Element ID list in a Structure Group '''
|
|
20
22
|
for i in Group.Structure.Groups:
|
|
21
23
|
if i.NAME == groupName:
|
|
22
24
|
return i.ELIST
|
|
25
|
+
print('⚠️ Structure group not found !')
|
|
23
26
|
return []
|
|
24
27
|
|
|
25
28
|
|
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.
|
|
@@ -74,10 +96,12 @@ class Load:
|
|
|
74
96
|
Sample: Load_SW("Self-Weight", "Z", -1, "DL")"""
|
|
75
97
|
data = []
|
|
76
98
|
def __init__(self, load_case, dir = "Z", value = -1, load_group = ""):
|
|
99
|
+
|
|
77
100
|
chk = 0
|
|
78
101
|
for i in Load_Case.cases:
|
|
79
102
|
if load_case in i.NAME: chk = 1
|
|
80
103
|
if chk == 0: Load_Case("D", load_case)
|
|
104
|
+
|
|
81
105
|
if load_group != "":
|
|
82
106
|
chk = 0
|
|
83
107
|
a = [v['NAME'] for v in Group.Load.json()["Assign"].values()]
|
|
@@ -177,7 +201,9 @@ class Load:
|
|
|
177
201
|
self.MZ = MZ
|
|
178
202
|
if id == "": id = len(Load.Nodal.data) + 1
|
|
179
203
|
self.ID = id
|
|
180
|
-
|
|
204
|
+
|
|
205
|
+
_ADD_NodalLoad(self)
|
|
206
|
+
# Load.Nodal.data.append(self)
|
|
181
207
|
|
|
182
208
|
@classmethod
|
|
183
209
|
def json(cls):
|
|
@@ -228,9 +254,9 @@ class Load:
|
|
|
228
254
|
#19 Class to define Beam Loads:
|
|
229
255
|
class Beam:
|
|
230
256
|
data = []
|
|
231
|
-
def __init__(self, element
|
|
257
|
+
def __init__(self, element, load_case: str, load_group: str = "", value: float=0, direction: str = "GZ",
|
|
232
258
|
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
|
|
259
|
+
eccn_dir = "LZ", eccn_type = 1, ieccn = 0, jeccn = 0, adnl_h = False, adnl_h_i = 0, adnl_h_j = 0):
|
|
234
260
|
"""
|
|
235
261
|
element: Element Number
|
|
236
262
|
load_case (str): Load case name
|
|
@@ -276,7 +302,7 @@ class Load:
|
|
|
276
302
|
if cmd not in ("BEAM", "LINE", "TYPICAL"): cmd = "BEAM"
|
|
277
303
|
if typ not in ("CONLOAD", "CONMOMENT", "UNILOAD", "UNIMOMENT","PRESSURE"): typ = "UNILOAD"
|
|
278
304
|
if use_ecc == False:
|
|
279
|
-
if ieccn != 0 or jeccn != 0
|
|
305
|
+
if ieccn != 0 or jeccn != 0: use_ecc = True
|
|
280
306
|
self.ELEMENT = element
|
|
281
307
|
self.LCN = load_case
|
|
282
308
|
self.LDGR = load_group
|
|
@@ -289,7 +315,7 @@ class Load:
|
|
|
289
315
|
self.ECCEN_TYPE = eccn_type
|
|
290
316
|
self.ECCEN_DIR = eccn_dir
|
|
291
317
|
self.IECC = ieccn
|
|
292
|
-
if jeccn == 0
|
|
318
|
+
if jeccn == 0:
|
|
293
319
|
self.JECC = 0
|
|
294
320
|
self.USE_JECC = False
|
|
295
321
|
else:
|
|
@@ -299,7 +325,7 @@ class Load:
|
|
|
299
325
|
self.P = P
|
|
300
326
|
self.USE_H = adnl_h
|
|
301
327
|
self.I_H = adnl_h_i
|
|
302
|
-
if adnl_h == 0
|
|
328
|
+
if adnl_h == 0:
|
|
303
329
|
self.USE_JH = False
|
|
304
330
|
self.J_H = 0
|
|
305
331
|
else:
|
|
@@ -309,7 +335,8 @@ class Load:
|
|
|
309
335
|
if id == "":
|
|
310
336
|
id = len(Load.Beam.data) + 1
|
|
311
337
|
self.ID = id
|
|
312
|
-
|
|
338
|
+
_ADD_BeamLoad(self)
|
|
339
|
+
# Load.Beam.data.append(self)
|
|
313
340
|
|
|
314
341
|
@classmethod
|
|
315
342
|
def json(cls):
|
|
@@ -368,23 +395,23 @@ class Load:
|
|
|
368
395
|
for i in a['BMLD'].keys():
|
|
369
396
|
for j in range(len(a['BMLD'][i]['ITEMS'])):
|
|
370
397
|
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]['
|
|
398
|
+
Load.Beam(i,a['BMLD'][i]['ITEMS'][j]['LCNAME'], a['BMLD'][i]['ITEMS'][j]['GROUP_NAME'], a['BMLD'][i]['ITEMS'][j]['P'][0],
|
|
372
399
|
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
400
|
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
401
|
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
402
|
a['BMLD'][i]['ITEMS'][j]['USE_ADDITIONAL'], a['BMLD'][i]['ITEMS'][j]['ADDITIONAL_I_END'], a['BMLD'][i]['ITEMS'][j]['ADDITIONAL_J_END'])
|
|
376
403
|
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]['
|
|
404
|
+
Load.Beam(i,a['BMLD'][i]['ITEMS'][j]['LCNAME'], a['BMLD'][i]['ITEMS'][j]['GROUP_NAME'], a['BMLD'][i]['ITEMS'][j]['P'][0],
|
|
378
405
|
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
406
|
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
407
|
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
408
|
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]['
|
|
409
|
+
Load.Beam(i,a['BMLD'][i]['ITEMS'][j]['LCNAME'], a['BMLD'][i]['ITEMS'][j]['GROUP_NAME'], a['BMLD'][i]['ITEMS'][j]['P'][0],
|
|
383
410
|
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
411
|
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
412
|
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
413
|
else:
|
|
387
|
-
Load.Beam(i,a['BMLD'][i]['ITEMS'][j]['LCNAME'], a['BMLD'][i]['ITEMS'][j]['
|
|
414
|
+
Load.Beam(i,a['BMLD'][i]['ITEMS'][j]['LCNAME'], a['BMLD'][i]['ITEMS'][j]['GROUP_NAME'],a['BMLD'][i]['ITEMS'][j]['P'][0],
|
|
388
415
|
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
416
|
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
417
|
|
|
@@ -521,12 +548,13 @@ class Load:
|
|
|
521
548
|
|
|
522
549
|
class NodalMass:
|
|
523
550
|
"""Creates nodal mass and converts to JSON format.
|
|
524
|
-
Example: NodalMass(1.5, 2.0, 3.0, 0.1, 0.2, 0.3)
|
|
551
|
+
Example: NodalMass(1, 1.5, 2.0, 3.0, 0.1, 0.2, 0.3)
|
|
525
552
|
"""
|
|
526
553
|
data = []
|
|
527
|
-
|
|
528
|
-
def __init__(self, mX, mY=0, mZ=0, rmX=0, rmY=0, rmZ=0):
|
|
554
|
+
|
|
555
|
+
def __init__(self, node_id, mX, mY=0, mZ=0, rmX=0, rmY=0, rmZ=0):
|
|
529
556
|
"""
|
|
557
|
+
node_id (int): Node ID where the mass is applied (Required)
|
|
530
558
|
mX (float): Translational Lumped Mass in GCS X-direction (Required)
|
|
531
559
|
mY (float): Translational Lumped Mass in GCS Y-direction. Defaults to 0
|
|
532
560
|
mZ (float): Translational Lumped Mass in GCS Z-direction. Defaults to 0
|
|
@@ -534,6 +562,7 @@ class Load:
|
|
|
534
562
|
rmY (float): Rotational Mass Moment of Inertia about GCS Y-axis. Defaults to 0
|
|
535
563
|
rmZ (float): Rotational Mass Moment of Inertia about GCS Z-axis. Defaults to 0
|
|
536
564
|
"""
|
|
565
|
+
self.NODE_ID = node_id
|
|
537
566
|
self.MX = mX
|
|
538
567
|
self.MY = mY
|
|
539
568
|
self.MZ = mZ
|
|
@@ -547,10 +576,8 @@ class Load:
|
|
|
547
576
|
def json(cls):
|
|
548
577
|
json_data = {"Assign": {}}
|
|
549
578
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
mass_obj = cls.data[-1] # Get the most recent mass object
|
|
553
|
-
json_data["Assign"]["1"] = {
|
|
579
|
+
for mass_obj in cls.data:
|
|
580
|
+
json_data["Assign"][mass_obj.NODE_ID] = {
|
|
554
581
|
"mX": mass_obj.MX,
|
|
555
582
|
"mY": mass_obj.MY,
|
|
556
583
|
"mZ": mass_obj.MZ,
|
|
@@ -567,23 +594,24 @@ class Load:
|
|
|
567
594
|
|
|
568
595
|
@classmethod
|
|
569
596
|
def get(cls):
|
|
570
|
-
|
|
597
|
+
MidasAPI("GET", "/db/nmas")
|
|
571
598
|
|
|
572
599
|
@classmethod
|
|
573
600
|
def delete(cls):
|
|
574
601
|
cls.data = []
|
|
575
|
-
|
|
602
|
+
MidasAPI("DELETE", "/db/nmas")
|
|
576
603
|
|
|
577
604
|
@classmethod
|
|
578
605
|
def sync(cls):
|
|
579
606
|
cls.data = []
|
|
580
607
|
response = cls.get()
|
|
581
608
|
|
|
582
|
-
if response != {'message': ''}:
|
|
609
|
+
if response and response != {'message': ''}:
|
|
583
610
|
nmas_data = response.get('NMAS', {})
|
|
584
|
-
|
|
585
|
-
|
|
611
|
+
|
|
612
|
+
for node_id, item_data in nmas_data.items():
|
|
586
613
|
Load.NodalMass(
|
|
614
|
+
node_id=int(node_id),
|
|
587
615
|
mX=item_data.get('mX'),
|
|
588
616
|
mY=item_data.get('mY'),
|
|
589
617
|
mZ=item_data.get('mZ'),
|
midas_civil/_mapi.py
CHANGED
|
@@ -11,17 +11,63 @@ def Midas_help():
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
class
|
|
15
|
-
|
|
14
|
+
class MAPI_COUNTRY:
|
|
15
|
+
|
|
16
|
+
country = "US"
|
|
17
|
+
|
|
18
|
+
def __init__(self,country:str):
|
|
19
|
+
''' Define Civil NX country to automatically set Base URL and MAPI Key from registry.
|
|
20
|
+
```
|
|
21
|
+
MAPI_COUNTRY('US')
|
|
22
|
+
MAPI_COUNTRY('CN')
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
'''
|
|
26
|
+
if country.lower() == 'cn':
|
|
27
|
+
MAPI_COUNTRY.country = 'CN'
|
|
28
|
+
else:
|
|
29
|
+
MAPI_COUNTRY.country = 'US'
|
|
30
|
+
|
|
31
|
+
MAPI_BASEURL.set_url()
|
|
32
|
+
MAPI_KEY.get_key()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class MAPI_BASEURL:
|
|
36
|
+
baseURL = "https://moa-engineers.midasit.com:443/civil"
|
|
37
|
+
|
|
38
|
+
def __init__(self, baseURL:str):
|
|
39
|
+
''' Define the Base URL for API connection.
|
|
40
|
+
```
|
|
41
|
+
MAPI_BASEURL('https://moa-engineers.midasit.com:443/civil')
|
|
42
|
+
```
|
|
43
|
+
'''
|
|
44
|
+
MAPI_BASEURL.baseURL = baseURL
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def get_url(cls):
|
|
48
|
+
return MAPI_BASEURL.baseURL
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def set_url(cls):
|
|
52
|
+
try:
|
|
53
|
+
key_path = f"Software\\MIDAS\\CVLwNX_{MAPI_COUNTRY.country}\\CONNECTION"
|
|
54
|
+
registry_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_READ)
|
|
55
|
+
url_reg = winreg.QueryValueEx(registry_key, "URI")
|
|
56
|
+
url_reg_key = url_reg[0]
|
|
57
|
+
|
|
58
|
+
port_reg = winreg.QueryValueEx(registry_key, "PORT")
|
|
59
|
+
port_reg_key = port_reg[0]
|
|
16
60
|
|
|
17
|
-
|
|
18
|
-
"""Product 'civil' or 'gen'"""
|
|
19
|
-
if product.lower() == 'gen':
|
|
20
|
-
MAPI_PRODUCT.product = 'gen'
|
|
61
|
+
url_comb = f'https://{url_reg_key}:{port_reg_key}/civil'
|
|
21
62
|
|
|
63
|
+
print(f' 🌐 BASE URL is taken from Registry entry. >> {url_comb}')
|
|
64
|
+
MAPI_BASEURL(url_comb)
|
|
65
|
+
except:
|
|
66
|
+
print(" 🌐 BASE URL is not defined. Click on Apps > API Settings to copy the BASE URL Key.\nDefine it using MAPI_BASEURL('https://moa-engineers.midasit.com:443/civil')")
|
|
67
|
+
sys.exit(0)
|
|
22
68
|
|
|
23
69
|
class MAPI_KEY:
|
|
24
|
-
"""MAPI key from Civil NX.\n\nEg: MAPI_Key("eadsfjaks568wqehhf.
|
|
70
|
+
"""MAPI key from Civil NX.\n\nEg: MAPI_Key("eadsfjaks568wqehhf.ajkgj345qfhh")"""
|
|
25
71
|
data = ""
|
|
26
72
|
|
|
27
73
|
def __init__(self, mapi_key:str):
|
|
@@ -31,14 +77,14 @@ class MAPI_KEY:
|
|
|
31
77
|
def get_key(cls):
|
|
32
78
|
if MAPI_KEY.data == "":
|
|
33
79
|
try:
|
|
34
|
-
key_path =
|
|
80
|
+
key_path = f"Software\\MIDAS\\CVLwNX_{MAPI_COUNTRY.country}\\CONNECTION"
|
|
35
81
|
registry_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_READ)
|
|
36
82
|
value = winreg.QueryValueEx(registry_key, "Key")
|
|
37
83
|
my_key = value[0]
|
|
38
|
-
print(' 🔑
|
|
84
|
+
print(f' 🔑 MAPI-KEY is taken from Registry entry. >> {my_key[:35]}...')
|
|
39
85
|
MAPI_KEY(my_key)
|
|
40
86
|
except:
|
|
41
|
-
print(f"🔑 MAPI KEY is not defined. Click on Apps > API Settings to copy the MAPI Key
|
|
87
|
+
print(f"🔑 MAPI KEY is not defined. Click on Apps > API Settings to copy the MAPI Key.\n Define it using MAPI_KEY('xxxx')")
|
|
42
88
|
sys.exit(0)
|
|
43
89
|
else:
|
|
44
90
|
my_key = MAPI_KEY.data
|
|
@@ -57,7 +103,7 @@ def MidasAPI(method:str, command:str, body:dict={})->dict:
|
|
|
57
103
|
# Create a node
|
|
58
104
|
MidasAPI("PUT","/db/NODE",{{"Assign":{{"1":{{'X':0, 'Y':0, 'Z':0}}}}}})"""
|
|
59
105
|
|
|
60
|
-
base_url =
|
|
106
|
+
base_url = MAPI_BASEURL.baseURL
|
|
61
107
|
mapi_key = MAPI_KEY.get_key()
|
|
62
108
|
|
|
63
109
|
url = base_url + command
|
midas_civil/_model.py
CHANGED
|
@@ -11,6 +11,7 @@ from ._material import *
|
|
|
11
11
|
from ._thickness import *
|
|
12
12
|
|
|
13
13
|
from ._tendon import *
|
|
14
|
+
from ._result import *
|
|
14
15
|
|
|
15
16
|
class Model:
|
|
16
17
|
|
|
@@ -242,6 +243,8 @@ class Model:
|
|
|
242
243
|
Load.create()
|
|
243
244
|
Tendon.create()
|
|
244
245
|
|
|
246
|
+
LoadCombination.create()
|
|
247
|
+
|
|
245
248
|
|
|
246
249
|
|
|
247
250
|
|
midas_civil/_node.py
CHANGED
|
@@ -12,7 +12,10 @@ def dist_tol(a,b):
|
|
|
12
12
|
def cell(point,size=1): #SIZE OF GRID
|
|
13
13
|
return (int(point.X//size),int(point.Y//size),int(point.Z//size))
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
# -------- FUNCTIONS ARE DEFINED BELOW TO RECOGNISE NODE CLASS ----------------
|
|
17
|
+
|
|
18
|
+
|
|
16
19
|
|
|
17
20
|
#5 Class to create nodes
|
|
18
21
|
class Node:
|
|
@@ -161,6 +164,16 @@ class Node:
|
|
|
161
164
|
|
|
162
165
|
|
|
163
166
|
|
|
167
|
+
# ---- GET NODE OBJECT FROM ID ----------
|
|
168
|
+
|
|
169
|
+
def nodeByID(nodeID:int) -> Node:
|
|
170
|
+
''' Return Node object with the input ID '''
|
|
171
|
+
for node in Node.nodes:
|
|
172
|
+
if node.ID == nodeID:
|
|
173
|
+
return node
|
|
174
|
+
|
|
175
|
+
print(f'There is no node with ID {nodeID}')
|
|
176
|
+
return None
|
|
164
177
|
|
|
165
178
|
|
|
166
179
|
|
midas_civil/_result.py
CHANGED
|
@@ -111,7 +111,7 @@ class LoadCombination:
|
|
|
111
111
|
@classmethod
|
|
112
112
|
def create(cls, classification = "All"):
|
|
113
113
|
if len(LoadCombination.data) == 0:
|
|
114
|
-
print("No Load Combinations defined! Define the load combination using the 'LoadCombination' class before creating these in the model.")
|
|
114
|
+
# print("No Load Combinations defined! Define the load combination using the 'LoadCombination' class before creating these in the model.")
|
|
115
115
|
return
|
|
116
116
|
if classification not in LoadCombination.valid:
|
|
117
117
|
print(f'"{classification}" is not a valid input. It is changed to "General".')
|