midas-civil 0.0.9__py3-none-any.whl → 0.1.1__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/_group.py CHANGED
@@ -1,5 +1,24 @@
1
1
 
2
2
  from ._mapi import *
3
+
4
+
5
+
6
+ # ----------- HELPER FUNCTION -----------
7
+ # -------- ADD ELEMENT TO STRUCTURE GROUP -------
8
+
9
+ def _add_elem_2_stGroup(elemID,groupName):
10
+ up = 0
11
+ if groupName in Group.Structure._names:
12
+ for i in Group.Structure.Groups:
13
+ if i.NAME == groupName:
14
+ i.ELIST = list(i.ELIST + [elemID])
15
+ else:
16
+ Group.Structure(groupName)
17
+ _add_elem_2_stGroup(elemID,groupName)
18
+
19
+
20
+
21
+
3
22
  #---------------------------------------------------------------------------------------------------------------
4
23
  class Group:
5
24
 
@@ -35,6 +54,7 @@ class Group:
35
54
 
36
55
  Groups = []
37
56
  ids=[]
57
+ _names = []
38
58
  url= "/db/GRUP"
39
59
 
40
60
  def __init__(self, name, nlist=[],elist=[]):
@@ -46,6 +66,7 @@ class Group:
46
66
  self.NLIST = list(set(nlist))
47
67
  Group.Structure.ids.append(self.ID)
48
68
  Group.Structure.Groups.append(self)
69
+ Group.Structure._names.append(self.NAME)
49
70
 
50
71
  @classmethod
51
72
  def update(cls, name,operation = "r", nlist = [],elist = [] ):
@@ -65,7 +86,7 @@ class Group:
65
86
 
66
87
  @classmethod
67
88
  def json(cls):
68
- "Generates the json file for all defined structure groups."
89
+ """Generates the json file for all defined structure groups."""
69
90
  json = {"Assign":{}}
70
91
  for i in cls.Groups:
