midas-civil 1.4.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.
Files changed (40) hide show
  1. midas_civil/_BoundaryChangeAssignment.py +278 -0
  2. midas_civil/__init__.py +51 -0
  3. midas_civil/_analysiscontrol.py +585 -0
  4. midas_civil/_boundary.py +888 -0
  5. midas_civil/_construction.py +1004 -0
  6. midas_civil/_element.py +1346 -0
  7. midas_civil/_group.py +337 -0
  8. midas_civil/_load.py +967 -0
  9. midas_civil/_loadcomb.py +159 -0
  10. midas_civil/_mapi.py +249 -0
  11. midas_civil/_material.py +1692 -0
  12. midas_civil/_model.py +522 -0
  13. midas_civil/_movingload.py +1479 -0
  14. midas_civil/_node.py +532 -0
  15. midas_civil/_result_table.py +929 -0
  16. midas_civil/_result_test.py +5455 -0
  17. midas_civil/_section/_TapdbSecSS.py +175 -0
  18. midas_civil/_section/__init__.py +413 -0
  19. midas_civil/_section/_compositeSS.py +283 -0
  20. midas_civil/_section/_dbSecSS.py +164 -0
  21. midas_civil/_section/_offsetSS.py +53 -0
  22. midas_civil/_section/_pscSS copy.py +455 -0
  23. midas_civil/_section/_pscSS.py +822 -0
  24. midas_civil/_section/_tapPSC12CellSS.py +565 -0
  25. midas_civil/_section/_unSupp.py +58 -0
  26. midas_civil/_settlement.py +161 -0
  27. midas_civil/_temperature.py +677 -0
  28. midas_civil/_tendon.py +1016 -0
  29. midas_civil/_thickness.py +147 -0
  30. midas_civil/_utils.py +529 -0
  31. midas_civil/_utilsFunc/__init__.py +0 -0
  32. midas_civil/_utilsFunc/_line2plate.py +636 -0
  33. midas_civil/_view.py +891 -0
  34. midas_civil/_view_trial.py +430 -0
  35. midas_civil/_visualise.py +347 -0
  36. midas_civil-1.4.1.dist-info/METADATA +74 -0
  37. midas_civil-1.4.1.dist-info/RECORD +40 -0
  38. midas_civil-1.4.1.dist-info/WHEEL +5 -0
  39. midas_civil-1.4.1.dist-info/licenses/LICENSE +21 -0
  40. midas_civil-1.4.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1004 @@
