midas-civil 0.1.3__py3-none-any.whl → 0.1.5__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 +3 -0
- midas_civil/_element.py +7 -7
- midas_civil/_group.py +20 -2
- midas_civil/_mapi.py +18 -5
- midas_civil/_model.py +3 -0
- midas_civil/_movingload.py +1431 -0
- midas_civil/_node.py +10 -6
- midas_civil/_result.py +2 -2
- midas_civil/_result_extract.py +17 -9
- midas_civil/_settlement.py +160 -0
- midas_civil/_temperature.py +262 -1
- midas_civil/_tendon.py +820 -56
- midas_civil/_thickness.py +1 -1
- {midas_civil-0.1.3.dist-info → midas_civil-0.1.5.dist-info}/METADATA +1 -1
- midas_civil-0.1.5.dist-info/RECORD +27 -0
- midas_civil-0.1.3.dist-info/RECORD +0 -25
- {midas_civil-0.1.3.dist-info → midas_civil-0.1.5.dist-info}/WHEEL +0 -0
- {midas_civil-0.1.3.dist-info → midas_civil-0.1.5.dist-info}/licenses/LICENSE +0 -0
- {midas_civil-0.1.3.dist-info → midas_civil-0.1.5.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,1431 @@
|
|
|
1
|
+
|
|
2
|
+
from ._mapi import *
|
|
3
|
+
from ._model import *
|
|
4
|
+
|
|
5
|
+
# ----------------------------------------------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
def El_list(Start_id: int, End_id: int) -> list:
|
|
8
|
+
|
|
9
|
+
return list(range(Start_id, End_id + 1))
|
|
10
|
+
|
|
11
|
+
# --------------------------------------------------------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
class MovingLoad:
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
def create(cls):
|
|
18
|
+
|
|
19
|
+
if cls.LineLane.lanes:
|
|
20
|
+
cls.LineLane.create()
|
|
21
|
+
|
|
22
|
+
if cls.Vehicle.vehicles:
|
|
23
|
+
cls.Vehicle.create()
|
|
24
|
+
|
|
25
|
+
if cls.Case.cases:
|
|
26
|
+
cls.Case.create()
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def delete(cls):
|
|
30
|
+
cls.Code.delete()
|
|
31
|
+
|
|
32
|
+
@classmethod
|
|
33
|
+
def sync(cls):
|
|
34
|
+
|
|
35
|
+
cls.LineLane.sync()
|
|
36
|
+
cls.Vehicle.sync()
|
|
37
|
+
cls.Case.sync()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class Code:
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def __init__(self, code_name: str):
|
|
44
|
+
"""
|
|
45
|
+
code_name (str): The name of the moving load code to be used.
|
|
46
|
+
|
|
47
|
+
Available Moving Load Codes:
|
|
48
|
+
- "KSCE-LSD15", "KOREA", "AASHTO STANDARD", "AASHTO LRFD",
|
|
49
|
+
- "AASHTO LRFD(PENNDOT)", "CHINA", "INDIA", "TAIWAN", "CANADA",
|
|
50
|
+
- "BS", "EUROCODE", "AUSTRALIA", "POLAND", "RUSSIA",
|
|
51
|
+
- "SOUTH AFRICA"
|
|
52
|
+
"""
|
|
53
|
+
valid_codes = {
|
|
54
|
+
"KSCE-LSD15", "KOREA", "AASHTO STANDARD", "AASHTO LRFD", "AASHTO LRFD(PENDOT)",
|
|
55
|
+
"CHINA", "INDIA", "TAIWAN", "CANADA", "BS", "EUROCODE", "AUSTRALIA",
|
|
56
|
+
"POLAND", "RUSSIA", "SOUTH AFRICA"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if code_name not in valid_codes:
|
|
60
|
+
raise ValueError(f"Invalid code_name. Choose from: {', '.join(valid_codes)}")
|
|
61
|
+
|
|
62
|
+
self.code_name = code_name
|
|
63
|
+
json_data = {
|
|
64
|
+
"Assign": {
|
|
65
|
+
"1": {
|
|
66
|
+
"CODE": code_name
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
MidasAPI("PUT", "/db/mvcd", json_data)
|
|
71
|
+
|
|
72
|
+
@classmethod
|
|
73
|
+
def get(cls):
|
|
74
|
+
"""Gets the currently set moving load code from the Midas model."""
|
|
75
|
+
return MidasAPI("GET", "/db/mvcd")
|
|
76
|
+
|
|
77
|
+
@classmethod
|
|
78
|
+
def delete(cls):
|
|
79
|
+
return MidasAPI("DELETE", "/db/mvcd")
|
|
80
|
+
|
|
81
|
+
#-------------------------------------------------------------------------------------------------------------------------------------
|
|
82
|
+
class LineLane:
|
|
83
|
+
|
|
84
|
+
lanes = []
|
|
85
|
+
|
|
86
|
+
def __init__(
|
|
87
|
+
self,
|
|
88
|
+
code: str,
|
|
89
|
+
Lane_name: str,
|
|
90
|
+
Ecc: float,
|
|
91
|
+
Wheel_space: float,
|
|
92
|
+
Elment_start: int,
|
|
93
|
+
Elemnt_end: int,
|
|
94
|
+
IF: float = 0,
|
|
95
|
+
Span: float = 0,
|
|
96
|
+
id: int = None,
|
|
97
|
+
width: float = 0,
|
|
98
|
+
opt_width: float = 0,
|
|
99
|
+
Group_Name: str = "",
|
|
100
|
+
Moving_Direction: str = "BOTH",
|
|
101
|
+
Skew_start: float = 0,
|
|
102
|
+
Skew_end: float = 0
|
|
103
|
+
):
|
|
104
|
+
"""
|
|
105
|
+
code (str): Country code for traffic lane standards (e.g., "INDIA", "CHINA").
|
|
106
|
+
Lane_name (str): A unique name for the lane.
|
|
107
|
+
Ecc (float): Lateral eccentricity of the lane's centerline from the reference element path.
|
|
108
|
+
A positive value indicates an offset in the +Y direction of the element's local axis.
|
|
109
|
+
Wheel_space (float): The center-to-center distance between the wheels of the vehicle.
|
|
110
|
+
(e.g., a standard value is often around 1.8m or 6ft).
|
|
111
|
+
Elment_start (int): The first element ID in the continuous path defining the lane.
|
|
112
|
+
Elemnt_end (int): The last element ID in the continuous path defining the lane.
|
|
113
|
+
IF (float, optional): Impact Factor or Scale Factor, as defined by the selected design code. Defaults to 0.(For LRFD code Add Centerifugal force Input)
|
|
114
|
+
Span (float, optional): The span length of the lane, used by some codes for impact factor calculation. Defaults to 0.
|
|
115
|
+
id (int, optional): A unique integer ID for the lane. If None, it will be auto-assigned. Defaults to None.
|
|
116
|
+
width (float, optional): The width of the traffic lane. Key name "WIDTH". Defaults to 0.
|
|
117
|
+
opt_width (float, optional): The allowable width of the traffic lane for auto-positioning. Key name "ALLOW_WIDTH". Defaults to 0.
|
|
118
|
+
Group_Name (str, optional): The group name for cross-beam load distribution. If provided, distribution is "CROSS". Defaults to "".
|
|
119
|
+
Moving_Direction (str, optional): The allowed direction of vehicle movement ("FORWARD", "BACKWARD", "BOTH"). Defaults to "BOTH".
|
|
120
|
+
Skew_start (float, optional): The skew angle of the bridge at the start of the lane (in degrees). Defaults to 0.
|
|
121
|
+
Skew_end (float, optional): The skew angle of the bridge at the end of the lane (in degrees). Defaults to 0.
|
|
122
|
+
"""
|
|
123
|
+
self.code = code
|
|
124
|
+
self.Lane_name = Lane_name
|
|
125
|
+
self.Ecc = Ecc
|
|
126
|
+
self.Wheel_space = Wheel_space
|
|
127
|
+
self.Elment_start = Elment_start
|
|
128
|
+
self.Elemnt_end = Elemnt_end
|
|
129
|
+
self.IF = IF
|
|
130
|
+
self.Span = Span
|
|
131
|
+
self.id = len(MovingLoad.LineLane.lanes) + 1 if id is None else id
|
|
132
|
+
self.width = width
|
|
133
|
+
self.opt_width = opt_width
|
|
134
|
+
self.Group_Name = Group_Name
|
|
135
|
+
self.Moving_Direction = Moving_Direction
|
|
136
|
+
self.Skew_start = Skew_start
|
|
137
|
+
self.Skew_end = Skew_end
|
|
138
|
+
|
|
139
|
+
# Ensure the correct moving load code is active in the model
|
|
140
|
+
MovingLoad.Code(code)
|
|
141
|
+
|
|
142
|
+
# Avoid duplicating lanes if syncing
|
|
143
|
+
if not any(lane.id == self.id for lane in MovingLoad.LineLane.lanes):
|
|
144
|
+
MovingLoad.LineLane.lanes.append(self)
|
|
145
|
+
|
|
146
|
+
# Definition of country-specific subclasses
|
|
147
|
+
class India:
|
|
148
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
149
|
+
Elemnt_end: int, IF: float = 0, Span: float = 0, id: int = None,
|
|
150
|
+
width: float = 0, opt_width: float = 0, Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
151
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
152
|
+
"""Defines a traffic lane according to Indian standards."""
|
|
153
|
+
MovingLoad.LineLane("INDIA", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
154
|
+
IF, Span, id, width, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
155
|
+
|
|
156
|
+
class China:
|
|
157
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
158
|
+
Elemnt_end: int, IF: float = 0, Span: float = 0, id: int = None,
|
|
159
|
+
width: float = 0, opt_width: float = 0, Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
160
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
161
|
+
"""Defines a traffic lane according to Chinese standards."""
|
|
162
|
+
MovingLoad.LineLane("CHINA", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
163
|
+
IF, Span, id, width, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
164
|
+
|
|
165
|
+
class Korea:
|
|
166
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
167
|
+
Elemnt_end: int, IF: float = 0, id: int = None, opt_width: float = 0,
|
|
168
|
+
Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
169
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
170
|
+
"""Defines a traffic lane according to Korean standards."""
|
|
171
|
+
MovingLoad.LineLane("KOREA", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
172
|
+
IF, 0, id, 3, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
173
|
+
|
|
174
|
+
class Taiwan:
|
|
175
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
176
|
+
Elemnt_end: int, IF: float = 0, id: int = None, width: float = 0, opt_width: float = 0,
|
|
177
|
+
Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
178
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
179
|
+
"""Defines a traffic lane according to Taiwanese standards."""
|
|
180
|
+
MovingLoad.LineLane("TAIWAN", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
181
|
+
IF, 0, id, width, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
182
|
+
|
|
183
|
+
class AASHTOStandard:
|
|
184
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
185
|
+
Elemnt_end: int, IF: float = 0, id: int = None, opt_width: float = 0,
|
|
186
|
+
Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
187
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
188
|
+
"""Defines a traffic lane according to AASHTO Standard."""
|
|
189
|
+
MovingLoad.LineLane("AASHTO STANDARD", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
190
|
+
IF, 0, id, 3, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
191
|
+
|
|
192
|
+
class AASHTOLRFD:
|
|
193
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
194
|
+
Elemnt_end: int, IF: float = 0, id: int = None, opt_width: float = 0,
|
|
195
|
+
Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
196
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
197
|
+
"""Defines a traffic lane according to AASHTO LRFD."""
|
|
198
|
+
MovingLoad.LineLane("AASHTO LRFD", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
199
|
+
IF, 0, id, 3, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
200
|
+
|
|
201
|
+
class PENNDOT:
|
|
202
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
203
|
+
Elemnt_end: int, id: int = None, opt_width: float = 0,
|
|
204
|
+
Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
205
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
206
|
+
"""Defines a traffic lane according to AASHTO LRFD (PENNDOT)."""
|
|
207
|
+
MovingLoad.LineLane("AASHTO LRFD(PENDOT)", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
208
|
+
0, 0, id, 3, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
209
|
+
|
|
210
|
+
class Canada:
|
|
211
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
212
|
+
Elemnt_end: int, id: int = None, opt_width: float = 0,
|
|
213
|
+
Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
214
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
215
|
+
"""Defines a traffic lane according to Canadian standards."""
|
|
216
|
+
MovingLoad.LineLane("CANADA", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
217
|
+
0, 0, id, 3, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
218
|
+
|
|
219
|
+
class BS:
|
|
220
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
221
|
+
Elemnt_end: int, id: int = None, width: float = 0, opt_width: float = 0,
|
|
222
|
+
Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
223
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
224
|
+
"""Defines a traffic lane according to British Standards (BS)."""
|
|
225
|
+
MovingLoad.LineLane("BS", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
226
|
+
0, 0, id, width, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
227
|
+
|
|
228
|
+
class Eurocode:
|
|
229
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
230
|
+
Elemnt_end: int, IF: float = 0, id: int = None, width: float = 0, opt_width: float = 0,
|
|
231
|
+
Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
232
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
233
|
+
"""Defines a traffic lane according to Eurocode."""
|
|
234
|
+
MovingLoad.LineLane("EUROCODE", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
235
|
+
IF, 0, id, width, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
236
|
+
|
|
237
|
+
class Australia:
|
|
238
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
239
|
+
Elemnt_end: int, id: int = None, width: float = 0, opt_width: float = 0,
|
|
240
|
+
Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
241
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
242
|
+
"""Defines a traffic lane according to Australian standards."""
|
|
243
|
+
MovingLoad.LineLane("AUSTRALIA", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
244
|
+
0, 0, id, width, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
245
|
+
|
|
246
|
+
class Poland:
|
|
247
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
248
|
+
Elemnt_end: int, id: int = None, width: float = 0, opt_width: float = 0,
|
|
249
|
+
Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
250
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
251
|
+
"""Defines a traffic lane according to Polish standards."""
|
|
252
|
+
MovingLoad.LineLane("POLAND", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
253
|
+
0, 0, id, width, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
254
|
+
|
|
255
|
+
class Russia:
|
|
256
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
257
|
+
Elemnt_end: int, id: int = None, width: float = 0, opt_width: float = 0,
|
|
258
|
+
Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
259
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
260
|
+
"""Defines a traffic lane according to Russian standards."""
|
|
261
|
+
MovingLoad.LineLane("RUSSIA", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
262
|
+
0, 0, id, width, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
263
|
+
|
|
264
|
+
class SouthAfrica:
|
|
265
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
266
|
+
Elemnt_end: int, id: int = None, width: float = 0, opt_width: float = 0,
|
|
267
|
+
Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
268
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
269
|
+
"""Defines a traffic lane according to South African standards."""
|
|
270
|
+
MovingLoad.LineLane("SOUTH AFRICA", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
271
|
+
0, 0, id, width, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
272
|
+
|
|
273
|
+
class KSCELSD15:
|
|
274
|
+
def __init__(self, Lane_name: str, Ecc: float, Wheel_space: float, Elment_start: int,
|
|
275
|
+
Elemnt_end: int, id: int = None, opt_width: float = 0,
|
|
276
|
+
Group_Name: str = "", Moving_Direction: str = "BOTH",
|
|
277
|
+
Skew_start: float = 0, Skew_end: float = 0):
|
|
278
|
+
"""Defines a traffic lane according to KSCE-LSD15."""
|
|
279
|
+
MovingLoad.LineLane("KSCE-LSD15", Lane_name, Ecc, Wheel_space, Elment_start, Elemnt_end,
|
|
280
|
+
0, 0, id, 3, opt_width, Group_Name, Moving_Direction, Skew_start, Skew_end)
|
|
281
|
+
|
|
282
|
+
@staticmethod
|
|
283
|
+
def _get_lane_item_details(code, lane, is_start_span):
|
|
284
|
+
"""
|
|
285
|
+
Internal helper to get code-specific keys for a LANE_ITEM.
|
|
286
|
+
This centralizes the logic for different country standards.
|
|
287
|
+
"""
|
|
288
|
+
details = {}
|
|
289
|
+
if code == "INDIA":
|
|
290
|
+
details = {
|
|
291
|
+
"SPAN": lane.Span,
|
|
292
|
+
"IMPACT_SPAN": 1 if lane.Span > 0 else 0,
|
|
293
|
+
"IMPACT_FACTOR": lane.IF
|
|
294
|
+
}
|
|
295
|
+
elif code == "CHINA":
|
|
296
|
+
details = {
|
|
297
|
+
"SPAN": lane.Span,
|
|
298
|
+
"SPAN_START": is_start_span,
|
|
299
|
+
"SCALE_FACTOR": lane.IF
|
|
300
|
+
}
|
|
301
|
+
elif code in ["KOREA", "TAIWAN", "AASHTO STANDARD"]:
|
|
302
|
+
details = {
|
|
303
|
+
"FACT": lane.IF,
|
|
304
|
+
"SPAN_START": is_start_span
|
|
305
|
+
}
|
|
306
|
+
elif code in ["AASHTO LRFD(PENDOT)", "AUSTRALIA", "POLAND"]:
|
|
307
|
+
details = {
|
|
308
|
+
"SPAN_START": is_start_span
|
|
309
|
+
}
|
|
310
|
+
elif code == "AASHTO LRFD":
|
|
311
|
+
details = {
|
|
312
|
+
"CENT_F": lane.IF,
|
|
313
|
+
"SPAN_START": is_start_span
|
|
314
|
+
}
|
|
315
|
+
elif code == "EUROCODE":
|
|
316
|
+
details = {
|
|
317
|
+
"ECCEN_VERT_LOAD": lane.IF
|
|
318
|
+
}
|
|
319
|
+
# Codes like "KSCE-LSD15", "BS", "CANADA" etc., don't need extra keys
|
|
320
|
+
|
|
321
|
+
return details
|
|
322
|
+
|
|
323
|
+
@classmethod
|
|
324
|
+
def json(cls, lanes_list=None):
|
|
325
|
+
"""
|
|
326
|
+
Generates the JSON
|
|
327
|
+
"""
|
|
328
|
+
if lanes_list is None:
|
|
329
|
+
lanes_list = cls.lanes
|
|
330
|
+
|
|
331
|
+
data = {"Assign": {}}
|
|
332
|
+
for lane in lanes_list:
|
|
333
|
+
E_list = El_list(lane.Elment_start, lane.Elemnt_end)
|
|
334
|
+
Load_Dist = "CROSS" if lane.Group_Name else "LANE"
|
|
335
|
+
opt_auto_lane = lane.width > 0 or lane.opt_width > 0
|
|
336
|
+
|
|
337
|
+
common_data = {
|
|
338
|
+
"LL_NAME": lane.Lane_name,
|
|
339
|
+
"LOAD_DIST": Load_Dist,
|
|
340
|
+
"GROUP_NAME": lane.Group_Name if Load_Dist == "CROSS" else "",
|
|
341
|
+
"SKEW_START": lane.Skew_start,
|
|
342
|
+
"SKEW_END": lane.Skew_end,
|
|
343
|
+
"MOVING": lane.Moving_Direction,
|
|
344
|
+
"WHEEL_SPACE": lane.Wheel_space,
|
|
345
|
+
"WIDTH": lane.width,
|
|
346
|
+
"OPT_AUTO_LANE": opt_auto_lane,
|
|
347
|
+
"ALLOW_WIDTH": lane.opt_width
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
lane_items = []
|
|
351
|
+
for i, e in enumerate(E_list):
|
|
352
|
+
is_start_span = (i == 0)
|
|
353
|
+
# Get code-specific details from the helper function
|
|
354
|
+
item_details = cls._get_lane_item_details(lane.code, lane, is_start_span)
|
|
355
|
+
|
|
356
|
+
# Start with the base item
|
|
357
|
+
lane_item = {"ELEM": e, "ECC": lane.Ecc}
|
|
358
|
+
# Add the code-specific details
|
|
359
|
+
lane_item.update(item_details)
|
|
360
|
+
lane_items.append(lane_item)
|
|
361
|
+
|
|
362
|
+
data["Assign"][str(lane.id)] = {
|
|
363
|
+
"COMMON": common_data,
|
|
364
|
+
"LANE_ITEMS": lane_items
|
|
365
|
+
}
|
|
366
|
+
return data
|
|
367
|
+
|
|
368
|
+
@classmethod
|
|
369
|
+
def create(cls):
|
|
370
|
+
"""Sends all defined traffic lane data to the Midas Civil API """
|
|
371
|
+
if not cls.lanes:
|
|
372
|
+
print("No lanes to create.")
|
|
373
|
+
return
|
|
374
|
+
|
|
375
|
+
# Group lanes by their country code to use the correct API endpoint
|
|
376
|
+
lanes_by_code = {"INDIA": [], "CHINA": [], "OTHER": []}
|
|
377
|
+
for lane in cls.lanes:
|
|
378
|
+
if lane.code == "INDIA":
|
|
379
|
+
lanes_by_code["INDIA"].append(lane)
|
|
380
|
+
elif lane.code == "CHINA":
|
|
381
|
+
lanes_by_code["CHINA"].append(lane)
|
|
382
|
+
else:
|
|
383
|
+
lanes_by_code["OTHER"].append(lane)
|
|
384
|
+
|
|
385
|
+
# Create JSON and send data for each group
|
|
386
|
+
if lanes_by_code["INDIA"]:
|
|
387
|
+
india_data = cls.json(lanes_by_code["INDIA"])
|
|
388
|
+
MidasAPI("PUT", "/db/llanid", india_data)
|
|
389
|
+
|
|
390
|
+
if lanes_by_code["CHINA"]:
|
|
391
|
+
china_data = cls.json(lanes_by_code["CHINA"])
|
|
392
|
+
MidasAPI("PUT", "/db/llanch", china_data)
|
|
393
|
+
|
|
394
|
+
if lanes_by_code["OTHER"]:
|
|
395
|
+
other_data = cls.json(lanes_by_code["OTHER"])
|
|
396
|
+
MidasAPI("PUT", "/db/llan", other_data)
|
|
397
|
+
|
|
398
|
+
@classmethod
|
|
399
|
+
def get(cls):
|
|
400
|
+
"""Retrieves all lane data from the Midas model"""
|
|
401
|
+
all_lanes_data = {"LANE_DATA": {}}
|
|
402
|
+
|
|
403
|
+
endpoints = {
|
|
404
|
+
"/db/llanid": ("INDIA", "LLANID"),
|
|
405
|
+
"/db/llanch": ("CHINA", "LLANCH"),
|
|
406
|
+
"/db/llan": ("OTHER", "LLAN")
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
for endpoint, (code_type, response_key) in endpoints.items():
|
|
410
|
+
api_data = MidasAPI("GET", endpoint)
|
|
411
|
+
if api_data and response_key in api_data:
|
|
412
|
+
for lane_id, lane_details in api_data[response_key].items():
|
|
413
|
+
if 'COMMON' in lane_details:
|
|
414
|
+
lane_details['COMMON']['CODE_TYPE'] = code_type
|
|
415
|
+
all_lanes_data["LANE_DATA"][lane_id] = lane_details
|
|
416
|
+
|
|
417
|
+
return all_lanes_data
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
@classmethod
|
|
421
|
+
def delete(cls):
|
|
422
|
+
"""Deletes all traffic lanes from the Midas model."""
|
|
423
|
+
all_lanes_in_model = cls.get().get("LANE_DATA", {})
|
|
424
|
+
if not all_lanes_in_model:
|
|
425
|
+
print("No lanes found in the model. Nothing to delete.")
|
|
426
|
+
return
|
|
427
|
+
|
|
428
|
+
target_ids = [int(id_str) for id_str in all_lanes_in_model.keys()]
|
|
429
|
+
|
|
430
|
+
if not target_ids:
|
|
431
|
+
print("No target lanes to delete.")
|
|
432
|
+
return
|
|
433
|
+
|
|
434
|
+
ids_to_delete = {"INDIA": [], "CHINA": [], "OTHER": []}
|
|
435
|
+
for lane_id in target_ids:
|
|
436
|
+
lane_id_str = str(lane_id)
|
|
437
|
+
code_type = all_lanes_in_model[lane_id_str].get("COMMON", {}).get("CODE_TYPE", "OTHER")
|
|
438
|
+
ids_to_delete[code_type].append(lane_id)
|
|
439
|
+
|
|
440
|
+
if ids_to_delete["INDIA"]:
|
|
441
|
+
MidasAPI("DELETE", "/db/llanid", {"Remove": ids_to_delete["INDIA"]})
|
|
442
|
+
if ids_to_delete["CHINA"]:
|
|
443
|
+
MidasAPI("DELETE", "/db/llanch", {"Remove": ids_to_delete["CHINA"]})
|
|
444
|
+
if ids_to_delete["OTHER"]:
|
|
445
|
+
MidasAPI("DELETE", "/db/llan", {"Remove": ids_to_delete["OTHER"]})
|
|
446
|
+
|
|
447
|
+
@classmethod
|
|
448
|
+
def sync(cls):
|
|
449
|
+
"""
|
|
450
|
+
Synchronizes the lane data from the Midas model
|
|
451
|
+
"""
|
|
452
|
+
# Clear existing lanes
|
|
453
|
+
cls.lanes = []
|
|
454
|
+
|
|
455
|
+
# Get the current active code from the model
|
|
456
|
+
try:
|
|
457
|
+
code_response = MovingLoad.Code.get()
|
|
458
|
+
if not code_response or 'MVCD' not in code_response:
|
|
459
|
+
print("Warning: No moving load code found in model. Cannot sync lanes.")
|
|
460
|
+
return
|
|
461
|
+
|
|
462
|
+
# Extract the active code name
|
|
463
|
+
current_code = None
|
|
464
|
+
mvcd_data = code_response.get('MVCD', {})
|
|
465
|
+
for code_id, code_info in mvcd_data.items():
|
|
466
|
+
if isinstance(code_info, dict) and 'CODE' in code_info:
|
|
467
|
+
current_code = code_info['CODE']
|
|
468
|
+
break
|
|
469
|
+
|
|
470
|
+
if not current_code:
|
|
471
|
+
print("Warning: Could not determine active moving load code. Cannot sync lanes.")
|
|
472
|
+
return
|
|
473
|
+
|
|
474
|
+
except Exception as e:
|
|
475
|
+
print(f"Error getting current code: {e}")
|
|
476
|
+
return
|
|
477
|
+
|
|
478
|
+
# Get all lane data from the model
|
|
479
|
+
response = cls.get()
|
|
480
|
+
all_lanes_data = response.get("LANE_DATA", {})
|
|
481
|
+
|
|
482
|
+
if not all_lanes_data:
|
|
483
|
+
print("No lane data found in model to sync.")
|
|
484
|
+
return
|
|
485
|
+
|
|
486
|
+
# Process each lane from the model
|
|
487
|
+
for lane_id, lane_data in all_lanes_data.items():
|
|
488
|
+
common = lane_data.get("COMMON", {})
|
|
489
|
+
items = lane_data.get("LANE_ITEMS", [])
|
|
490
|
+
|
|
491
|
+
if not common or not items:
|
|
492
|
+
continue
|
|
493
|
+
|
|
494
|
+
# Extract element list to find start and end
|
|
495
|
+
element_ids = [item['ELEM'] for item in items]
|
|
496
|
+
if not element_ids:
|
|
497
|
+
continue
|
|
498
|
+
el_start = min(element_ids)
|
|
499
|
+
el_end = max(element_ids)
|
|
500
|
+
|
|
501
|
+
# Extract common properties
|
|
502
|
+
lane_name = common.get("LL_NAME", f"Lane_{lane_id}")
|
|
503
|
+
ecc = items[0].get("ECC", 0) if items else 0
|
|
504
|
+
wheel_space = common.get("WHEEL_SPACE", 0)
|
|
505
|
+
width = common.get("WIDTH", 0)
|
|
506
|
+
opt_width = common.get("ALLOW_WIDTH", 0)
|
|
507
|
+
group_name = common.get("GROUP_NAME", "")
|
|
508
|
+
moving_dir = common.get("MOVING", "BOTH")
|
|
509
|
+
skew_start = common.get("SKEW_START", 0)
|
|
510
|
+
skew_end = common.get("SKEW_END", 0)
|
|
511
|
+
|
|
512
|
+
# Extract code-specific parameters based on the current active code
|
|
513
|
+
if_val = 0
|
|
514
|
+
span_val = 0
|
|
515
|
+
|
|
516
|
+
# Use the first item to extract code-specific parameters
|
|
517
|
+
first_item = items[0] if items else {}
|
|
518
|
+
|
|
519
|
+
if current_code == "INDIA":
|
|
520
|
+
if_val = first_item.get("IMPACT_FACTOR", 0)
|
|
521
|
+
span_val = first_item.get("SPAN", 0)
|
|
522
|
+
elif current_code == "CHINA":
|
|
523
|
+
if_val = first_item.get("SCALE_FACTOR", 0)
|
|
524
|
+
span_val = first_item.get("SPAN", 0)
|
|
525
|
+
elif current_code in ["KOREA", "TAIWAN", "AASHTO STANDARD"]:
|
|
526
|
+
if_val = first_item.get("FACT", 0)
|
|
527
|
+
elif current_code == "AASHTO LRFD":
|
|
528
|
+
if_val = first_item.get("CENT_F", 0)
|
|
529
|
+
elif current_code == "EUROCODE":
|
|
530
|
+
if_val = first_item.get("ECCEN_VERT_LOAD", 0)
|
|
531
|
+
# For codes like "KSCE-LSD15", "AASHTO LRFD(PENDOT)", "BS", "CANADA",
|
|
532
|
+
# "AUSTRALIA", "POLAND", "RUSSIA", "SOUTH AFRICA" - they don't have specific IF parameters
|
|
533
|
+
|
|
534
|
+
# Create the LineLane object with the current active code
|
|
535
|
+
try:
|
|
536
|
+
lane_obj = MovingLoad.LineLane(
|
|
537
|
+
code=current_code,
|
|
538
|
+
Lane_name=lane_name,
|
|
539
|
+
Ecc=ecc,
|
|
540
|
+
Wheel_space=wheel_space,
|
|
541
|
+
Elment_start=el_start,
|
|
542
|
+
Elemnt_end=el_end,
|
|
543
|
+
IF=if_val,
|
|
544
|
+
Span=span_val,
|
|
545
|
+
id=int(lane_id),
|
|
546
|
+
width=width,
|
|
547
|
+
opt_width=opt_width,
|
|
548
|
+
Group_Name=group_name,
|
|
549
|
+
Moving_Direction=moving_dir,
|
|
550
|
+
Skew_start=skew_start,
|
|
551
|
+
Skew_end=skew_end
|
|
552
|
+
)
|
|
553
|
+
# print(f"Synced lane '{lane_name}' (ID: {lane_id}) with code '{current_code}'")
|
|
554
|
+
|
|
555
|
+
except Exception as e:
|
|
556
|
+
print(f"Error creating lane {lane_id}: {e}")
|
|
557
|
+
continue
|
|
558
|
+
# ============================================= VEHICLE CLASS =================================================================
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
class Vehicle:
|
|
562
|
+
|
|
563
|
+
vehicles = []
|
|
564
|
+
|
|
565
|
+
# --- Data mapping for Indian (IRS) vehicle codes ---
|
|
566
|
+
_irs_vehicle_map = {
|
|
567
|
+
"BG-1676": {
|
|
568
|
+
"full_name": "Broad Gauge-1676mm",
|
|
569
|
+
"vehicles": [
|
|
570
|
+
"Modified B.G. Loading 1987-1", "Modified B.G. Loading 1987-2", "B.G. Standard Loading 1926-M.L.",
|
|
571
|
+
"B.G. Standard Loading 1926-B.L.", "Revised B.G. Loading 1975-WG1+WG1", "Revised B.G. Loading 1975-WAM4A+WAM4A",
|
|
572
|
+
"Revised B.G. Loading 1975-Bo-Bo+Bo-Bo", "Revised B.G. Loading 1975-WAM4A", "Revised B.G. Loading 1975-WAM4A+WAM4",
|
|
573
|
+
"Revised B.G. Loading 1975-WAM4A+WDM2", "25t Loading-2008 Combination 1", "25t Loading-2008 Combination 2",
|
|
574
|
+
"25t Loading-2008 Combination 3", "25t Loading-2008 Combination 4", "25t Loading-2008 Combination 5",
|
|
575
|
+
"DFC Loading Combination 1", "DFC Loading Combination 2", "DFC Loading Combination 3",
|
|
576
|
+
"DFC Loading Combination 4", "DFC Loading Combination 5"
|
|
577
|
+
]
|
|
578
|
+
},
|
|
579
|
+
"MG-1000": {
|
|
580
|
+
"full_name": "Metre Gauge-1000mm",
|
|
581
|
+
"vehicles": ["2 Co-Co Locomotives", "2 Bo-Bo Locomotives", "MGML Loading of 1929", "M.L.", "B.L.", "C."]
|
|
582
|
+
},
|
|
583
|
+
"NG-762": {
|
|
584
|
+
"full_name": "Narrow Gauge-762mm",
|
|
585
|
+
"vehicles": [
|
|
586
|
+
"Class H: B-B or Bo-Bo Type", "Class H: C-C or Co-Co Type", "Class H: Steam (Zf/1)", "Class H: Diesel Electric",
|
|
587
|
+
"Class A: B-B or Bo-Bo Type", "Class A: C-C or Co-Co Type", "Class A: Diesel Mech./Elec.",
|
|
588
|
+
"Class A: Diesel Mech./Elec.(Articulated)", "Class A: DRG No. CSO/C-873", "Class B: B-B or Bo-Bo Type",
|
|
589
|
+
"Class B: Steam Engine (Tank)", "Class B: Steam Engine (Tender)", "Class B: Diesel Electric"
|
|
590
|
+
]
|
|
591
|
+
},
|
|
592
|
+
"HML": {
|
|
593
|
+
"full_name": "Heavy Mineral Loadings",
|
|
594
|
+
"vehicles": [f"Train Formation No.{i}" for i in range(1, 18)]
|
|
595
|
+
},
|
|
596
|
+
"FTB": {
|
|
597
|
+
"full_name": "Footbridge & Footpath",
|
|
598
|
+
"vehicles": ["Footbridge & Footpath"]
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
# --- Default parameter mapping for Indian vehicle codes ---
|
|
603
|
+
_india_defaults_map = {
|
|
604
|
+
"IRC": {
|
|
605
|
+
"Footway": {"VEH_IN": {"FOOTWAY": 4.903325, "FOOTWAY_WIDTH": 3}}
|
|
606
|
+
},
|
|
607
|
+
"IRS": {
|
|
608
|
+
"BG-1676": {
|
|
609
|
+
"Modified B.G. Loading 1987-1": {"VEH_IN": {"TRACTIVE": 490.3325, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
610
|
+
"Modified B.G. Loading 1987-2": {"VEH_IN": {"TRACTIVE": 490.3325, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
611
|
+
"B.G. Standard Loading 1926-M.L.": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
612
|
+
"B.G. Standard Loading 1926-B.L.": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
613
|
+
"Revised B.G. Loading 1975-WG1+WG1": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
614
|
+
"Revised B.G. Loading 1975-WAM4A+WAM4A": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
615
|
+
"Revised B.G. Loading 1975-Bo-Bo+Bo-Bo": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
616
|
+
"Revised B.G. Loading 1975-WAM4A": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
617
|
+
"Revised B.G. Loading 1975-WAM4A+WAM4": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
618
|
+
"Revised B.G. Loading 1975-WAM4A+WDM2": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
619
|
+
"25t Loading-2008 Combination 1": {"VEH_IN": {"TRACTIVE": 617.81895, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
620
|
+
"25t Loading-2008 Combination 2": {"VEH_IN": {"TRACTIVE": 509.9458, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
621
|
+
"25t Loading-2008 Combination 3": {"VEH_IN": {"TRACTIVE": 823.7586, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
622
|
+
"25t Loading-2008 Combination 4": {"VEH_IN": {"TRACTIVE": 490.3325, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
623
|
+
"25t Loading-2008 Combination 5": {"VEH_IN": {"TRACTIVE": 490.3325, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
624
|
+
"DFC Loading Combination 1": {"VEH_IN": {"TRACTIVE": 617.81895, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
625
|
+
"DFC Loading Combination 2": {"VEH_IN": {"TRACTIVE": 509.9458, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
626
|
+
"DFC Loading Combination 3": {"VEH_IN": {"TRACTIVE": 823.7586, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
627
|
+
"DFC Loading Combination 4": {"VEH_IN": {"TRACTIVE": 490.3325, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
628
|
+
"DFC Loading Combination 5": {"VEH_IN": {"TRACTIVE": 490.3325, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
629
|
+
},
|
|
630
|
+
"MG-1000": {
|
|
631
|
+
"2 Co-Co Locomotives": {"VEH_IN": {"TRACTIVE": 313.8128, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
632
|
+
"2 Bo-Bo Locomotives": {"VEH_IN": {"TRACTIVE": 235.3596, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
633
|
+
"MGML Loading of 1929": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
634
|
+
"M.L.": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
635
|
+
"B.L.": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
636
|
+
"C.": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
637
|
+
},
|
|
638
|
+
"NG-762": {
|
|
639
|
+
"Class H: B-B or Bo-Bo Type": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
640
|
+
"Class H: C-C or Co-Co Type": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
641
|
+
"Class H: Steam (Zf/1)": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
642
|
+
"Class H: Diesel Electric": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
643
|
+
"Class A: B-B or Bo-Bo Type": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
644
|
+
"Class A: C-C or Co-Co Type": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
645
|
+
"Class A: Diesel Mech./Elec.": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
646
|
+
"Class A: Diesel Mech./Elec.(Articulated)": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
647
|
+
"Class A: DRG No. CSO/C-873": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
648
|
+
"Class B: B-B or Bo-Bo Type": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
649
|
+
"Class B: Steam Engine (Tank)": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
650
|
+
"Class B: Steam Engine (Tender)": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
651
|
+
"Class B: Diesel Electric": {"VEH_IN": {"TRACTIVE": 0, "BRAKE_LOCO_RATIO": 25, "BRAKE_TRAIN_RATIO": 13.4}},
|
|
652
|
+
},
|
|
653
|
+
"HML": {
|
|
654
|
+
"Train Formation No.1": {"VEH_IN": {"TRACTIVE": 588.399, "BRAKE_LOCO": 245.16625}},
|
|
655
|
+
"Train Formation No.2": {"VEH_IN": {"TRACTIVE": 588.399, "BRAKE_LOCO": 245.16625}},
|
|
656
|
+
"Train Formation No.3": {"VEH_IN": {"TRACTIVE": 588.399, "BRAKE_LOCO": 245.16625}},
|
|
657
|
+
"Train Formation No.4": {"VEH_IN": {"TRACTIVE": 588.399, "BRAKE_LOCO": 245.16625}},
|
|
658
|
+
"Train Formation No.5": {"VEH_IN": {"TRACTIVE": 441.29925, "BRAKE_LOCO": 245.16625}},
|
|
659
|
+
"Train Formation No.6": {"VEH_IN": {"TRACTIVE": 441.29925, "BRAKE_LOCO": 245.16625}},
|
|
660
|
+
"Train Formation No.7": {"VEH_IN": {"TRACTIVE": 441.29925, "BRAKE_LOCO": 245.16625}},
|
|
661
|
+
"Train Formation No.8": {"VEH_IN": {"TRACTIVE": 298.61249, "BRAKE_LOCO": 215.7463}},
|
|
662
|
+
"Train Formation No.9": {"VEH_IN": {"TRACTIVE": 397.169325, "BRAKE_LOCO": 114.737805}},
|
|
663
|
+
"Train Formation No.10": {"VEH_IN": {"TRACTIVE": 397.169325, "BRAKE_LOCO": 114.737805}},
|
|
664
|
+
"Train Formation No.11": {"VEH_IN": {"TRACTIVE": 397.169325, "BRAKE_LOCO": 114.737805}},
|
|
665
|
+
"Train Formation No.12": {"VEH_IN": {"TRACTIVE": 441.29925, "BRAKE_LOCO": 245.16625}},
|
|
666
|
+
"Train Formation No.13": {"VEH_IN": {"TRACTIVE": 441.29925, "BRAKE_LOCO": 245.16625}},
|
|
667
|
+
"Train Formation No.14": {"VEH_IN": {"TRACTIVE": 441.29925, "BRAKE_LOCO": 245.16625}},
|
|
668
|
+
"Train Formation No.15": {"VEH_IN": {"TRACTIVE": 441.29925, "BRAKE_LOCO": 245.16625}},
|
|
669
|
+
"Train Formation No.16": {"VEH_IN": {"TRACTIVE": 441.29925, "BRAKE_LOCO": 245.16625}},
|
|
670
|
+
"Train Formation No.17": {"VEH_IN": {"TRACTIVE": 441.29925, "BRAKE_LOCO": 245.16625}},
|
|
671
|
+
},
|
|
672
|
+
"FTB": {
|
|
673
|
+
"Footbridge & Footpath": {"VEH_IN": {"FOOTWAY_WIDTH": 3, "SPAN_LENGTH": 7.5}}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
# --- Data mapping for Eurocode vehicle codes ---
|
|
679
|
+
_euro_vehicle_map = {
|
|
680
|
+
"RoadBridge": {
|
|
681
|
+
"full_name": "EN 1991-2:2003 - Road Bridge", "sub_type": 19,
|
|
682
|
+
"vehicle_types": [
|
|
683
|
+
{"name": "Load Model 1", "defaults": {"AMP_VALUES": [0.75, 0.4], "TANDEM_ADJUST_VALUES": [1,1,1], "UDL_ADJUST_VALUES": [1,1,1,1]}},
|
|
684
|
+
{"name": "Load Model 2", "defaults": {"ADJUSTMENT": 0.75, "ADJUSTMENT2": 1}},
|
|
685
|
+
{"name": "Load Model 4", "defaults": {"ADJUSTMENT": 0.75}},
|
|
686
|
+
{"name": "Load Model 3", "selectable_vehicles": ["600/150", "900/150", "1200/150/200", "1500/150/200", "1800/150/200", "2400/200", "3000/200", "3600/200"], "defaults": {"LM3_LOADCASE1": True, "LM3_LOADCASE2": False, "DYNAMIC_FACTOR": True, "USER_INPUT": False}},
|
|
687
|
+
{"name": "Load Model 3 (UK NA)", "selectable_vehicles": ["SV 80", "SV 100", "SV 196", "SOV 250", "SOV 350", "SOV 450", "SOV 600"], "defaults": {"DYNAMIC_FACTOR": True, "USER_INPUT": False}}
|
|
688
|
+
]
|
|
689
|
+
},
|
|
690
|
+
"FTB": {
|
|
691
|
+
"full_name": "EN 1991-2:2003 - Footway and FootBridge", "sub_type": 20,
|
|
692
|
+
"vehicle_types": [
|
|
693
|
+
{"name": "Uniform load (Road bridge footway)", "defaults": {"ADJUSTMENT": 0.4, "FOOTWAY": 5}},
|
|
694
|
+
{"name": "Uniform load (Footbridge)", "defaults": {"ADJUSTMENT": 0.4}},
|
|
695
|
+
{"name": "Concentrated Load", "defaults": {}},
|
|
696
|
+
{"name": "Uniform load (Road bridge footway) UK NA", "defaults": {"ADJUSTMENT": 0.4}}
|
|
697
|
+
]
|
|
698
|
+
},
|
|
699
|
+
"RoadBridgeFatigue": {
|
|
700
|
+
"full_name": "EN 1991-2:2003 - RoadBridge Fatigue", "sub_type": 21,
|
|
701
|
+
"vehicle_types": [
|
|
702
|
+
{"name": "Fatigue Load Model 1", "defaults": {"AMP": 1, "TANDEM_ADJUST_VALUES": [1,1,1], "UDL_ADJUST_VALUES": [1,1,1,1]}},
|
|
703
|
+
{"name": "Fatigue Load Model 2 (280)", "defaults": {"AMP": 1}},
|
|
704
|
+
{"name": "Fatigue Load Model 2 (360)", "defaults": {"AMP": 1}},
|
|
705
|
+
{"name": "Fatigue Load Model 2 (630)", "defaults": {"AMP": 1}},
|
|
706
|
+
{"name": "Fatigue Load Model 2 (560)", "defaults": {"AMP": 1}},
|
|
707
|
+
{"name": "Fatigue Load Model 2 (610)", "defaults": {"AMP": 1}},
|
|
708
|
+
{"name": "Fatigue Load Model 3 (One Vehicle)", "defaults": {"AMP": 1}},
|
|
709
|
+
{"name": "Fatigue Load Model 3 (Two Vehicle)", "defaults": {"AMP": 1, "INTERVAL": 31.6}},
|
|
710
|
+
{"name": "Fatigue Load Model 4 (200)", "defaults": {"AMP": 1}},
|
|
711
|
+
{"name": "Fatigue Load Model 4 (310)", "defaults": {"AMP": 1}},
|
|
712
|
+
{"name": "Fatigue Load Model 4 (490)", "defaults": {"AMP": 1}},
|
|
713
|
+
{"name": "Fatigue Load Model 4 (390)", "defaults": {"AMP": 1}},
|
|
714
|
+
{"name": "Fatigue Load Model 4 (450)", "defaults": {"AMP": 1}}
|
|
715
|
+
]
|
|
716
|
+
},
|
|
717
|
+
"RailTraffic": {
|
|
718
|
+
"full_name": "EN 1991-2:2003-Rail Traffic Load", "sub_type": 23,
|
|
719
|
+
"vehicle_types": [
|
|
720
|
+
{"name": "Load Model 71", "defaults": {"W1": 80, "DD1": 0, "D1": 0.8, "W2": 80, "DD2": 0, "D2": 0.8, "V_LOAD_FACTOR": 1, "LONGI_DIST": False, "ECCEN_VERT_LOAD": False}},
|
|
721
|
+
{"name": "Load Model SW/0", "defaults": {"W1": 133, "DD1": 15, "D1": 5.3, "W2": 133, "DD2": 15, "D2": 0, "V_LOAD_FACTOR": 1, "LONGI_DIST": False, "ECCEN_VERT_LOAD": False}},
|
|
722
|
+
{"name": "Load Model SW/2", "defaults": {"W1": 150, "DD1": 25, "D1": 7, "W2": 150, "DD2": 25, "D2": 0, "V_LOAD_FACTOR": 1, "LONGI_DIST": False, "ECCEN_VERT_LOAD": False}},
|
|
723
|
+
{"name": "Unloaded Train", "defaults": {"W1": 10, "DD1": 0, "D1": 0, "W2": 0, "DD2": 0, "D2": 0, "V_LOAD_FACTOR": 1, "LONGI_DIST": False, "ECCEN_VERT_LOAD": False}},
|
|
724
|
+
{"name": "HSLM B", "defaults": {"V_LOAD_FACTOR": 1, "LONGI_DIST": False, "ECCEN_VERT_LOAD": False, "HSLMB_NUM": 10, "HSLMB_FORCE": 170, "HSLMB_DIST": 3.5, "PHI_DYN_EFF1": 0, "PHI_DYN_EFF2": 0}},
|
|
725
|
+
{"name": "HSLM A1 ~ HSLM A10", "selectable_vehicles": [f"A{i}" for i in range(1, 11)], "defaults": {"V_LOAD_FACTOR": 1, "LONGI_DIST": False, "ECCEN_VERT_LOAD": False, "PHI_DYN_EFF1": 0, "PHI_DYN_EFF2": 0}}
|
|
726
|
+
]
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
def __init__(self, code: str, v_type: str, name: str, id: int = None, **kwargs):
|
|
731
|
+
"""Base class for vehicle definition"""
|
|
732
|
+
self.code, self.v_type, self.name = code, v_type, name
|
|
733
|
+
self.id = len(MovingLoad.Vehicle.vehicles) + 1 if id is None else id
|
|
734
|
+
self.params = kwargs
|
|
735
|
+
if not any(v.id == self.id for v in MovingLoad.Vehicle.vehicles):
|
|
736
|
+
MovingLoad.Vehicle.vehicles.append(self)
|
|
737
|
+
#--------------------------------------------------------------- INDIA----------------------------------------------------
|
|
738
|
+
class India:
|
|
739
|
+
"""
|
|
740
|
+
Defines a Standard Indian Vehicle
|
|
741
|
+
"""
|
|
742
|
+
def __init__(self,
|
|
743
|
+
name: str,
|
|
744
|
+
standard_code: str,
|
|
745
|
+
vehicle_type: str,
|
|
746
|
+
vehicle_name: int = None,
|
|
747
|
+
id: int = None):
|
|
748
|
+
"""
|
|
749
|
+
name (str): A unique name for the vehicle load.
|
|
750
|
+
standard_code (str): Abbreviation for the standard code ("IRC", "IRS", "Footway", "Fatigue").
|
|
751
|
+
vehicle_type (str): The specific type of vehicle.
|
|
752
|
+
- For "IRC": "Class A", "Class B", "Class 70R", "Class 40R", "Class AA","Footway".
|
|
753
|
+
- For "IRS": Use short codes: "BG-1676", "MG-1000", "NG-762", "HML", "FTB".
|
|
754
|
+
vehicle_name (int, optional): The numeric identifier (1-based) for the vehicle, required for "IRS" code.
|
|
755
|
+
id (int, optional): A unique ID for the vehicle. Auto-assigned if None.
|
|
756
|
+
"""
|
|
757
|
+
code_map = {"IRC": "IRC:6-2000", "Footway": "IRC:6-2000", "IRS": "IRS: BRIDGE RULES", "Fatigue": "IRC:6-2014"}
|
|
758
|
+
full_standard_code = code_map.get(standard_code)
|
|
759
|
+
if not full_standard_code:
|
|
760
|
+
raise ValueError(f"Invalid standard_code. Use 'IRC', 'IRS', 'Footway', or 'Fatigue'.")
|
|
761
|
+
|
|
762
|
+
all_params = { "standard_code": full_standard_code }
|
|
763
|
+
defaults = {}
|
|
764
|
+
|
|
765
|
+
if standard_code == "IRS":
|
|
766
|
+
if not vehicle_name:
|
|
767
|
+
raise ValueError("'vehicle_name' is required for IRS standard code.")
|
|
768
|
+
|
|
769
|
+
irs_map = MovingLoad.Vehicle._irs_vehicle_map
|
|
770
|
+
if vehicle_type not in irs_map:
|
|
771
|
+
raise ValueError(f"Invalid IRS vehicle_type '{vehicle_type}'. Choose from {list(irs_map.keys())}")
|
|
772
|
+
|
|
773
|
+
vehicle_info = irs_map[vehicle_type]
|
|
774
|
+
all_params["vehicle_type_name"] = vehicle_info["full_name"]
|
|
775
|
+
|
|
776
|
+
if not (1 <= vehicle_name <= len(vehicle_info["vehicles"])):
|
|
777
|
+
raise ValueError(f"Invalid 'vehicle_name' {vehicle_name} for type '{vehicle_type}'. "
|
|
778
|
+
f"Must be between 1 and {len(vehicle_info['vehicles'])}.")
|
|
779
|
+
|
|
780
|
+
select_vehicle_name = vehicle_info["vehicles"][vehicle_name - 1]
|
|
781
|
+
all_params["select_vehicle"] = select_vehicle_name
|
|
782
|
+
|
|
783
|
+
# Get defaults for the specific IRS vehicle
|
|
784
|
+
if vehicle_type in MovingLoad.Vehicle._india_defaults_map["IRS"]:
|
|
785
|
+
if select_vehicle_name in MovingLoad.Vehicle._india_defaults_map["IRS"][vehicle_type]:
|
|
786
|
+
defaults = MovingLoad.Vehicle._india_defaults_map["IRS"][vehicle_type][select_vehicle_name]
|
|
787
|
+
|
|
788
|
+
else: # For IRC, Footway, Fatigue
|
|
789
|
+
all_params["vehicle_type_name"] = vehicle_type
|
|
790
|
+
# Get defaults if any exist for this type
|
|
791
|
+
if standard_code in MovingLoad.Vehicle._india_defaults_map:
|
|
792
|
+
if vehicle_type in MovingLoad.Vehicle._india_defaults_map[standard_code]:
|
|
793
|
+
defaults = MovingLoad.Vehicle._india_defaults_map[standard_code][vehicle_type]
|
|
794
|
+
|
|
795
|
+
all_params.update(defaults)
|
|
796
|
+
MovingLoad.Vehicle("INDIA", "Standard", name, id, **all_params)
|
|
797
|
+
|
|
798
|
+
class Eurocode:
|
|
799
|
+
"""
|
|
800
|
+
Defines a Standard Eurocode Vehicle
|
|
801
|
+
"""
|
|
802
|
+
def __init__(self,
|
|
803
|
+
name: str,
|
|
804
|
+
standard_code: str,
|
|
805
|
+
vehicle_type: str,
|
|
806
|
+
vehicle_name: int = None,
|
|
807
|
+
id: int = None):
|
|
808
|
+
"""
|
|
809
|
+
name (str): A unique name for the vehicle load.
|
|
810
|
+
standard_code (str): Abbreviation for the standard code.
|
|
811
|
+
- "RoadBridge", "FTB", "RoadBridgeFatigue", "RailTraffic"
|
|
812
|
+
vehicle_type (str): The specific type of vehicle (e.g., "Load Model 1", "Load Model 3").
|
|
813
|
+
vehicle_name (int, optional): The numeric ID (1-based) for a selectable vehicle (e.g., for "Load Model 3").
|
|
814
|
+
id (int, optional): A unique ID for the vehicle. Auto-assigned if None.
|
|
815
|
+
"""
|
|
816
|
+
euro_map = MovingLoad.Vehicle._euro_vehicle_map
|
|
817
|
+
if standard_code not in euro_map:
|
|
818
|
+
raise ValueError(f"Invalid standard_code. Choose from {list(euro_map.keys())}")
|
|
819
|
+
|
|
820
|
+
std_info = euro_map[standard_code]
|
|
821
|
+
v_type_info = next((vt for vt in std_info["vehicle_types"] if vt["name"] == vehicle_type), None)
|
|
822
|
+
if not v_type_info:
|
|
823
|
+
available_types = [vt['name'] for vt in std_info['vehicle_types']]
|
|
824
|
+
raise ValueError(f"Invalid vehicle_type '{vehicle_type}' for '{standard_code}'. Choose from: {available_types}")
|
|
825
|
+
|
|
826
|
+
# Start with the default parameters for the vehicle type
|
|
827
|
+
all_params = v_type_info.get("defaults", {}).copy()
|
|
828
|
+
all_params["SUB_TYPE"] = std_info["sub_type"]
|
|
829
|
+
all_params["vehicle_type_name"] = vehicle_type
|
|
830
|
+
|
|
831
|
+
# Handle selectable vehicles
|
|
832
|
+
if "selectable_vehicles" in v_type_info:
|
|
833
|
+
if not vehicle_name:
|
|
834
|
+
raise ValueError(f"'vehicle_name' is required for vehicle_type '{vehicle_type}'.")
|
|
835
|
+
selectable_list = v_type_info["selectable_vehicles"]
|
|
836
|
+
if not (1 <= vehicle_name <= len(selectable_list)):
|
|
837
|
+
raise ValueError(f"Invalid 'vehicle_name' {vehicle_name} for type '{vehicle_type}'. Must be between 1 and {len(selectable_list)}.")
|
|
838
|
+
|
|
839
|
+
select_vehicle_name = selectable_list[vehicle_name - 1]
|
|
840
|
+
all_params["SEL_VEHICLE"] = select_vehicle_name
|
|
841
|
+
|
|
842
|
+
MovingLoad.Vehicle("EUROCODE", "Standard", name, id, **all_params)
|
|
843
|
+
|
|
844
|
+
@classmethod
|
|
845
|
+
def create(cls):
|
|
846
|
+
"""Sends all defined vehicle data to the Midas Civil"""
|
|
847
|
+
if not cls.vehicles:
|
|
848
|
+
print("No vehicles defined to create.")
|
|
849
|
+
return
|
|
850
|
+
|
|
851
|
+
json_data = cls.json(cls.vehicles)
|
|
852
|
+
MidasAPI("PUT", "/db/mvhl", json_data)
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
@classmethod
|
|
856
|
+
def json(cls, vehicle_list=None):
|
|
857
|
+
"""
|
|
858
|
+
Generates the JSON Data
|
|
859
|
+
"""
|
|
860
|
+
if vehicle_list is None:
|
|
861
|
+
vehicle_list = cls.vehicles
|
|
862
|
+
|
|
863
|
+
data = {"Assign": {}}
|
|
864
|
+
for v in vehicle_list:
|
|
865
|
+
# Creates a copy to avoid modifying the original stored parameters
|
|
866
|
+
params = v.params.copy()
|
|
867
|
+
|
|
868
|
+
if v.code == "INDIA":
|
|
869
|
+
vehicle_data = {
|
|
870
|
+
"MVLD_CODE": 7, # Static code for INDIA
|
|
871
|
+
"VEHICLE_LOAD_NAME": v.name,
|
|
872
|
+
"VEHICLE_LOAD_NUM": 1, # Always Standard for this implementation
|
|
873
|
+
"STANDARD_CODE": params.pop("standard_code"),
|
|
874
|
+
"VEHICLE_TYPE_NAME": params.pop("vehicle_type_name")
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
# Extract the selected vehicle name if it exists
|
|
878
|
+
select_vehicle_name = params.pop("select_vehicle", None)
|
|
879
|
+
|
|
880
|
+
# The remaining parameters in 'params' should be the content for VEH_IN
|
|
881
|
+
# If VEH_IN was added from defaults, use it
|
|
882
|
+
if "VEH_IN" in params:
|
|
883
|
+
# For IRS vehicles, SEL_VEHICLE key is required inside the VEH_IN block
|
|
884
|
+
if select_vehicle_name:
|
|
885
|
+
params["VEH_IN"]["SEL_VEHICLE"] = select_vehicle_name
|
|
886
|
+
vehicle_data["VEH_IN"] = params["VEH_IN"]
|
|
887
|
+
# If there's no default VEH_IN but a vehicle name is selected (e.g., basic IRC class)
|
|
888
|
+
elif select_vehicle_name:
|
|
889
|
+
vehicle_data["VEH_IN"] = {"SEL_VEHICLE": select_vehicle_name}
|
|
890
|
+
|
|
891
|
+
data["Assign"][str(v.id)] = vehicle_data
|
|
892
|
+
|
|
893
|
+
elif v.code == "EUROCODE":
|
|
894
|
+
vehicle_data = {
|
|
895
|
+
"MVLD_CODE": 11, # Static code for EUROCODE
|
|
896
|
+
"VEHICLE_LOAD_NAME": v.name,
|
|
897
|
+
"VEHICLE_LOAD_NUM": 1, # Always Standard for this implementation
|
|
898
|
+
"VEHICLE_TYPE_NAME": params.pop("vehicle_type_name"),
|
|
899
|
+
# All other parameters are nested under VEH_EUROCODE
|
|
900
|
+
"VEH_EUROCODE": params
|
|
901
|
+
}
|
|
902
|
+
data["Assign"][str(v.id)] = vehicle_data
|
|
903
|
+
|
|
904
|
+
return data
|
|
905
|
+
|
|
906
|
+
@classmethod
|
|
907
|
+
def sync(cls):
|
|
908
|
+
"""
|
|
909
|
+
Synchronizes the vehicle data from the Midas model
|
|
910
|
+
"""
|
|
911
|
+
cls.vehicles = [] # Clear the local list before syncing
|
|
912
|
+
response = cls.get()
|
|
913
|
+
|
|
914
|
+
if not response or "MVHL" not in response:
|
|
915
|
+
print("No vehicle data found in the model to sync.")
|
|
916
|
+
return
|
|
917
|
+
|
|
918
|
+
all_vehicles_data = response["MVHL"]
|
|
919
|
+
|
|
920
|
+
# --- Reverse Maps for Lookups ---
|
|
921
|
+
# India Standard Code (e.g., "IRC:6-2000" -> "IRC")
|
|
922
|
+
india_std_code_rev_map = {
|
|
923
|
+
"IRC:6-2000": "IRC",
|
|
924
|
+
"IRS: BRIDGE RULES": "IRS",
|
|
925
|
+
"IRC:6-2014": "Fatigue"
|
|
926
|
+
}
|
|
927
|
+
# India Vehicle Type (e.g., "Broad Gauge-1676mm" -> "BG-1676")
|
|
928
|
+
india_type_rev_map = {v['full_name']: k for k, v in cls._irs_vehicle_map.items()}
|
|
929
|
+
|
|
930
|
+
# Eurocode Standard Code (e.g., 19 -> "RoadBridge")
|
|
931
|
+
euro_std_code_rev_map = {v['sub_type']: k for k, v in cls._euro_vehicle_map.items()}
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
for v_id, v_data in all_vehicles_data.items():
|
|
935
|
+
vehicle_id = int(v_id)
|
|
936
|
+
mvld_code = v_data.get("MVLD_CODE")
|
|
937
|
+
vehicle_load_name = v_data.get("VEHICLE_LOAD_NAME")
|
|
938
|
+
|
|
939
|
+
# --- Sync logic for INDIA vehicles ---
|
|
940
|
+
if mvld_code == 7:
|
|
941
|
+
standard_code_full = v_data.get("STANDARD_CODE")
|
|
942
|
+
vehicle_type_full = v_data.get("VEHICLE_TYPE_NAME")
|
|
943
|
+
|
|
944
|
+
# Handle special case for Footway which uses IRC standard
|
|
945
|
+
if vehicle_type_full == "Footway":
|
|
946
|
+
standard_code = "Footway"
|
|
947
|
+
vehicle_type = "Footway"
|
|
948
|
+
vehicle_name_id = None
|
|
949
|
+
else:
|
|
950
|
+
standard_code = india_std_code_rev_map.get(standard_code_full)
|
|
951
|
+
vehicle_type = india_type_rev_map.get(vehicle_type_full)
|
|
952
|
+
vehicle_name_id = None
|
|
953
|
+
|
|
954
|
+
if standard_code == "IRS" and "VEH_IN" in v_data:
|
|
955
|
+
sel_vehicle_name = v_data["VEH_IN"].get("SEL_VEHICLE")
|
|
956
|
+
if vehicle_type in cls._irs_vehicle_map and sel_vehicle_name:
|
|
957
|
+
try:
|
|
958
|
+
# Find the 1-based index of the vehicle name
|
|
959
|
+
vehicle_name_id = cls._irs_vehicle_map[vehicle_type]["vehicles"].index(sel_vehicle_name) + 1
|
|
960
|
+
except ValueError:
|
|
961
|
+
print(f"Warning: Could not find vehicle name '{sel_vehicle_name}' for type '{vehicle_type}' during sync.")
|
|
962
|
+
continue
|
|
963
|
+
|
|
964
|
+
# Instantiate the vehicle to add it to the local list
|
|
965
|
+
MovingLoad.Vehicle.India(
|
|
966
|
+
name=vehicle_load_name,
|
|
967
|
+
standard_code=standard_code,
|
|
968
|
+
vehicle_type=vehicle_type or vehicle_type_full, # Fallback to full name if no short code
|
|
969
|
+
vehicle_name=vehicle_name_id,
|
|
970
|
+
id=vehicle_id
|
|
971
|
+
)
|
|
972
|
+
|
|
973
|
+
# --- Sync logic for EUROCODE vehicles ---
|
|
974
|
+
elif mvld_code == 11 and "VEH_EUROCODE" in v_data:
|
|
975
|
+
euro_params = v_data["VEH_EUROCODE"]
|
|
976
|
+
sub_type = euro_params.get("SUB_TYPE")
|
|
977
|
+
vehicle_type_name = v_data.get("VEHICLE_TYPE_NAME")
|
|
978
|
+
|
|
979
|
+
standard_code = euro_std_code_rev_map.get(sub_type)
|
|
980
|
+
if not standard_code:
|
|
981
|
+
print(f"Warning: Unknown Eurocode SUB_TYPE '{sub_type}' for vehicle ID {vehicle_id}. Skipping.")
|
|
982
|
+
continue
|
|
983
|
+
|
|
984
|
+
# Check if this vehicle type has selectable options
|
|
985
|
+
std_info = cls._euro_vehicle_map.get(standard_code, {})
|
|
986
|
+
v_type_info = next((vt for vt in std_info.get("vehicle_types", []) if vt["name"] == vehicle_type_name), None)
|
|
987
|
+
|
|
988
|
+
vehicle_name_id = None
|
|
989
|
+
if v_type_info and "selectable_vehicles" in v_type_info:
|
|
990
|
+
sel_vehicle_name = euro_params.get("SEL_VEHICLE")
|
|
991
|
+
if sel_vehicle_name:
|
|
992
|
+
try:
|
|
993
|
+
vehicle_name_id = v_type_info["selectable_vehicles"].index(sel_vehicle_name) + 1
|
|
994
|
+
except ValueError:
|
|
995
|
+
print(f"Warning: Could not find Eurocode vehicle name '{sel_vehicle_name}' for type '{vehicle_type_name}' during sync.")
|
|
996
|
+
continue
|
|
997
|
+
|
|
998
|
+
MovingLoad.Vehicle.Eurocode(
|
|
999
|
+
name=vehicle_load_name,
|
|
1000
|
+
standard_code=standard_code,
|
|
1001
|
+
vehicle_type=vehicle_type_name,
|
|
1002
|
+
vehicle_name=vehicle_name_id,
|
|
1003
|
+
id=vehicle_id
|
|
1004
|
+
)
|
|
1005
|
+
|
|
1006
|
+
@classmethod
|
|
1007
|
+
def get(cls):
|
|
1008
|
+
"""Gets all vehicle load definitions from the Midas model."""
|
|
1009
|
+
return MidasAPI("GET", "/db/mvhl")
|
|
1010
|
+
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
@classmethod
|
|
1014
|
+
def delete(cls):
|
|
1015
|
+
"""Deletes all vehicles from the Midas model."""
|
|
1016
|
+
return MidasAPI("DELETE", "/db/mvhl")
|
|
1017
|
+
|
|
1018
|
+
|
|
1019
|
+
#--------------------------------------------------Load Case--------------------------------------------
|
|
1020
|
+
|
|
1021
|
+
class Case:
|
|
1022
|
+
|
|
1023
|
+
cases = []
|
|
1024
|
+
|
|
1025
|
+
def __init__(self, code: str, case_id: int, params: dict):
|
|
1026
|
+
"""
|
|
1027
|
+
Internal constructor for the Case class. User should use country-specific subclasses.
|
|
1028
|
+
"""
|
|
1029
|
+
self.code = code
|
|
1030
|
+
self.id = case_id
|
|
1031
|
+
self.params = params
|
|
1032
|
+
|
|
1033
|
+
# Add the new case instance to the class-level list, avoiding duplicates by ID
|
|
1034
|
+
if not any(c.id == self.id for c in self.__class__.cases):
|
|
1035
|
+
self.__class__.cases.append(self)
|
|
1036
|
+
|
|
1037
|
+
@classmethod
|
|
1038
|
+
def create(cls):
|
|
1039
|
+
"""
|
|
1040
|
+
Creates moving load cases in the Midas model for all defined country codes.
|
|
1041
|
+
"""
|
|
1042
|
+
if not cls.cases:
|
|
1043
|
+
print("No moving load cases to create.")
|
|
1044
|
+
return
|
|
1045
|
+
|
|
1046
|
+
# Separate cases by country code and send them to the appropriate API endpoint
|
|
1047
|
+
country_codes = set(c.code for c in cls.cases)
|
|
1048
|
+
for code in country_codes:
|
|
1049
|
+
cases_to_create = [c for c in cls.cases if c.code == code]
|
|
1050
|
+
if cases_to_create:
|
|
1051
|
+
json_data = cls.json(cases_to_create)
|
|
1052
|
+
endpoint = ""
|
|
1053
|
+
if code == "INDIA":
|
|
1054
|
+
endpoint = "/db/MVLDid"
|
|
1055
|
+
elif code == "EUROCODE":
|
|
1056
|
+
endpoint = "/db/MVLDeu"
|
|
1057
|
+
|
|
1058
|
+
if endpoint:
|
|
1059
|
+
MidasAPI("PUT", endpoint, json_data)
|
|
1060
|
+
|
|
1061
|
+
# Clear the list after creation
|
|
1062
|
+
cls.cases.clear()
|
|
1063
|
+
|
|
1064
|
+
@classmethod
|
|
1065
|
+
def json(cls, case_list=None):
|
|
1066
|
+
"""Generates the JSON for a list of cases. Uses all stored cases if list is not provided."""
|
|
1067
|
+
if case_list is None:
|
|
1068
|
+
case_list = cls.cases
|
|
1069
|
+
data = {"Assign": {}}
|
|
1070
|
+
for case in case_list:
|
|
1071
|
+
data["Assign"][str(case.id)] = case.params
|
|
1072
|
+
return data
|
|
1073
|
+
|
|
1074
|
+
@classmethod
|
|
1075
|
+
def get(cls):
|
|
1076
|
+
"""
|
|
1077
|
+
Retrieves all moving load cases from the Midas model
|
|
1078
|
+
"""
|
|
1079
|
+
all_cases_data = {}
|
|
1080
|
+
|
|
1081
|
+
# Define endpoints and their expected response keys.
|
|
1082
|
+
endpoints = {
|
|
1083
|
+
"/db/MVLDid": "MVLDID",
|
|
1084
|
+
"/db/MVLDeu": "MVLDEU"
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
for endpoint, response_key in endpoints.items():
|
|
1088
|
+
api_data = MidasAPI("GET", endpoint)
|
|
1089
|
+
|
|
1090
|
+
# Check if the response is valid and contains the expected key
|
|
1091
|
+
if api_data and response_key in api_data:
|
|
1092
|
+
# Add the data under its original API key (e.g., "MVLDID")
|
|
1093
|
+
all_cases_data[response_key] = api_data[response_key]
|
|
1094
|
+
|
|
1095
|
+
return all_cases_data
|
|
1096
|
+
|
|
1097
|
+
@classmethod
|
|
1098
|
+
def delete(cls):
|
|
1099
|
+
"""Deletes all moving load cases from the Midas model."""
|
|
1100
|
+
all_cases_in_model = cls.get()
|
|
1101
|
+
if not all_cases_in_model:
|
|
1102
|
+
return
|
|
1103
|
+
|
|
1104
|
+
if "MVLDID" in all_cases_in_model:
|
|
1105
|
+
MidasAPI("DELETE", "/db/MVLDid")
|
|
1106
|
+
if "MVLDEU" in all_cases_in_model:
|
|
1107
|
+
MidasAPI("DELETE", "/db/MVLDeu")
|
|
1108
|
+
|
|
1109
|
+
@classmethod
|
|
1110
|
+
def sync(cls):
|
|
1111
|
+
"""
|
|
1112
|
+
Synchronizes the load case data from the Midas model
|
|
1113
|
+
"""
|
|
1114
|
+
cls.cases = []
|
|
1115
|
+
response = cls.get()
|
|
1116
|
+
|
|
1117
|
+
# Sync India Cases
|
|
1118
|
+
if "MVLDID" in response:
|
|
1119
|
+
for case_id, case_data in response["MVLDID"].items():
|
|
1120
|
+
name = case_data.get("LCNAME")
|
|
1121
|
+
num_lanes = case_data.get("NUM_LOADED_LANES")
|
|
1122
|
+
scale_factor = case_data.get("SCALE_FACTOR")
|
|
1123
|
+
|
|
1124
|
+
# Case 1: Permit Vehicle Load
|
|
1125
|
+
if case_data.get("OPT_LC_FOR_PERMIT_LOAD"):
|
|
1126
|
+
MovingLoad.Case.India(
|
|
1127
|
+
id=int(case_id),
|
|
1128
|
+
name=name,
|
|
1129
|
+
num_loaded_lanes=num_lanes,
|
|
1130
|
+
scale_factor=scale_factor,
|
|
1131
|
+
opt_lc_for_permit=True,
|
|
1132
|
+
permit_vehicle_id=case_data.get("PERMIT_VEHICLE"),
|
|
1133
|
+
ref_lane_id=case_data.get("REF_LANE"),
|
|
1134
|
+
eccentricity=case_data.get("ECCEN"),
|
|
1135
|
+
permit_scale_factor=case_data.get("PERMIT_SCALE_FACTOR")
|
|
1136
|
+
)
|
|
1137
|
+
# Case 2: Auto Live Load Combination
|
|
1138
|
+
elif case_data.get("OPT_AUTO_LL"):
|
|
1139
|
+
sub_items = []
|
|
1140
|
+
for item in case_data.get("SUB_LOAD_ITEMS", []):
|
|
1141
|
+
sub_items.append([
|
|
1142
|
+
item.get("SCALE_FACTOR"),
|
|
1143
|
+
item.get("VEHICLE_CLASS_1"),
|
|
1144
|
+
item.get("VEHICLE_CLASS_2"),
|
|
1145
|
+
item.get("FOOTWAY"),
|
|
1146
|
+
item.get("SELECTED_LANES"),
|
|
1147
|
+
item.get("SELECTED_FOOTWAY_LANES") # Will be None if not present
|
|
1148
|
+
])
|
|
1149
|
+
MovingLoad.Case.India(
|
|
1150
|
+
id=int(case_id),
|
|
1151
|
+
name=name,
|
|
1152
|
+
num_loaded_lanes=num_lanes,
|
|
1153
|
+
scale_factor=scale_factor,
|
|
1154
|
+
opt_auto_ll=True,
|
|
1155
|
+
sub_load_items=sub_items
|
|
1156
|
+
)
|
|
1157
|
+
# Case 3: General Load
|
|
1158
|
+
else:
|
|
1159
|
+
sub_items = []
|
|
1160
|
+
for item in case_data.get("SUB_LOAD_ITEMS", []):
|
|
1161
|
+
sub_items.append([
|
|
1162
|
+
item.get("SCALE_FACTOR"),
|
|
1163
|
+
item.get("MIN_NUM_LOADED_LANES"),
|
|
1164
|
+
item.get("MAX_NUM_LOADED_LANES"),
|
|
1165
|
+
item.get("VEHICLE_CLASS_1"),
|
|
1166
|
+
item.get("SELECTED_LANES")
|
|
1167
|
+
])
|
|
1168
|
+
MovingLoad.Case.India(
|
|
1169
|
+
id=int(case_id),
|
|
1170
|
+
name=name,
|
|
1171
|
+
num_loaded_lanes=num_lanes,
|
|
1172
|
+
scale_factor=scale_factor,
|
|
1173
|
+
opt_auto_ll=False,
|
|
1174
|
+
sub_load_items=sub_items
|
|
1175
|
+
)
|
|
1176
|
+
|
|
1177
|
+
# Sync Eurocode Cases
|
|
1178
|
+
if "MVLDEU" in response:
|
|
1179
|
+
for case_id, case_data in response["MVLDEU"].items():
|
|
1180
|
+
# The Eurocode constructor can handle the raw dictionary via **kwargs
|
|
1181
|
+
# by leveraging its fallback mechanism when sub_load_items is not provided.
|
|
1182
|
+
name = case_data.pop("LCNAME")
|
|
1183
|
+
load_model = case_data.pop("TYPE_LOADMODEL")
|
|
1184
|
+
use_optimization = case_data.pop("OPT_AUTO_OPTIMIZE")
|
|
1185
|
+
|
|
1186
|
+
MovingLoad.Case.Eurocode(
|
|
1187
|
+
id=int(case_id),
|
|
1188
|
+
name=name,
|
|
1189
|
+
load_model=load_model,
|
|
1190
|
+
use_optimization=use_optimization,
|
|
1191
|
+
**case_data # Pass the rest of the data as keyword arguments
|
|
1192
|
+
)
|
|
1193
|
+
|
|
1194
|
+
class India:
|
|
1195
|
+
"""
|
|
1196
|
+
Defines a Moving Load Case according to Indian standards.
|
|
1197
|
+
|
|
1198
|
+
"""
|
|
1199
|
+
def __init__(self,
|
|
1200
|
+
name: str,
|
|
1201
|
+
num_loaded_lanes: int,
|
|
1202
|
+
id: int = None,
|
|
1203
|
+
# --- Switches to select the type of load case ---
|
|
1204
|
+
opt_auto_ll: bool = False,
|
|
1205
|
+
opt_lc_for_permit: bool = False,
|
|
1206
|
+
|
|
1207
|
+
# --- Common and General Load Parameters ---
|
|
1208
|
+
sub_load_items: list = None,
|
|
1209
|
+
scale_factor: list = None,
|
|
1210
|
+
|
|
1211
|
+
# --- Permit Vehicle Specific Parameters ---
|
|
1212
|
+
permit_vehicle_id: int = None,
|
|
1213
|
+
ref_lane_id: int = None,
|
|
1214
|
+
eccentricity: float = None,
|
|
1215
|
+
permit_scale_factor: float = None):
|
|
1216
|
+
"""
|
|
1217
|
+
|
|
1218
|
+
name (str): The name of the load case (LCNAME).
|
|
1219
|
+
num_loaded_lanes (int): The number of loaded lanes.
|
|
1220
|
+
id (int, optional): A unique integer ID for the case.
|
|
1221
|
+
opt_auto_ll (bool, optional): Set to True for "Auto Live Load Combinations".
|
|
1222
|
+
opt_lc_for_permit (bool, optional): Set to True for "Load Cases for Permit Vehicle".
|
|
1223
|
+
sub_load_items (list, optional): A list of lists defining sub-loads. The format depends on the selected options:
|
|
1224
|
+
|
|
1225
|
+
*** Case 1: General Load Format (opt_auto_ll=False) ***
|
|
1226
|
+
Each inner list must contain 5 items in this order:
|
|
1227
|
+
1. Scale Factor (Number)
|
|
1228
|
+
2. Min. Number of Loaded Lanes (Integer)
|
|
1229
|
+
3. Max. Number of Loaded Lanes (Integer)
|
|
1230
|
+
4. Vehicle Name (String, e.g., "Class A")
|
|
1231
|
+
5. Selected Lanes (list[str], e.g., ["T1", "T2"])
|
|
1232
|
+
|
|
1233
|
+
*** Case 2: Auto Live Load Format (opt_auto_ll=True) ***
|
|
1234
|
+
Each inner list must contain 5-6 items in this order:
|
|
1235
|
+
1. Scale Factor (Number)
|
|
1236
|
+
2. Vehicle Class I (String)
|
|
1237
|
+
3. Vehicle Class II (String)
|
|
1238
|
+
4. Vehicle Footway (String, "" for none)
|
|
1239
|
+
5. Selected Carriageway Lanes (list[str])
|
|
1240
|
+
6. Selected Footway Lanes (list[str]) - Optional, omit or set to None if no footway.
|
|
1241
|
+
|
|
1242
|
+
*** Case 3: Permit Vehicle Format (opt_lc_for_permit=True) ***
|
|
1243
|
+
sub_load_items is not used. Use permit_vehicle_id, ref_lane_id, etc. instead.
|
|
1244
|
+
|
|
1245
|
+
scale_factor (list, optional): A list of 4 numbers for the Multiple Presence Factor. Defaults to [1, 0.9, 0.8, 0.8].
|
|
1246
|
+
permit_vehicle_id (int, optional): The ID of the permit vehicle. Required for permit cases.
|
|
1247
|
+
ref_lane_id (int, optional): The reference lane ID. Required for permit cases.
|
|
1248
|
+
eccentricity (float, optional): Eccentricity for the permit vehicle. Required for permit cases.
|
|
1249
|
+
permit_scale_factor (float, optional): Scale factor for the permit vehicle. Required for permit cases.
|
|
1250
|
+
"""
|
|
1251
|
+
if id is None:
|
|
1252
|
+
# Correctly reference the 'cases' list through its full path
|
|
1253
|
+
case_id = (max(c.id for c in MovingLoad.Case.cases) + 1) if MovingLoad.Case.cases else 1
|
|
1254
|
+
else:
|
|
1255
|
+
case_id = id
|
|
1256
|
+
final_scale_factor = scale_factor if scale_factor is not None else [1, 0.9, 0.8, 0.8]
|
|
1257
|
+
|
|
1258
|
+
params = {
|
|
1259
|
+
"LCNAME": name,
|
|
1260
|
+
"DESC": "",
|
|
1261
|
+
"SCALE_FACTOR": final_scale_factor,
|
|
1262
|
+
"NUM_LOADED_LANES": num_loaded_lanes
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
formatted_sub_loads = []
|
|
1266
|
+
|
|
1267
|
+
if opt_lc_for_permit:
|
|
1268
|
+
if any(p is None for p in [permit_vehicle_id, ref_lane_id, eccentricity, permit_scale_factor]):
|
|
1269
|
+
raise ValueError("For Permit Vehicle cases, 'permit_vehicle_id', 'ref_lane_id', 'eccentricity', and 'permit_scale_factor' are required.")
|
|
1270
|
+
|
|
1271
|
+
params.update({
|
|
1272
|
+
"OPT_AUTO_LL": True,
|
|
1273
|
+
"OPT_LC_FOR_PERMIT_LOAD": True,
|
|
1274
|
+
"PERMIT_VEHICLE": permit_vehicle_id,
|
|
1275
|
+
"REF_LANE": ref_lane_id,
|
|
1276
|
+
"ECCEN": eccentricity,
|
|
1277
|
+
"PERMIT_SCALE_FACTOR": permit_scale_factor
|
|
1278
|
+
})
|
|
1279
|
+
|
|
1280
|
+
elif opt_auto_ll:
|
|
1281
|
+
if sub_load_items is None:
|
|
1282
|
+
raise ValueError("For Auto Live Load cases, 'sub_load_items' is required.")
|
|
1283
|
+
|
|
1284
|
+
carriage_way_width = 2.3 if num_loaded_lanes == 1 else 0
|
|
1285
|
+
carriage_way_loading = 4.903325 if num_loaded_lanes == 1 else 0
|
|
1286
|
+
|
|
1287
|
+
for item_list in sub_load_items:
|
|
1288
|
+
sub_load_dict = {
|
|
1289
|
+
"SCALE_FACTOR": item_list[0],
|
|
1290
|
+
"VEHICLE_CLASS_1": item_list[1],
|
|
1291
|
+
"VEHICLE_CLASS_2": item_list[2],
|
|
1292
|
+
"FOOTWAY": item_list[3],
|
|
1293
|
+
"CARRIAGE_WAY_WIDTH": carriage_way_width,
|
|
1294
|
+
"CARRIAGE_WAY_LOADING": carriage_way_loading,
|
|
1295
|
+
"SELECTED_LANES": item_list[4]
|
|
1296
|
+
}
|
|
1297
|
+
if len(item_list) > 5 and item_list[5] is not None:
|
|
1298
|
+
sub_load_dict["SELECTED_FOOTWAY_LANES"] = item_list[5]
|
|
1299
|
+
formatted_sub_loads.append(sub_load_dict)
|
|
1300
|
+
|
|
1301
|
+
params.update({
|
|
1302
|
+
"OPT_AUTO_LL": True,
|
|
1303
|
+
"OPT_LC_FOR_PERMIT_LOAD": False,
|
|
1304
|
+
"SUB_LOAD_ITEMS": formatted_sub_loads
|
|
1305
|
+
})
|
|
1306
|
+
|
|
1307
|
+
else: # General Load
|
|
1308
|
+
if sub_load_items is None:
|
|
1309
|
+
raise ValueError("For General Load cases, 'sub_load_items' is required.")
|
|
1310
|
+
|
|
1311
|
+
for item_list in sub_load_items:
|
|
1312
|
+
formatted_sub_loads.append({
|
|
1313
|
+
"SCALE_FACTOR": item_list[0],
|
|
1314
|
+
"MIN_NUM_LOADED_LANES": item_list[1],
|
|
1315
|
+
"MAX_NUM_LOADED_LANES": item_list[2],
|
|
1316
|
+
"VEHICLE_CLASS_1": item_list[3],
|
|
1317
|
+
"SELECTED_LANES": item_list[4]
|
|
1318
|
+
})
|
|
1319
|
+
|
|
1320
|
+
params.update({
|
|
1321
|
+
"OPT_AUTO_LL": False,
|
|
1322
|
+
"OPT_LC_FOR_PERMIT_LOAD": False,
|
|
1323
|
+
"SUB_LOAD_ITEMS": formatted_sub_loads
|
|
1324
|
+
})
|
|
1325
|
+
|
|
1326
|
+
MovingLoad.Case("INDIA", case_id, params)
|
|
1327
|
+
|
|
1328
|
+
class Eurocode:
|
|
1329
|
+
|
|
1330
|
+
def __init__(self,
|
|
1331
|
+
name: str,
|
|
1332
|
+
load_model: int,
|
|
1333
|
+
use_optimization: bool = False,
|
|
1334
|
+
id: int = None,
|
|
1335
|
+
sub_load_items: list = None,
|
|
1336
|
+
**kwargs):
|
|
1337
|
+
"""
|
|
1338
|
+
|
|
1339
|
+
name (str): The name of the load case (LCNAME).
|
|
1340
|
+
load_model (int): The Eurocode Load Model type (1-5).
|
|
1341
|
+
use_optimization (bool, optional): Set to True for "Moving Load Optimization". Defaults to False.
|
|
1342
|
+
id (int, optional): A unique integer ID for the case. Auto-assigned if None.
|
|
1343
|
+
sub_load_items (list, optional): Simplified list input. Format depends on the load_model and use_optimization.
|
|
1344
|
+
**kwargs: Additional individual parameters (for backward compatibility).
|
|
1345
|
+
|
|
1346
|
+
* General Load (use_optimization=False) *
|
|
1347
|
+
|
|
1348
|
+
- load_model = 1: [opt_leading, vhl_name1, vhl_name2, selected_lanes, remaining_area, footway_lanes]
|
|
1349
|
+
Example: [False, "V1", "V2", ["L1"], ["L2"], ["F1"]]
|
|
1350
|
+
|
|
1351
|
+
- load_model = 2: [opt_leading, opt_comb, [(name, sf, min_L, max_L, [lanes]), ...]]
|
|
1352
|
+
Example: [True, 1, [("V_Permit", 1.0, 1, 4, ["L1", "L2"])]]
|
|
1353
|
+
|
|
1354
|
+
- load_model = 3: [opt_leading, vhl_name1, vhl_name2, selected_lanes, remaining_area]
|
|
1355
|
+
Example: [False, "V1", "V3", ["L1", "L2"], ["L3"]]
|
|
1356
|
+
|
|
1357
|
+
- load_model = 4: [opt_leading, vhl_name1, vhl_name2, selected_lanes, remaining_area, straddling_lanes]
|
|
1358
|
+
Where straddling_lanes is a list of dicts: [{'NAME1': 'start', 'NAME2': 'end'}, ...]
|
|
1359
|
+
Example: [False, "V1", "V4", ["L1"], ["L2"], [{"NAME1": "L3", "NAME2": "L4"}]]
|
|
1360
|
+
|
|
1361
|
+
- load_model = 5 (Railway): [opt_psi, opt_comb, [sf1,sf2,sf3], [mf1,mf2,mf3], [(name, sf, min_L, max_L, [lanes]), ...]]
|
|
1362
|
+
Example: [False, 1, [0.8,0.7,0.6], [1,1,0.75], [("Rail-V", 1, 1, 1, ["T1"])]]
|
|
1363
|
+
|
|
1364
|
+
* Moving Load Optimization (use_optimization=True) *
|
|
1365
|
+
|
|
1366
|
+
- load_model = 1: [opt_leading, vhl_name1, vhl_name2, min_dist, opt_lane, loaded_lanes, [selected_lanes]]
|
|
1367
|
+
Example: [False, "V1", "V2", 10, "L1", 2, ["L1", "L2"]]
|
|
1368
|
+
|
|
1369
|
+
- load_model = 2: [opt_leading, opt_comb, min_dist, opt_lane, min_v, max_v, [(name, sf), ...]]
|
|
1370
|
+
Example: [False, 1, 10, "L1", 1, 2, [("V_Permit", 1.0), ("V_Other", 0.8)]]
|
|
1371
|
+
|
|
1372
|
+
- load_model = 3: [opt_leading, vhl_name1, vhl_name2, min_dist, opt_lane, loaded_lanes, [selected_lanes]]
|
|
1373
|
+
Example: [True, "V1", "V3_auto", 10, "L1", 3, ["L1", "L2", "L3"]]
|
|
1374
|
+
|
|
1375
|
+
- load_model = 4: [opt_leading, vhl_name1, vhl_name2, min_dist, opt_lane, loaded_lanes, [selected_lanes], [straddling_lanes]]
|
|
1376
|
+
Example: [True, "V1", "V4_auto", 10, "L2", 3, ["L1", "L3"], [{"NAME1": "L3", "NAME2": "L4"}]]
|
|
1377
|
+
|
|
1378
|
+
- load_model = 5 (Railway): [opt_psi, opt_comb, [sf1,sf2,sf3], [mf1,mf2,mf3], min_dist, opt_lane, min_v, max_v, [(name, sf), ...]]
|
|
1379
|
+
Example: [False, 1, [0.8,0.7,0.6], [1,1,0.75], 20, "T1", 1, 1, [("Rail-V", 1)]]
|
|
1380
|
+
"""
|
|
1381
|
+
if id is None:
|
|
1382
|
+
# Correctly reference the 'cases' list through its full path
|
|
1383
|
+
case_id = (max(c.id for c in MovingLoad.Case.cases) + 1) if MovingLoad.Case.cases else 1
|
|
1384
|
+
else:
|
|
1385
|
+
case_id = id
|
|
1386
|
+
params = {
|
|
1387
|
+
"LCNAME": name,
|
|
1388
|
+
"DESC": kwargs.get("DESC", ""),
|
|
1389
|
+
"TYPE_LOADMODEL": load_model,
|
|
1390
|
+
"OPT_AUTO_OPTIMIZE": use_optimization
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
if sub_load_items is None:
|
|
1394
|
+
# Fallback to kwargs for backward compatibility if sub_load_items is not used
|
|
1395
|
+
params.update(kwargs)
|
|
1396
|
+
MovingLoad.Case("EUROCODE", case_id, params)
|
|
1397
|
+
return
|
|
1398
|
+
|
|
1399
|
+
if not use_optimization: # General Load
|
|
1400
|
+
if load_model == 1:
|
|
1401
|
+
params.update({"OPT_LEADING": sub_load_items[0], "VHLNAME1": sub_load_items[1], "VHLNAME2": sub_load_items[2], "SLN_LIST": sub_load_items[3], "SRA_LIST": sub_load_items[4], "FLN_LIST": sub_load_items[5]})
|
|
1402
|
+
elif load_model == 2:
|
|
1403
|
+
sub_loads = [{"TYPE": 2, "NAME": item[0], "SCALE_FACTOR": item[1], "MIN_LOAD_LANE_TYPE": item[2], "MAX_LOAD_LANE_TYPE": item[3], "SLN_LIST": item[4]} for item in sub_load_items[2]]
|
|
1404
|
+
params.update({"OPT_LEADING": sub_load_items[0], "OPT_COMB": sub_load_items[1], "SUB_LOAD_LIST": sub_loads})
|
|
1405
|
+
elif load_model == 3:
|
|
1406
|
+
params.update({"OPT_LEADING": sub_load_items[0], "VHLNAME1": sub_load_items[1], "VHLNAME2": sub_load_items[2], "SLN_LIST": sub_load_items[3], "SRA_LIST": sub_load_items[4]})
|
|
1407
|
+
elif load_model == 4:
|
|
1408
|
+
params.update({"OPT_LEADING": sub_load_items[0], "VHLNAME1": sub_load_items[1], "VHLNAME2": sub_load_items[2], "SLN_LIST": sub_load_items[3], "SRA_LIST": sub_load_items[4], "STL_LIST": sub_load_items[5]})
|
|
1409
|
+
elif load_model == 5:
|
|
1410
|
+
sub_loads = [{"TYPE": 2, "NAME": item[0], "SCALE_FACTOR": item[1], "MIN_LOAD_LANE_TYPE": item[2], "MAX_LOAD_LANE_TYPE": item[3], "SLN_LIST": item[4]} for item in sub_load_items[4]]
|
|
1411
|
+
params.update({"OPT_PSI_FACTOR": sub_load_items[0], "OPT_COMB": sub_load_items[1], "SCALE_FACTOR1": sub_load_items[2][0], "SCALE_FACTOR2": sub_load_items[2][1], "SCALE_FACTOR3": sub_load_items[2][2], "MULTI_FACTOR1": sub_load_items[3][0], "MULTI_FACTOR2": sub_load_items[3][1], "MULTI_FACTOR3": sub_load_items[3][2], "SUB_LOAD_LIST": sub_loads})
|
|
1412
|
+
|
|
1413
|
+
else: # Moving Load Optimization
|
|
1414
|
+
if load_model == 1:
|
|
1415
|
+
params.update({"OPT_LEADING": sub_load_items[0], "VHLNAME1": sub_load_items[1], "VHLNAME2": sub_load_items[2], "MINVHLDIST": sub_load_items[3], "OPTIMIZE_LANE_NAME": sub_load_items[4], "LOADEDLANE": sub_load_items[5], "SLN_LIST": sub_load_items[6]})
|
|
1416
|
+
elif load_model == 2:
|
|
1417
|
+
opt_list = [{"TYPE": 2, "NAME": item[0], "SCALE_FACTOR": item[1]} for item in sub_load_items[6]]
|
|
1418
|
+
params.update({"OPT_LEADING": sub_load_items[0], "OPT_COMB": sub_load_items[1], "MINVHLDIST": sub_load_items[2], "OPTIMIZE_LANE_NAME": sub_load_items[3], "MIN_NUM_VHL": sub_load_items[4], "MAX_NUM_VHL": sub_load_items[5], "OPTIMIZE_LIST": opt_list})
|
|
1419
|
+
elif load_model == 3:
|
|
1420
|
+
params.update({"OPT_LEADING": sub_load_items[0], "VHLNAME1": sub_load_items[1], "VHLNAME2": sub_load_items[2], "MINVHLDIST": sub_load_items[3], "OPTIMIZE_LANE_NAME": sub_load_items[4], "LOADEDLANE": sub_load_items[5], "SLN_LIST": sub_load_items[6]})
|
|
1421
|
+
elif load_model == 4:
|
|
1422
|
+
params.update({"OPT_LEADING": sub_load_items[0], "VHLNAME1": sub_load_items[1], "VHLNAME2": sub_load_items[2], "MINVHLDIST": sub_load_items[3], "OPTIMIZE_LANE_NAME": sub_load_items[4], "LOADEDLANE": sub_load_items[5], "SLN_LIST": sub_load_items[6], "STL_LIST": sub_load_items[7]})
|
|
1423
|
+
elif load_model == 5:
|
|
1424
|
+
opt_list = [{"TYPE": 2, "NAME": item[0], "SCALE_FACTOR": item[1]} for item in sub_load_items[8]]
|
|
1425
|
+
params.update({"OPT_PSI_FACTOR": sub_load_items[0], "OPT_COMB": sub_load_items[1], "SCALE_FACTOR1": sub_load_items[2][0], "SCALE_FACTOR2": sub_load_items[2][1], "SCALE_FACTOR3": sub_load_items[2][2], "MULTI_FACTOR1": sub_load_items[3][0], "MULTI_FACTOR2": sub_load_items[3][1], "MULTI_FACTOR3": sub_load_items[3][2], "MINVHLDIST": sub_load_items[4], "OPTIMIZE_LANE_NAME": sub_load_items[5], "MIN_NUM_VHL": sub_load_items[6], "MAX_NUM_VHL": sub_load_items[7], "OPTIMIZE_LIST": opt_list})
|
|
1426
|
+
|
|
1427
|
+
MovingLoad.Case("EUROCODE", case_id, params)
|
|
1428
|
+
|
|
1429
|
+
|
|
1430
|
+
|
|
1431
|
+
#--------------------------------------Test---------------------------------------------
|