71
92
  json["Assign"][i.ID] = {
midas_civil/_load.py CHANGED
@@ -122,6 +122,11 @@ class Load:
122
122
  def get():
123
123
  return MidasAPI("GET","/db/BODF")
124
124
 
125
+ @classmethod
126
+ def delete(cls):
127
+ cls.data=[]
128
+ return MidasAPI("DELETE","/db/BODF")
129
+
125
130
  @staticmethod
126
131
  def sync():
127
132
  a = Load.SW.get()
@@ -264,7 +269,8 @@ class Load:
264
269
  D = (D + [0] * 4)[:4]
265
270
  P = (P + [0] * 4)[:4]
266
271
  if P == [0, 0, 0, 0]: P = [value, value, 0, 0]
267
- if eccn_type != 0 or eccn_type != 1: eccn_type = 0
272
+ if eccn_type not in (0, 1):
273
+ eccn_type = 1
268
274
  if direction not in ("GX", "GY", "GZ", "LX", "LY", "LZ"): direction = "GZ"
269
275
  if eccn_dir not in ("GX", "GY", "GZ", "LX", "LY", "LZ"): eccn_dir = "LY"
270
276
  if cmd not in ("BEAM", "LINE", "TYPICAL"): cmd = "BEAM"
@@ -381,4 +387,321 @@ class Load:
381
387
  Load.Beam(i,a['BMLD'][i]['ITEMS'][j]['LCNAME'], a['BMLD'][i]['ITEMS'][j]['P'][0], a['BMLD'][i]['ITEMS'][j]['GROUP_NAME'],
382
388
  a['BMLD'][i]['ITEMS'][j]['DIRECTION'], a['BMLD'][i]['ITEMS'][j]['ID'], a['BMLD'][i]['ITEMS'][j]['D'], a['BMLD'][i]['ITEMS'][j]['P'],
383
389
  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'])
384
- #---------------------------------------------------------------------------------------------------------------
390
+
391
+
392
+ #-------------------------------- Load to Mass ------------------------------------------------------------
393
+
394
+ #20 Class to add Load to Mass:
395
+ class LoadToMass:
396
+ """Creates load to mass conversion and converts to JSON format.
397
+ Example: LoadToMass("Z", ["DL", "LL"], [1.0, 0.5])
398
+ """
399
+ data = []
400
+
401
+ def __init__(self, dir, load_case, load_factor=None, nodal_load=True, beam_load=True,
402
+ floor_load=True, pressure=True, gravity=9.806):
403
+ """
404
+ dir (str): Mass Direction - "X", "Y", "Z", "XY", "YZ", "XZ", "XYZ"
405
+ load_case (list): List of load case names
406
+ load_factor (list, optional): List of scale factors corresponding to load cases.
407
+ If None or shorter than load_case, remaining factors default to 1.0
408
+ nodal_load (bool): Include nodal loads. Defaults to True
409
+ beam_load (bool): Include beam loads. Defaults to True
410
+ floor_load (bool): Include floor loads. Defaults to True
411
+ pressure (bool): Include pressure loads. Defaults to True
412
+ gravity (float): Gravity acceleration. Defaults to 9.806
413
+ """
414
+
415
+ # Validate direction
416
+ valid_directions = ["X", "Y", "Z", "XY", "YZ", "XZ", "XYZ"]
417
+ if dir not in valid_directions:
418
+ dir = "XYZ" # Default to XYZ if invalid
419
+
420
+ # Ensure load_case is a list
421
+ if not isinstance(load_case, list):
422
+ load_case = [load_case]
423
+
424
+ # Handle load_factor - ensure it matches load_case length
425
+ if load_factor is None:
426
+ load_factor = [1.0] * len(load_case)
427
+ elif not isinstance(load_factor, list):
428
+ load_factor = [load_factor]
429
+
430
+ # Pad load_factor with 1.0 if shorter than load_case
431
+ while len(load_factor) < len(load_case):
432
+ load_factor.append(1.0)
433
+
434
+ # Check if load cases exist - give warning if not
435
+ for case in load_case:
436
+ chk = 0
437
+ for i in Load_Case.cases:
438
+ if case in i.NAME:
439
+ chk = 1
440
+ if chk == 0:
441
+ print(f"Warning: Load case '{case}' does not exist!")
442
+
443
+ self.DIR = dir
444
+ self.LOAD_CASE = load_case
445
+ self.LOAD_FACTOR = load_factor
446
+ self.NODAL = nodal_load
447
+ self.BEAM = beam_load
448
+ self.FLOOR = floor_load
449
+ self.PRESSURE = pressure
450
+ self.GRAVITY = gravity
451
+
452
+ Load.LoadToMass.data.append(self)
453
+
454
+ @classmethod
455
+ def json(cls):
456
+ json_data = {"Assign": {}}
457
+
458
+ for load_obj in enumerate(cls.data):
459
+ # Create vLC array with load case names and factors
460
+ vlc_array = []
461
+ for i, case_name in enumerate(load_obj.LOAD_CASE):
462
+ vlc_array.append({
463
+ "LCNAME": case_name,
464
+ "FACTOR": load_obj.LOAD_FACTOR[i]
465
+ })
466
+
467
+ json_data["Assign"]["1"] = {
468
+ "DIR": load_obj.DIR,
469
+ "bNODAL": load_obj.NODAL,
470
+ "bBEAM": load_obj.BEAM,
471
+ "bFLOOR": load_obj.FLOOR,
472
+ "bPRES": load_obj.PRESSURE,
473
+ "GRAV": load_obj.GRAVITY,
474
+ "vLC": vlc_array
475
+ }
476
+
477
+ return json_data
478
+
479
+ @classmethod
480
+ def create(cls):
481
+ return MidasAPI("PUT", "/db/ltom", cls.json())
482
+
483
+ @classmethod
484
+ def get(cls):
485
+ return MidasAPI("GET", "/db/ltom")
486
+
487
+ @classmethod
488
+ def delete(cls):
489
+ cls.data = []
490
+ return MidasAPI("DELETE", "/db/ltom")
491
+
492
+ @classmethod
493
+ def sync(cls):
494
+ cls.data = []
495
+ response = cls.get()
496
+
497
+ if response != {'message': ''}:
498
+ for key, item_data in response.get('LTOM', {}).items():
499
+ # Extract load cases and factors from vLC array
500
+ load_cases = []
501
+ load_factors = []
502
+
503
+ for lc_item in item_data.get('vLC'):
504
+ load_cases.append(lc_item.get('LCNAME'))
505
+ load_factors.append(lc_item.get('FACTOR'))
506
+
507
+ # Create LoadToMass object
508
+ Load.LoadToMass(
509
+ dir=item_data.get('DIR'),
510
+ load_case=load_cases,
511
+ load_factor=load_factors,
512
+ nodal_load=item_data.get('bNODAL'),
513
+ beam_load=item_data.get('bBEAM'),
514
+ floor_load=item_data.get('bFLOOR'),
515
+ pressure=item_data.get('bPRES'),
516
+ gravity=item_data.get('GRAV')
517
+ )
518
+
519
+ #-----------------------------------------------------------NodalMass-----------------
520
+ #21NodalMass
521
+
522
+ class NodalMass:
523
+ """Creates nodal mass and converts to JSON format.
524
+ Example: NodalMass(1.5, 2.0, 3.0, 0.1, 0.2, 0.3)
525
+ """
526
+ data = []
527
+
528
+ def __init__(self, mX, mY=0, mZ=0, rmX=0, rmY=0, rmZ=0):
529
+ """
530
+ mX (float): Translational Lumped Mass in GCS X-direction (Required)
531
+ mY (float): Translational Lumped Mass in GCS Y-direction. Defaults to 0
532
+ mZ (float): Translational Lumped Mass in GCS Z-direction. Defaults to 0
533
+ rmX (float): Rotational Mass Moment of Inertia about GCS X-axis. Defaults to 0
534
+ rmY (float): Rotational Mass Moment of Inertia about GCS Y-axis. Defaults to 0
535
+ rmZ (float): Rotational Mass Moment of Inertia about GCS Z-axis. Defaults to 0
536
+ """
537
+ self.MX = mX
538
+ self.MY = mY
539
+ self.MZ = mZ
540
+ self.RMX = rmX
541
+ self.RMY = rmY
542
+ self.RMZ = rmZ
543
+
544
+ Load.NodalMass.data.append(self)
545
+
546
+ @classmethod
547
+ def json(cls):
548
+ json_data = {"Assign": {}}
549
+
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"] = {
554
+ "mX": mass_obj.MX,
555
+ "mY": mass_obj.MY,
556
+ "mZ": mass_obj.MZ,
557
+ "rmX": mass_obj.RMX,
558
+ "rmY": mass_obj.RMY,
559
+ "rmZ": mass_obj.RMZ
560
+ }
561
+
562
+ return json_data
563
+
564
+ @classmethod
565
+ def create(cls):
566
+ return MidasAPI("PUT", "/db/nmas", cls.json())
567
+
568
+ @classmethod
569
+ def get(cls):
570
+ return MidasAPI("GET", "/db/nmas")
571
+
572
+ @classmethod
573
+ def delete(cls):
574
+ cls.data = []
575
+ return MidasAPI("DELETE", "/db/nmas")
576
+
577
+ @classmethod
578
+ def sync(cls):
579
+ cls.data = []
580
+ response = cls.get()
581
+
582
+ if response != {'message': ''}:
583
+ nmas_data = response.get('NMAS', {})
584
+ if "1" in nmas_data:
585
+ item_data = nmas_data["1"]
586
+ Load.NodalMass(
587
+ mX=item_data.get('mX'),
588
+ mY=item_data.get('mY'),
589
+ mZ=item_data.get('mZ'),
590
+ rmX=item_data.get('rmX'),
591
+ rmY=item_data.get('rmY'),
592
+ rmZ=item_data.get('rmZ')
593
+ )
594
+
595
+ #-----------------------------------------------------------Specified Displacement-------------------------------------------------
596
+ class SpDisp:
597
+ """Creates specified displacement loads and converts to JSON format.
598
+ Example: SpDisp(10, "LL", "Group1", [1.5, 1.5, 1.5, 1.5, 0.5, 0.5])
599
+ """
600
+ data = []
601
+
602
+ def __init__(self, node, load_case, load_group="", values=[0, 0, 0, 0, 0, 0], id=""):
603
+ """
604
+ node (int): Node number (Required)
605
+ load_case (str): Load case name (Required)
606
+ load_group (str, optional): Load group name. Defaults to ""
607
+ values (list): Displacement values [Dx, Dy, Dz, Rx, Ry, Rz]. Defaults to [0, 0, 0, 0, 0, 0]
608
+ id (str, optional): Load ID. Defaults to auto-generated
609
+ """
610
+
611
+ # Check if load case exists - give warning if not
612
+ chk = 0
613
+ for i in Load_Case.cases:
614
+ if load_case in i.NAME:
615
+ chk = 1
616
+ if chk == 0:
617
+ print(f"Warning: Load case '{load_case}' does not exist!")
618
+
619
+ # Check if load group exists and create if specified
620
+ if load_group != "":
621
+ chk = 0
622
+ a = [v['NAME'] for v in Group.Load.json()["Assign"].values()]
623
+ if load_group in a:
624
+ chk = 1
625
+ if chk == 0:
626
+ print(f"Warning: Load group '{load_group}' does not exist!")
627
+
628
+ # Ensure values is a list of 6 elements [Dx, Dy, Dz, Rx, Ry, Rz]
629
+ if not isinstance(values, list):
630
+ values = [0, 0, 0, 0, 0, 0]
631
+
632
+ # Pad or truncate to exactly 6 values
633
+ values = (values + [0] * 6)[:6]
634
+
635
+ self.NODE = node
636
+ self.LCN = load_case
637
+ self.LDGR = load_group
638
+ self.VALUES = values
639
+
640
+ if id == "":
641
+ id = len(Load.SpDisp.data) + 1
642
+ self.ID = id
643
+
644
+ Load.SpDisp.data.append(self)
645
+
646
+ @classmethod
647
+ def json(cls):
648
+ json_data = {"Assign": {}}
649
+
650
+ for i in cls.data:
651
+ if i.NODE not in list(json_data["Assign"].keys()):
652
+ json_data["Assign"][i.NODE] = {"ITEMS": []}
653
+
654
+ # Create VALUES array with OPT_FLAG logic
655
+ values_array = []
656
+ displacement_labels = ["Dx", "Dy", "Dz", "Rx", "Ry", "Rz"]
657
+
658
+ for idx, value in enumerate(i.VALUES):
659
+ values_array.append({
660
+ "OPT_FLAG": value != 0, # True if value > 0, False if value = 0
661
+ "DISPLACEMENT": float(value)
662
+ })
663
+
664
+ json_data["Assign"][i.NODE]["ITEMS"].append({
665
+ "ID": i.ID,
666
+ "LCNAME": i.LCN,
667
+ "GROUP_NAME": i.LDGR,
668
+ "VALUES": values_array
669
+ })
670
+
671
+ return json_data
672
+
673
+ @classmethod
674
+ def create(cls):
675
+ return MidasAPI("PUT", "/db/sdsp", cls.json())
676
+
677
+ @classmethod
678
+ def get(cls):
679
+ return MidasAPI("GET", "/db/sdsp")
680
+
681
+ @classmethod
682
+ def delete(cls):
683
+ cls.data = []
684
+ return MidasAPI("DELETE", "/db/sdsp")
685
+
686
+ @classmethod
687
+ def sync(cls):
688
+ cls.data = []
689
+ response = cls.get()
690
+
691
+ if response != {'message': ''}:
692
+ for node_key in response['SDSP'].keys():
693
+ for j in range(len(response['SDSP'][node_key]['ITEMS'])):
694
+ item = response['SDSP'][node_key]['ITEMS'][j]
695
+
696
+ # Extract displacement values from VALUES array
697
+ values = []
698
+ for val_item in item.get('VALUES', []):
699
+ values.append(val_item.get('DISPLACEMENT', 0))
700
+
701
+ Load.SpDisp(
702
+ int(node_key),
703
+ item['LCNAME'],
704
+ item['GROUP_NAME'],
705
+ values,
706
+ item['ID']
707
+ )
midas_civil/_material.py CHANGED
@@ -58,7 +58,7 @@ class Material:
58
58
  if Material.mats!=[] : Material.create_only()
59
59
  if CreepShrinkage.mats!=[] : CreepShrinkage.create()
60
60
  if CompStrength.mats!=[] : CompStrength.create()
61
- if TDLink.json()!={'Assign':{}} : TDLink.create()
61
+ if TDMatLink.json()!={'Assign':{}} : TDMatLink.create()
62
62
 
63
63
 
64
64
  @staticmethod
@@ -1592,23 +1592,23 @@ class CompStrength:
1592
1592
 
1593
1593
 
1594
1594
 
1595
- class TDLink:
1595
+ class TDMatLink:
1596
1596
  mats = {}
1597
1597
  def __init__(self,matID,CnSName='',CompName=''):
1598
1598
 
1599
- TDLink.mats[str(matID)]={
1599
+ TDMatLink.mats[str(matID)]={
1600
1600
  "TDMT_NAME": CnSName,
1601
1601
  "TDME_NAME": CompName
1602
1602
  }
1603
1603
 
1604
1604
  @classmethod
1605
1605
  def json(cls):
1606
- json = {"Assign": TDLink.mats}
1606
+ json = {"Assign": TDMatLink.mats}
1607
1607
  return json
1608
1608
 
1609
1609
  @staticmethod
1610
1610
  def create():
1611
- MidasAPI("PUT","/db/TMAT",TDLink.json())
1611
+ MidasAPI("PUT","/db/TMAT",TDMatLink.json())
1612
1612
 
1613
1613
  @staticmethod
1614
1614
  def get():
@@ -1618,16 +1618,16 @@ class TDLink:
1618
1618
  @staticmethod
1619
1619
  def delete():
1620
1620
  MidasAPI("DELETE","/db/TMAT")
1621
- TDLink.mats={}
1621
+ TDMatLink.mats={}
1622
1622
 
1623
1623
  @staticmethod
1624
1624
  def sync():
1625
- a = TDLink.get()
1625
+ a = TDMatLink.get()
1626
1626
  if a != {'message': ''}:
1627
1627
  if list(a['TMAT'].keys()) != []:
1628
- TDLink.mats = []
1629
- TDLink.ids=[]
1628
+ TDMatLink.mats = []
1629
+ TDMatLink.ids=[]
1630
1630
  for j in a['TMAT'].keys():
1631
- TDLink(a['TMAT'][j], int(j))
1631
+ TDMatLink(a['TMAT'][j], int(j))
1632
1632
 
1633
1633
  #-------------------------------------------------------------------------------------------------
midas_civil/_model.py CHANGED
@@ -341,6 +341,44 @@ class Model:
341
341
 
342
342
 
343
343
  MidasAPI("PUT","/db/PJCF",js)
344
+
345
+ @staticmethod
346
+ def exportJSON(location=""):
347
+ """Export the model data as JSON file
348
+ Model.exportJSON('D:\\model.json')"""
349
+ if location.endswith('.json'):
350
+ MidasAPI("POST","/doc/EXPORT",{"Argument":str(location)})
351
+ else:
352
+ print('⚠️ Location data in exportJSON is missing file extension')
353
+
354
+ @staticmethod
355
+ def exportMCT(location=""):
356
+ """Export the model data as MCT file
357
+ Model.exportMCT('D:\\model.mct')"""
358
+ if location.endswith('.mct'):
359
+ MidasAPI("POST","/doc/EXPORTMXT",{"Argument":str(location)})
360
+ else:
361
+ print('⚠️ Location data in exportMCT is missing file extension')
362
+
363
+
364
+ @staticmethod
365
+ def importJSON(location=""):
366
+ """Import JSON data file in MIDAS CIVIL NX
367
+ Model.importJSON('D:\\model.json')"""
368
+ if location.endswith('.json'):
369
+ MidasAPI("POST","/doc/IMPORT",{"Argument":str(location)})
370
+ else:
371
+ print('⚠️ Location data in importJSON is missing file extension')
372
+
373
+ @staticmethod
374
+ def importMCT(location=""):
375
+ """Import MCT data file in MIDAS CIVIL NX
376
+ Model.importMCT('D:\\model.mct')"""
377
+ if location.endswith('.mct'):
378
+ MidasAPI("POST","/doc/IMPORTMXT",{"Argument":str(location)})
379
+ else:
380
+ print('⚠️ Location data in importMCT is missing file extension')
381
+
344
382
 
345
383
 
346
384