1
+ from ._mapi import MidasAPI
2
+
3
+ class CS:
4
+
5
+ @staticmethod
6
+ def create():
7
+ if CS.STAGE.stages!=[]: CS.STAGE.create()
8
+ if CS.CompSec.compsecs!=[] : CS.CompSec.create()
9
+ if CS.TimeLoad.timeloads!=[] : CS.TimeLoad.create()
10
+ if CS.CreepCoeff.creepcoeffs!=[] : CS.CreepCoeff.create()
11
+ if CS.Camber.cambers!=[] : CS.Camber.create()
12
+
13
+ class STAGE:
14
+ stages = []
15
+ _maxID_ = 0
16
+ _maxNO_ = 0
17
+ _isSync_ = False
18
+
19
+ def __init__(self,
20
+ name: str,
21
+ duration: float = 0,
22
+ s_group: str = None,
23
+ s_age: float = None,
24
+ s_type: str= None,
25
+ b_group: str = None,
26
+ b_pos: str = None,
27
+ b_type: str = None,
28
+ l_group: str = None,
29
+ l_day: str = None,
30
+ l_type: str = None,
31
+ id: int = None,
32
+ sv_result: bool = True,
33
+ sv_step: bool = False,
34
+ load_in: bool = False,
35
+ nl: int = 5,
36
+ addstp: list = None):
37
+ """
38
+ Construction Stage define.
39
+
40
+ Parameters:
41
+ name: Name of Construction Stage
42
+ duration: Duration of Construction Stage in days (default 0)
43
+ s_group: Structure group name or list of group names (default None)
44
+ s_age: Age of structure group in days and Redistribution value(%) win case of Deactivation (default 0)
45
+ s_type: Structure activation type - "A" to activate, "D" to deactivate(default A)
46
+ b_group: Boundary group name or list of group names (default None)
47
+ b_pos: Boundary position type - "ORIGINAL" or "DEFORMED", or list (default DEFORMED)
48
+ b_type: Boundary activation type - "A" to activate, "D" to deactivate (default A)
49
+ l_group: Load group name or list of group names (default None)
50
+ l_day: Load activation day - "FIRST" or "LAST" (default "FIRST")
51
+ l_type: Load activation type - "A" to activate, "D" to deactivate (default A)
52
+ id: The construction stage ID (optional)
53
+ sv_result: Save results of this stage (default True)
54
+ sv_step: Add additional step results (default False)
55
+ load_in: Load incremental steps for material nonlinear analysis (default False)
56
+ nl: Number of load incremental steps (default 5)
57
+ addstp: List of additional steps (default None)
58
+
59
+ Examples:
60
+ ```python
61
+ # Single group activation
62
+ CS("CS1", 7, "S1", 7, "A", "B1", "DEFORMED", "A", "L1", "FIRST", "A")
63
+
64
+ # Multiple group activation
65
+ CS("CS1", 7, ["S1", "S2"], [7, 10], ["A", "A"], ["B1", "B2"],
66
+ ["DEFORMED", "DEFORMED"], ["A", "A"], ["L1", "L2"], ["FIRST", "FIRST"], ["A", "A"])
67
+
68
+ # Mixed activation and deactivation
69
+ CS("CS1", 7, ["S1", "S2"], [7, 10], ["A", "D"], ["B1", "B2"],
70
+ ["DEFORMED", "DEFORMED"], ["A", "D"], "L1", "FIRST", "A")
71
+
72
+ # With additional options
73
+ CS("CS1", 7, "S1", 7, "A", "B1", "DEFORMED", "A", "L1", "FIRST", "A",
74
+ sv_result=True, sv_step=True, load_in=True, nl=6, addstp=[1, 2, 3])
75
+ ```
76
+ """
77
+
78
+ self.NAME = name
79
+ self.DURATION = duration
80
+ self.SV_Result = sv_result
81
+ self.SV_Step = sv_step
82
+ self.Load_IN = load_in
83
+ self.NL = nl
84
+ self.addstp = [] if addstp is None else addstp
85
+
86
+ # Initialize group containers
87
+ self.act_structure_groups = []
88
+ self.deact_structure_groups = []
89
+ self.act_boundary_groups = []
90
+ self.deact_boundary_groups = []
91
+ self.act_load_groups = []
92
+ self.deact_load_groups = []
93
+
94
+
95
+ # Set ID
96
+ if id is None:
97
+ self.ID = CS.STAGE._maxID_ + 1
98
+ self.NO = CS.STAGE._maxNO_ + 1
99
+ else:
100
+ self.ID = id
101
+ self.NO = id
102
+ CS.STAGE._maxNO_ = max(CS.STAGE._maxNO_ ,self.NO)
103
+ CS.STAGE._maxID_ = max(CS.STAGE._maxID_ ,self.ID)
104
+
105
+ # Process structure groups
106
+ if s_group:
107
+ # Convert single values to lists for uniform processing
108
+ if not isinstance(s_group, list):
109
+ s_group = [s_group]
110
+ s_age = [s_age if s_age is not None else 0]
111
+ s_type = [s_type if s_type is not None else "A"]
112
+ else:
113
+ # Ensure other parameters are lists too
114
+ if s_age is None:
115
+ s_age = [0] * len(s_group)
116
+ elif not isinstance(s_age, list):
117
+ s_age = [s_age] * len(s_group)
118
+
119
+ if s_type is None:
120
+ s_type = ["A"] * len(s_group)
121
+ elif not isinstance(s_type, list):
122
+ s_type = [s_type] * len(s_group)
123
+
124
+ # Process each structure group
125
+ for i, group in enumerate(s_group):
126
+ if i < len(s_type) and s_type[i] == "A":
127
+ # Activation: Check if already activated in previous stages
128
+ for stage in CS.STAGE.stages:
129
+ for existing_group in stage.act_structure_groups:
130
+ if existing_group["name"] == group:
131
+ raise ValueError(f"Structure group '{group}' has already been activated in stage '{stage.NAME}' (ID: {stage.ID})")
132
+
133
+ age = s_age[i] if i < len(s_age) else 0
134
+ self.act_structure_groups.append({"name": group, "age": age})
135
+ else:
136
+ # Deactivation: Check if activated in previous stages
137
+ activated = False
138
+ for stage in CS.STAGE.stages:
139
+ for existing_group in stage.act_structure_groups:
140
+ if existing_group["name"] == group:
141
+ activated = True
142
+ break
143
+ if activated:
144
+ break
145
+
146
+ if not activated:
147
+ raise ValueError(f"Structure group '{group}' cannot be deactivated as it has not been activated in any previous stage")
148
+
149
+ # For deactivation, s_age value is used as redist percentage
150
+ redist = s_age[i] if i < len(s_age) else 100
151
+ self.deact_structure_groups.append({"name": group, "redist": redist})
152
+
153
+ # Process boundary groups
154
+ if b_group:
155
+ # Convert single values to lists for uniform processing
156
+ if not isinstance(b_group, list):
157
+ b_group = [b_group]
158
+ b_pos = [b_pos if b_pos is not None else "DEFORMED"]
159
+ b_type = [b_type if b_type is not None else "A"]
160
+ else:
161
+ # Ensure other parameters are lists too
162
+ if b_pos is None:
163
+ b_pos = ["DEFORMED"] * len(b_group)
164
+ elif not isinstance(b_pos, list):
165
+ b_pos = [b_pos] * len(b_group)
166
+
167
+ if b_type is None:
168
+ b_type = ["A"] * len(b_group)
169
+ elif not isinstance(b_type, list):
170
+ b_type = [b_type] * len(b_group)
171
+
172
+ # Process each boundary group
173
+ for i, group in enumerate(b_group):
174
+ if i < len(b_type) and b_type[i] == "A":
175
+ # Activation: Check if already activated in previous stages
176
+ for stage in CS.STAGE.stages:
177
+ for existing_group in stage.act_boundary_groups:
178
+ if existing_group["name"] == group:
179
+ raise ValueError(f"Boundary group '{group}' has already been activated in stage '{stage.NAME}' (ID: {stage.ID})")
180
+
181
+ pos = b_pos[i] if i < len(b_pos) else "DEFORMED"
182
+ self.act_boundary_groups.append({"name": group, "pos": pos})
183
+ else:
184
+ # Deactivation: Check if activated in previous stages
185
+ activated = False
186
+ for stage in CS.STAGE.stages:
187
+ for existing_group in stage.act_boundary_groups:
188
+ if existing_group["name"] == group:
189
+ activated = True
190
+ break
191
+ if activated:
192
+ break
193
+
194
+ if not activated:
195
+ raise ValueError(f"Boundary group '{group}' cannot be deactivated as it has not been activated in any previous stage")
196
+
197
+ self.deact_boundary_groups.append(group)
198
+
199
+ # Process load groups
200
+ if l_group:
201
+ # Convert single values to lists for uniform processing
202
+ if not isinstance(l_group, list):
203
+ l_group = [l_group]
204
+ l_day = [l_day if l_day is not None else "FIRST"]
205
+ l_type = [l_type if l_type is not None else "A"]
206
+ else:
207
+ # Ensure other parameters are lists too
208
+ if l_day is None:
209
+ l_day = ["FIRST"] * len(l_group)
210
+ elif not isinstance(l_day, list):
211
+ l_day = [l_day] * len(l_group)
212
+
213
+ if l_type is None:
214
+ l_type = ["A"] * len(l_group)
215
+ elif not isinstance(l_type, list):
216
+ l_type = [l_type] * len(l_group)
217
+
218
+ # Process each load group
219
+ for i, group in enumerate(l_group):
220
+ if i < len(l_type) and l_type[i] == "A":
221
+ # Activation: Check if already activated in previous stages
222
+ for stage in CS.STAGE.stages:
223
+ for existing_group in stage.act_load_groups:
224
+ if existing_group["name"] == group:
225
+ raise ValueError(f"Load group '{group}' has already been activated in stage '{stage.NAME}' (ID: {stage.ID})")
226
+
227
+ day = l_day[i] if i < len(l_day) else "FIRST"
228
+ self.act_load_groups.append({"name": group, "day": day})
229
+ else:
230
+ # Deactivation: Check if activated in previous stages
231
+ activated = False
232
+ for stage in CS.STAGE.stages:
233
+ for existing_group in stage.act_load_groups:
234
+ if existing_group["name"] == group:
235
+ activated = True
236
+ break
237
+ if activated:
238
+ break
239
+
240
+ if not activated:
241
+ raise ValueError(f"Load group '{group}' cannot be deactivated as it has not been activated in any previous stage")
242
+
243
+ day = l_day[i] if i < len(l_day) else "FIRST"
244
+ self.deact_load_groups.append({"name": group, "day": day})
245
+
246
+ CS.STAGE.stages.append(self)
247
+
248
+ @classmethod
249
+ def json(cls):
250
+ """
251
+ Converts Construction Stage data to JSON format
252
+ Example:
253
+ # Get the JSON data for all construction stages
254
+ json_data = CS.json()
255
+ print(json_data)
256
+ """
257
+ json = {"Assign": {}}
258
+
259
+ for csa in cls.stages:
260
+ stage_data = {
261
+ "NAME": csa.NAME,
262
+ "DURATION": csa.DURATION,
263
+ "bSV_RSLT": csa.SV_Result,
264
+ "bSV_STEP": csa.SV_Step,
265
+ "bLOAD_STEP": csa.Load_IN,
266
+ "NO" : csa.NO
267
+ }
268
+
269
+ # Add incremental steps if load step is enabled
270
+ if csa.Load_IN:
271
+ stage_data["INCRE_STEP"] = csa.NL
272
+
273
+ # Add additional steps if specified
274
+ if csa.addstp:
275
+ stage_data["ADD_STEP"] = csa.addstp
276
+ else:
277
+ stage_data["ADD_STEP"] = []
278
+
279
+ # Handle structure group activation
280
+ if csa.act_structure_groups:
281
+ stage_data["ACT_ELEM"] = []
282
+ for group in csa.act_structure_groups:
283
+ stage_data["ACT_ELEM"].append({
284
+ "GRUP_NAME": group["name"],
285
+ "AGE": group["age"]
286
+ })
287
+
288
+ # Handle structure group deactivation
289
+ if csa.deact_structure_groups:
290
+ stage_data["DACT_ELEM"] = []
291
+ for group in csa.deact_structure_groups:
292
+ stage_data["DACT_ELEM"].append({
293
+ "GRUP_NAME": group["name"],
294
+ "REDIST": group["redist"]
295
+ })
296
+
297
+ # Handle boundary group activation
298
+ if csa.act_boundary_groups:
299
+ stage_data["ACT_BNGR"] = []
300
+ for group in csa.act_boundary_groups:
301
+ stage_data["ACT_BNGR"].append({
302
+ "BNGR_NAME": group["name"],
303
+ "POS": group["pos"]
304
+ })
305
+
306
+ # Handle boundary group deactivation
307
+ if csa.deact_boundary_groups:
308
+ stage_data["DACT_BNGR"] = []
309
+ for group_name in csa.deact_boundary_groups:
310
+ stage_data["DACT_BNGR"].append(group_name)
311
+
312
+ # Handle load group activation
313
+ if csa.act_load_groups:
314
+ stage_data["ACT_LOAD"] = []
315
+ for group in csa.act_load_groups:
316
+ stage_data["ACT_LOAD"].append({
317
+ "LOAD_NAME": group["name"],
318
+ "DAY": group["day"]
319
+ })
320
+
321
+ # Handle load group deactivation
322
+ if csa.deact_load_groups:
323
+ stage_data["DACT_LOAD"] = []
324
+ for group in csa.deact_load_groups:
325
+ stage_data["DACT_LOAD"].append({
326
+ "LOAD_NAME": group["name"],
327
+ "DAY": group["day"]
328
+ })
329
+
330
+ json["Assign"][str(csa.ID)] = stage_data
331
+
332
+ return json
333
+
334
+ @classmethod
335
+ def create(cls):
336
+ """Creates construction stages in the database"""
337
+ if CS.STAGE._isSync_:
338
+ MidasAPI("DELETE", "/db/stag")
339
+ MidasAPI("PUT", "/db/stag", cls.json())
340
+
341
+ @classmethod
342
+ def get(cls):
343
+ """Gets construction stage data from the database"""
344
+ return MidasAPI("GET", "/db/stag")
345
+
346
+ @classmethod
347
+ def sync(cls):
348
+ """Updates the CS class with data from the database"""
349
+ cls.stages = []
350
+ a = cls.get()
351
+ if a != {'message': ''}:
352
+ if "STAG" in a:
353
+ stag_data_dict = a["STAG"]
354
+ else:
355
+ return
356
+
357
+ for stag_id, stag_data in stag_data_dict.items():
358
+ # Basic stage data
359
+ name = stag_data.get("NAME")
360
+ duration = stag_data.get("DURATION")
361
+ sv_result = stag_data.get("bSV_RSLT")
362
+ sv_step = stag_data.get("bSV_STEP")
363
+ load_in = stag_data.get("bLOAD_STEP")
364
+ nl = stag_data.get("INCRE_STEP")
365
+ addstp = stag_data.get("ADD_STEP")
366
+ stagNo = stag_data.get("NO")
367
+
368
+ # Create a new CS object with basic properties
369
+ new_cs = CS.STAGE(
370
+ name=name,
371
+ duration=duration,
372
+ id=int(stagNo),
373
+ sv_result=sv_result,
374
+ sv_step=sv_step,
375
+ load_in=load_in,
376
+ nl=nl,
377
+ addstp=addstp
378
+ )
379
+ new_cs.NO = stagNo
380
+ CS.STAGE.stages.pop()
381
+
382
+ # Process activation elements
383
+ if "ACT_ELEM" in stag_data and stag_data["ACT_ELEM"]:
384
+ for elem in stag_data["ACT_ELEM"]:
385
+ group_name = elem.get("GRUP_NAME")
386
+ age = elem.get("AGE")
387
+ new_cs.act_structure_groups.append({"name": group_name, "age": age})
388
+
389
+ # Process deactivation elements
390
+ if "DACT_ELEM" in stag_data and stag_data["DACT_ELEM"]:
391
+ for elem in stag_data["DACT_ELEM"]:
392
+ if isinstance(elem, dict):
393
+ group_name = elem.get("GRUP_NAME")
394
+ redist = elem.get("REDIST")
395
+ else:
396
+ group_name = elem
397
+ redist = 0
398
+ new_cs.deact_structure_groups.append({"name": group_name, "redist": redist})
399
+
400
+ # Process activation boundary groups
401
+ if "ACT_BNGR" in stag_data and stag_data["ACT_BNGR"]:
402
+ for bngr in stag_data["ACT_BNGR"]:
403
+ group_name = bngr.get("BNGR_NAME")
404
+ pos = bngr.get("POS")
405
+ new_cs.act_boundary_groups.append({"name": group_name, "pos": pos})
406
+
407
+ # Process deactivation boundary groups
408
+ if "DACT_BNGR" in stag_data and stag_data["DACT_BNGR"]:
409
+ for bngr in stag_data["DACT_BNGR"]:
410
+ new_cs.deact_boundary_groups.append(bngr)
411
+
412
+ # Process activation loads
413
+ if "ACT_LOAD" in stag_data and stag_data["ACT_LOAD"]:
414
+ for load in stag_data["ACT_LOAD"]:
415
+ group_name = load.get("LOAD_NAME")
416
+ day = load.get("DAY")
417
+ new_cs.act_load_groups.append({"name": group_name, "day": day})
418
+
419
+ # Process deactivation loads
420
+ if "DACT_LOAD" in stag_data and stag_data["DACT_LOAD"]:
421
+ for load in stag_data["DACT_LOAD"]:
422
+ if isinstance(load, dict):
423
+ group_name = load.get("LOAD_NAME")
424
+ day = load.get("DAY")
425
+ else:
426
+ group_name = load
427
+ day = "FIRST"
428
+ new_cs.deact_load_groups.append({"name": group_name, "day": day})
429
+
430
+ CS.STAGE.stages.append(new_cs)
431
+
432
+ sorted_stgs = sorted(CS.STAGE.stages,key=lambda x : x.NO)
433
+ CS.STAGE.stages = sorted_stgs
434
+ CS.STAGE._isSync_ = True
435
+
436
+ @classmethod
437
+ def delete(cls):
438
+ """Deletes all construction stages from the database and resets the class"""
439
+ cls.stages = []
440
+ return MidasAPI("DELETE", "/db/stag")
441
+
442
+ #-----------------------------------------------------------Comp Section for CS--------------------------------------------------------------
443
+
444
+ class CompSec:
445
+ compsecs = []
446
+
447
+ def __init__(self,
448
+ activation_stage: str,
449
+ section_id: int,
450
+ comp_type: str = "GENERAL",
451
+ tapered_type: bool = False,
452
+ partinfo: list = None,
453
+ id: int = None):
454
+ """
455
+ Parameters:
456
+ activation_stage: Active Stage name (required)
457
+ section_id: Section ID (required)
458
+ comp_type: Composite Type - "GENERAL" or "USER" (default "GENERAL")
459
+ tapered_type: Tapered Type - True or False (default False)
460
+ partinfo: List of part information lists (required)
461
+ id: The composite section ID (optional)
462
+
463
+ Part Info Format:
464
+ Each part should be a list with elements in order:
465
+ [part_number, material_type, material_id, composite_stage, age,
466
+ height, volume_surface_ratio, module_exposed_surface, area,
467
+ asy, asz, ixx, iyy, izz, warea, iw]
468
+
469
+ - part_number: Integer (required)
470
+ - material_type: "ELEM" or "MATL" (required)
471
+ - material_id: String (optional, blank for ELEM)
472
+ - composite_stage: String (optional, blank for active stage)
473
+ - age: Number (default 0)
474
+ - height: Number (default AUTO)
475
+ - volume_surface_ratio: Number (default 0)
476
+ - module_exposed_surface: Number (default 0)
477
+ - area: Number (default 1)
478
+ - asy: Number (default 1)
479
+ - asz: Number (default 1)
480
+ - ixx: Number (default 1)
481
+ - iyy: Number (default 1)
482
+ - izz: Number (default 1)
483
+ - warea: Number (default 1)
484
+ - iw: Number (default 1)
485
+
486
+ Examples:
487
+ ```python
488
+ # Basic composite section
489
+ CompSec("CS1", 1, "GENERAL", False, [
490
+ [1, "ELEM", "", "", 2, 1.5, 1.5, 1, 1, 1, 1, 1, 1, 1, 1, 1],
491
+ [2, "MATL", "3", "CS2", 5, 0.245, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1]
492
+ ])
493
+
494
+ # With minimal part info (using defaults)
495
+ CompSec("CS1", 2, "GENERAL", False, [
496
+ [1, "ELEM"],
497
+ [2, "MATL", "2","CS2"]
498
+ ])
499
+ ```
500
+ """
501
+
502
+ self.ASTAGE = activation_stage
503
+ self.SEC = section_id
504
+ self.TYPE = comp_type
505
+ self.bTAP = tapered_type
506
+
507
+ # Set ID
508
+ if id is None:
509
+ self.ID = len(CS.CompSec.compsecs) + 1
510
+ else:
511
+ self.ID = id
512
+
513
+ # Process part information
514
+ self.vPARTINFO = []
515
+
516
+ if partinfo is None:
517
+ raise ValueError("Part information is required")
518
+
519
+ if not isinstance(partinfo, list):
520
+ raise ValueError("Part information must be a list of lists")
521
+
522
+ for part_data in partinfo:
523
+ if not isinstance(part_data, list) or len(part_data) < 2:
524
+ raise ValueError("Each part must be a list with at least part number and material type")
525
+
526
+ # Default values for part info
527
+ defaults = [
528
+ None, # PART (required)
529
+ None, # MTYPE (required)
530
+ "", # MAT
531
+ "", # CSTAGE
532
+ 0, # AGE
533
+ "AUTO", # PARTINFO_H
534
+ 0, # PARTINFO_VS
535
+ 0, # PARTINFO_M
536
+ 1, # AREA
537
+ 1, # ASY
538
+ 1, # ASZ
539
+ 1, # IXX
540
+ 1, # IYY
541
+ 1, # IZZ
542
+ 1, # WAREA
543
+ 1 # IW
544
+ ]
545
+
546
+ # Fill in provided values
547
+ for i, value in enumerate(part_data):
548
+ if i < len(defaults):
549
+ defaults[i] = value
550
+
551
+ # Validate required fields
552
+ if defaults[0] is None:
553
+ raise ValueError("Part number is required")
554
+ if defaults[1] is None:
555
+ raise ValueError("Material type is required")
556
+ if defaults[1] not in ["ELEM", "MATL"]:
557
+ raise ValueError("Material type must be 'ELEM' or 'MATL'")
558
+
559
+ # Create part info dictionary
560
+ part_info = {
561
+ "PART": defaults[0],
562
+ "MTYPE": defaults[1],
563
+ "MAT": defaults[2],
564
+ "CSTAGE": defaults[3],
565
+ "AGE": defaults[4],
566
+ "PARTINFO_H": defaults[5],
567
+ "PARTINFO_VS": defaults[6],
568
+ "PARTINFO_M": defaults[7],
569
+ "AREA": defaults[8],
570
+ "ASY": defaults[9],
571
+ "ASZ": defaults[10],
572
+ "IXX": defaults[11],
573
+ "IYY": defaults[12],
574
+ "IZZ": defaults[13],
575
+ "WAREA": defaults[14],
576
+ "IW": defaults[15]
577
+ }
578
+
579
+ self.vPARTINFO.append(part_info)
580
+
581
+ CS.CompSec.compsecs.append(self)
582
+
583
+ @classmethod
584
+ def json(cls):
585
+ """
586
+ Converts Composite Section data to JSON format
587
+ Example:
588
+ # Get the JSON data for all composite sections
589
+ json_data = CS.CompSec.json()
590
+ print(json_data)
591
+ """
592
+ json_data = {"Assign": {}}
593
+
594
+ for compsec in cls.compsecs:
595
+ section_data = {
596
+ "SEC": compsec.SEC,
597
+ "ASTAGE": compsec.ASTAGE,
598
+ "TYPE": compsec.TYPE,
599
+ "bTAP": compsec.bTAP,
600
+ "vPARTINFO": compsec.vPARTINFO
601
+ }
602
+
603
+ json_data["Assign"][str(compsec.ID)] = section_data
604
+
605
+ return json_data
606
+
607
+ @classmethod
608
+ def create(cls):
609
+ """Creates composite sections in the database"""
610
+ return MidasAPI("PUT", "/db/cscs", cls.json())
611
+
612
+ @classmethod
613
+ def get(cls):
614
+ """Gets composite section data from the database"""
615
+ return MidasAPI("GET", "/db/cscs")
616
+
617
+ @classmethod
618
+ def sync(cls):
619
+ """Updates the CompSec class with data from the database"""
620
+ cls.compsecs = []
621
+ response = cls.get()
622
+
623
+ if response != {'message': ''}:
624
+ if "CSCS" in response:
625
+ cscs_data_dict = response["CSCS"]
626
+ else:
627
+ return
628
+
629
+ for cscs_id, cscs_data in cscs_data_dict.items():
630
+ # Basic section data
631
+ astage = cscs_data.get("ASTAGE")
632
+ sec = cscs_data.get("SEC")
633
+ comp_type = cscs_data.get("TYPE", "GENERAL")
634
+ tapered_type = cscs_data.get("bTAP", False)
635
+ partinfo_data = cscs_data.get("vPARTINFO", [])
636
+
637
+ # Convert partinfo from dict format to list format
638
+ partinfo = []
639
+ for part in partinfo_data:
640
+ part_list = [
641
+ part.get("PART"),
642
+ part.get("MTYPE"),
643
+ part.get("MAT", ""),
644
+ part.get("CSTAGE", ""),
645
+ part.get("AGE", 0),
646
+ part.get("PARTINFO_H", "AUTO"),
647
+ part.get("PARTINFO_VS", 0),
648
+ part.get("PARTINFO_M", 0),
649
+ part.get("AREA", 1),
650
+ part.get("ASY", 1),
651
+ part.get("ASZ", 1),
652
+ part.get("IXX", 1),
653
+ part.get("IYY", 1),
654
+ part.get("IZZ", 1),
655
+ part.get("WAREA", 1),
656
+ part.get("IW", 1)
657
+ ]
658
+ partinfo.append(part_list)
659
+
660
+ # Create a new CompSec object
661
+ new_compsec = CS.CompSec(
662
+ activation_stage=astage,
663
+ section_id=sec,
664
+ comp_type=comp_type,
665
+ tapered_type=tapered_type,
666
+ partinfo=partinfo,
667
+ id=int(cscs_id)
668
+ )
669
+
670
+ # Remove the automatically added instance and replace with synced data
671
+ CS.CompSec.compsecs.pop()
672
+ CS.CompSec.compsecs.append(new_compsec)
673
+
674
+ @classmethod
675
+ def delete(cls):
676
+ """Deletes all composite sections from the database and resets the class"""
677
+ cls.compsecs = []
678
+ return MidasAPI("DELETE", "/db/cscs")
679
+
680
+
681
+ #-----------------------------------------------------------------------------------------------------------------------------------
682
+
683
+ class TimeLoad:
684
+ timeloads = []
685
+
686
+ def __init__(self,
687
+ element_id: int,
688
+ day: int,
689
+ group: str = "",
690
+ id: int = None):
691
+ """
692
+ Time Loads for Construction Stage define.
693
+
694
+ Parameters:
695
+ element_id: Element ID (required)
696
+ day: Time Loads in days (required)
697
+ group: Load Group Name (optional, default blank)
698
+ id: The time loads ID (optional)
699
+
700
+ Examples:
701
+ ```python
702
+ CS.TimeLoad(10, 35, "DL")
703
+ ```
704
+ """
705
+
706
+ self.ELEMENT_ID = element_id
707
+ self.DAY = day
708
+ self.GROUP_NAME = group
709
+
710
+ # Set ID
711
+ if id is None:
712
+ self.ID = len(CS.TimeLoad.timeloads) + 1
713
+ else:
714
+ self.ID = id
715
+
716
+ CS.TimeLoad.timeloads.append(self)
717
+
718
+ @classmethod
719
+ def json(cls):
720
+ """
721
+ Converts Time Loads data to JSON format
722
+ Example:
723
+ # Get the JSON data for all time loads
724
+ json_data = CS.TimeLoad.json()
725
+ print(json_data)
726
+ """
727
+ json_data = {"Assign": {}}
728
+
729
+ for timeload in cls.timeloads:
730
+ items_data = {
731
+ "ITEMS": [
732
+ {
733
+ "ID": 1,
734
+ "GROUP_NAME": timeload.GROUP_NAME,
735
+ "DAY": timeload.DAY
736
+ }
737
+ ]
738
+ }
739
+
740
+ json_data["Assign"][str(timeload.ELEMENT_ID)] = items_data
741
+
742
+ return json_data
743
+
744
+ @classmethod
745
+ def create(cls):
746
+ """Creates time loads in the CIVIL NX"""
747
+ return MidasAPI("PUT", "/db/tmld", cls.json())
748
+
749
+ @classmethod
750
+ def get(cls):
751
+ """Gets time loads data from the CIVIL NX"""
752
+ return MidasAPI("GET", "/db/tmld")
753
+
754
+ @classmethod
755
+ def sync(cls):
756
+ """Updates the TimeLoad class with data from the CIVIL NX"""
757
+ cls.timeloads = []
758
+ response = cls.get()
759
+
760
+ if response != {'message': ''}:
761
+ if "TMLD" in response:
762
+ stbk_data_dict = response["TMLD"]
763
+ else:
764
+ return
765
+
766
+ for element_id, stbk_data in stbk_data_dict.items():
767
+ items = stbk_data.get("ITEMS", [])
768
+
769
+ for item in items:
770
+ group_name = item.get("GROUP_NAME", "")
771
+ day = item.get("DAY", 0)
772
+ item_id = item.get("ID", 1)
773
+
774
+ # Create a new TimeLoad object
775
+ new_timeload = CS.TimeLoad(
776
+ element_id=int(element_id),
777
+ day=day,
778
+ group=group_name,
779
+ id=item_id
780
+ )
781
+
782
+ # Remove the automatically added instance and replace with synced data
783
+ CS.TimeLoad.timeloads.pop()
784
+ CS.TimeLoad.timeloads.append(new_timeload)
785
+
786
+ @classmethod
787
+ def delete(cls):
788
+ """Deletes all time loads from the CIVIL NX and python class"""
789
+ cls.timeloads = []
790
+ return MidasAPI("DELETE", "/db/tmld")
791
+
792
+ class CreepCoeff:
793
+ creepcoeffs = []
794
+
795
+ def __init__(self,
796
+ element_id: int,
797
+ creep: float,
798
+ group: str = "",
799
+ id: int = None):
800
+ """
801
+ Creep Coefficient for Construction Stage define.
802
+
803
+ Parameters:
804
+ element_id: Element ID (required)
805
+ creep: Creep Coefficient value (required)
806
+ group: Load Group Name (optional, default blank)
807
+ id: The creep coefficient ID (optional)
808
+
809
+ Examples:
810
+ ```python
811
+ # Basic creep coefficient
812
+ CS.CreepCoeff(25, 1.2)
813
+
814
+ # With specific ID & Group
815
+ CS.CreepCoeff(26, 1.5, "GR", id=2)
816
+ ```
817
+ """
818
+
819
+ self.ELEMENT_ID = element_id
820
+ self.CREEP = creep
821
+ self.GROUP_NAME = group
822
+
823
+ # Set ID
824
+ if id is None:
825
+ self.ID = len(CS.CreepCoeff.creepcoeffs) + 1
826
+ else:
827
+ self.ID = id
828
+
829
+ CS.CreepCoeff.creepcoeffs.append(self)
830
+
831
+ @classmethod
832
+ def json(cls):
833
+ """
834
+ Converts Creep Coefficient data to JSON format
835
+ Example:
836
+ # Get the JSON data for all creep coefficients
837
+ json_data = CS.CreepCoeff.json()
838
+ print(json_data)
839
+ """
840
+ json_data = {"Assign": {}}
841
+
842
+ for creepcoeff in cls.creepcoeffs:
843
+ items_data = {
844
+ "ITEMS": [
845
+ {
846
+ "ID": 1,
847
+ "GROUP_NAME": creepcoeff.GROUP_NAME,
848
+ "CREEP": creepcoeff.CREEP
849
+ }
850
+ ]
851
+ }
852
+
853
+ json_data["Assign"][str(creepcoeff.ELEMENT_ID)] = items_data
854
+
855
+ return json_data
856
+
857
+ @classmethod
858
+ def create(cls):
859
+ """Creates creep coefficients in the database"""
860
+ return MidasAPI("PUT", "/db/crpc", cls.json())
861
+
862
+ @classmethod
863
+ def get(cls):
864
+ """Gets creep coefficient data from the database"""
865
+ return MidasAPI("GET", "/db/crpc")
866
+
867
+ @classmethod
868
+ def sync(cls):
869
+ """Updates the CreepCoeff class with data from the database"""
870
+ cls.creepcoeffs = []
871
+ response = cls.get()
872
+
873
+ if response != {'message': ''}:
874
+ if "CRPC" in response:
875
+ crpc_data_dict = response["CRPC"]
876
+ else:
877
+ return
878
+
879
+ for element_id, crpc_data in crpc_data_dict.items():
880
+ items = crpc_data.get("ITEMS", [])
881
+
882
+ for item in items:
883
+ group_name = item.get("GROUP_NAME", "")
884
+ creep = item.get("CREEP", 0.0)
885
+ item_id = item.get("ID", 1)
886
+
887
+ # Create a new CreepCoeff object
888
+ new_creepcoeff = CS.CreepCoeff(
889
+ element_id=int(element_id),
890
+ creep=creep,
891
+ group=group_name,
892
+ id=item_id
893
+ )
894
+
895
+ # Remove the automatically added instance and replace with synced data
896
+ CS.CreepCoeff.creepcoeffs.pop()
897
+ CS.CreepCoeff.creepcoeffs.append(new_creepcoeff)
898
+
899
+ @classmethod
900
+ def delete(cls):
901
+ """Deletes all creep coefficients from the database and resets the class"""
902
+ cls.creepcoeffs = []
903
+ return MidasAPI("DELETE", "/db/crpc")
904
+
905
+ class Camber:
906
+ cambers = []
907
+
908
+ def __init__(self,
909
+ node_id: int,
910
+ camber: float,
911
+ deform: float,
912
+ id: int = None):
913
+ """
914
+ Camber for Construction Stage define.
915
+
916
+ Parameters:
917
+ node_id: Node ID (required)
918
+ camber: User camber value (required)
919
+ deform: Deformation value (required)
920
+ id: The camber ID (optional)
921
+
922
+ Examples:
923
+ ```python
924
+
925
+ CS.Camber(25, 0.17, 0.1)
926
+ ```
927
+ """
928
+
929
+ self.NODE_ID = node_id
930
+ self.USER = camber
931
+ self.DEFORM = deform
932
+
933
+ # Set ID
934
+ if id is None:
935
+ self.ID = len(CS.Camber.cambers) + 1
936
+ else:
937
+ self.ID = id
938
+
939
+ CS.Camber.cambers.append(self)
940
+
941
+ @classmethod
942
+ def json(cls):
943
+ """
944
+ Converts Camber data to JSON format
945
+ Example:
946
+ # Get the JSON data for all cambers
947
+ json_data = CS.Camber.json()
948
+ print(json_data)
949
+ """
950
+ json_data = {"Assign": {}}
951
+
952
+ for camber in cls.cambers:
953
+ camber_data = {
954
+ "DEFORM": camber.DEFORM,
955
+ "USER": camber.USER
956
+ }
957
+
958
+ json_data["Assign"][str(camber.NODE_ID)] = camber_data
959
+
960
+ return json_data
961
+
962
+ @classmethod
963
+ def create(cls):
964
+ """Creates cambers in the database"""
965
+ return MidasAPI("PUT", "/db/cmcs", cls.json())
966
+
967
+ @classmethod
968
+ def get(cls):
969
+ """Gets camber data from the database"""
970
+ return MidasAPI("GET", "/db/cmcs")
971
+
972
+ @classmethod
973
+ def sync(cls):
974
+ """Updates the Camber class with data from the database"""
975
+ cls.cambers = []
976
+ response = cls.get()
977
+
978
+ if response != {'message': ''}:
979
+ if "CMCS" in response:
980
+ cmcs_data_dict = response["CMCS"]
981
+ else:
982
+ return
983
+
984
+ for node_id, cmcs_data in cmcs_data_dict.items():
985
+ deform = cmcs_data.get("DEFORM", 0.0)
986
+ user = cmcs_data.get("USER", 0.0)
987
+
988
+ # Create a new Camber object
989
+ new_camber = CS.Camber(
990
+ node_id=int(node_id),
991
+ camber=user,
992
+ deform=deform,
993
+ id=len(cls.cambers) + 1
994
+ )
995
+
996
+ # Remove the automatically added instance and replace with synced data
997
+ CS.Camber.cambers.pop()
998
+ CS.Camber.cambers.append(new_camber)
999
+
1000
+ @classmethod
1001
+ def delete(cls):
1002
+ """Deletes all cambers from the database and resets the class"""
1003
+ cls.cambers = []
1004
+ return MidasAPI("DELETE", "/db/cmcs")