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.
- midas_civil/_BoundaryChangeAssignment.py +278 -0
- midas_civil/__init__.py +51 -0
- midas_civil/_analysiscontrol.py +585 -0
- midas_civil/_boundary.py +888 -0
- midas_civil/_construction.py +1004 -0
- midas_civil/_element.py +1346 -0
- midas_civil/_group.py +337 -0
- midas_civil/_load.py +967 -0
- midas_civil/_loadcomb.py +159 -0
- midas_civil/_mapi.py +249 -0
- midas_civil/_material.py +1692 -0
- midas_civil/_model.py +522 -0
- midas_civil/_movingload.py +1479 -0
- midas_civil/_node.py +532 -0
- midas_civil/_result_table.py +929 -0
- midas_civil/_result_test.py +5455 -0
- midas_civil/_section/_TapdbSecSS.py +175 -0
- midas_civil/_section/__init__.py +413 -0
- midas_civil/_section/_compositeSS.py +283 -0
- midas_civil/_section/_dbSecSS.py +164 -0
- midas_civil/_section/_offsetSS.py +53 -0
- midas_civil/_section/_pscSS copy.py +455 -0
- midas_civil/_section/_pscSS.py +822 -0
- midas_civil/_section/_tapPSC12CellSS.py +565 -0
- midas_civil/_section/_unSupp.py +58 -0
- midas_civil/_settlement.py +161 -0
- midas_civil/_temperature.py +677 -0
- midas_civil/_tendon.py +1016 -0
- midas_civil/_thickness.py +147 -0
- midas_civil/_utils.py +529 -0
- midas_civil/_utilsFunc/__init__.py +0 -0
- midas_civil/_utilsFunc/_line2plate.py +636 -0
- midas_civil/_view.py +891 -0
- midas_civil/_view_trial.py +430 -0
- midas_civil/_visualise.py +347 -0
- midas_civil-1.4.1.dist-info/METADATA +74 -0
- midas_civil-1.4.1.dist-info/RECORD +40 -0
- midas_civil-1.4.1.dist-info/WHEEL +5 -0
- midas_civil-1.4.1.dist-info/licenses/LICENSE +21 -0
- midas_civil-1.4.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
from ._mapi import MidasAPI
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def _ThikADD(self):
|
|
6
|
+
# Commom HERE ---------------------------------------------
|
|
7
|
+
id = int(self.ID)
|
|
8
|
+
if Thickness.ids == []:
|
|
9
|
+
count = 1
|
|
10
|
+
else:
|
|
11
|
+
count = max(Thickness.ids)+1
|
|
12
|
+
|
|
13
|
+
if id==0 :
|
|
14
|
+
self.ID = count
|
|
15
|
+
Thickness.thick.append(self)
|
|
16
|
+
Thickness.ids.append(int(self.ID))
|
|
17
|
+
elif id in Thickness.ids:
|
|
18
|
+
self.ID=int(id)
|
|
19
|
+
print(f'⚠️ Thickness with ID {id} already exist! It will be replaced.')
|
|
20
|
+
index=Thickness.ids.index(id)
|
|
21
|
+
Thickness.thick[index]=self
|
|
22
|
+
else:
|
|
23
|
+
self.ID=id
|
|
24
|
+
Thickness.thick.append(self)
|
|
25
|
+
Thickness.ids.append(int(self.ID))
|
|
26
|
+
# Common END -------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _updateThik(self):
|
|
30
|
+
js2s = {'Assign':{self.ID : _Obj2JS(self)}}
|
|
31
|
+
MidasAPI('PUT','/db/THIK',js2s)
|
|
32
|
+
return js2s
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _Obj2JS(obj):
|
|
36
|
+
|
|
37
|
+
js={
|
|
38
|
+
"NAME": obj.NAME,
|
|
39
|
+
"TYPE": obj.TYPE,
|
|
40
|
+
"bINOUT": obj.bINOUT,
|
|
41
|
+
"T_IN": obj.T_IN,
|
|
42
|
+
"T_OUT": obj.T_OUT,
|
|
43
|
+
"OFFSET": obj.OFF_TYPE,
|
|
44
|
+
"O_VALUE": obj.OFFSET
|
|
45
|
+
}
|
|
46
|
+
return js
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _JS2Obj(id,js):
|
|
51
|
+
name = js['NAME']
|
|
52
|
+
type = js['TYPE']
|
|
53
|
+
binout = js['bINOUT']
|
|
54
|
+
t_in = js['T_IN']
|
|
55
|
+
t_out = js['T_OUT']
|
|
56
|
+
try : offset = js['OFFSET']
|
|
57
|
+
except: offset = 0
|
|
58
|
+
off_value = js['O_VALUE']
|
|
59
|
+
|
|
60
|
+
t_out2=-1
|
|
61
|
+
if binout:t_out2 = t_out
|
|
62
|
+
|
|
63
|
+
if type == 'VALUE':
|
|
64
|
+
Thickness(t_in,t_out2,off_value,offset,name,id)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class _common:
|
|
69
|
+
def __str__(self):
|
|
70
|
+
return str(f'ID = {self.ID} \nJSON : {_Obj2JS(self)}\n')
|
|
71
|
+
|
|
72
|
+
def update(self):
|
|
73
|
+
return _updateThik(self)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class Thickness(_common):
|
|
77
|
+
"""Create Thicknes"""
|
|
78
|
+
thick = []
|
|
79
|
+
ids = []
|
|
80
|
+
|
|
81
|
+
def __init__(self,thick=0.0,thick_out=-1,offset=0,off_type='rat',name="",id=None):
|
|
82
|
+
if id == None: id = 0
|
|
83
|
+
self.ID = id
|
|
84
|
+
if name == "":
|
|
85
|
+
self.NAME = str(thick)
|
|
86
|
+
else: self.NAME = name
|
|
87
|
+
self.TYPE = 'VALUE'
|
|
88
|
+
self.T_IN = thick
|
|
89
|
+
self.bINOUT = True
|
|
90
|
+
|
|
91
|
+
if thick_out==-1:
|
|
92
|
+
self.T_OUT = thick
|
|
93
|
+
self.bINOUT = False
|
|
94
|
+
else: self.T_OUT = thick_out
|
|
95
|
+
|
|
96
|
+
self.OFFSET = offset
|
|
97
|
+
|
|
98
|
+
if off_type=='rat':
|
|
99
|
+
self.OFF_TYPE = 1
|
|
100
|
+
else: self.OFF_TYPE = 2
|
|
101
|
+
|
|
102
|
+
if offset==0:
|
|
103
|
+
self.OFF_TYPE =0
|
|
104
|
+
|
|
105
|
+
_ThikADD(self)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@classmethod
|
|
109
|
+
def json(cls):
|
|
110
|
+
json = {"Assign":{}}
|
|
111
|
+
for sect in cls.thick:
|
|
112
|
+
js = _Obj2JS(sect)
|
|
113
|
+
json["Assign"][sect.ID] = js
|
|
114
|
+
return json
|
|
115
|
+
|
|
116
|
+
@staticmethod
|
|
117
|
+
def create():
|
|
118
|
+
MidasAPI("PUT","/db/THIK",Thickness.json())
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def get():
|
|
122
|
+
return MidasAPI("GET","/db/THIK")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@staticmethod
|
|
126
|
+
def delete():
|
|
127
|
+
MidasAPI("DELETE","/db/THIK")
|
|
128
|
+
Thickness.thick=[]
|
|
129
|
+
Thickness.ids=[]
|
|
130
|
+
|
|
131
|
+
@staticmethod
|
|
132
|
+
def clear():
|
|
133
|
+
Thickness.thick=[]
|
|
134
|
+
Thickness.ids=[]
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@staticmethod
|
|
138
|
+
def sync():
|
|
139
|
+
a = Thickness.get()
|
|
140
|
+
if a != {'message': ''}:
|
|
141
|
+
if list(a['THIK'].keys()) != []:
|
|
142
|
+
Thickness.thick = []
|
|
143
|
+
Thickness.ids=[]
|
|
144
|
+
for sect_id in a['THIK'].keys():
|
|
145
|
+
_JS2Obj(sect_id,a['THIK'][sect_id])
|
|
146
|
+
|
|
147
|
+
|
midas_civil/_utils.py
ADDED
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
# from ._model import *
|
|
2
|
+
# from ._mapi import *
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from math import hypot,sqrt
|
|
5
|
+
import numpy as np
|
|
6
|
+
from typing import Literal
|
|
7
|
+
|
|
8
|
+
#Function to remove duplicate set of values from 2 lists
|
|
9
|
+
# def unique_lists(li1, li2):
|
|
10
|
+
# if type (li1) == list and type (li2) == list:
|
|
11
|
+
# if len(li1) == len(li2):
|
|
12
|
+
# indices_to_remove = []
|
|
13
|
+
# for i in range(len(li1)):
|
|
14
|
+
# for j in range(i+1,len(li1)):
|
|
15
|
+
# if li1[i] == li1[j] and li2[i] == li2[j]:
|
|
16
|
+
# indices_to_remove.append(j)
|
|
17
|
+
# for index in sorted(indices_to_remove, reverse = True):
|
|
18
|
+
# del li1[index]
|
|
19
|
+
# del li2[index]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# def sect_inp(sec):
|
|
23
|
+
# """Section ID. Enter one section id or list of section IDs. Sample: sect_inp(1) OR sect_inp([3,2,5])"""
|
|
24
|
+
# Model.units()
|
|
25
|
+
# a = MidasAPI("GET","/db/SECT",{"Assign":{}})
|
|
26
|
+
# if type(sec)==int: sec = [sec]
|
|
27
|
+
# b={}
|
|
28
|
+
# for s in sec:
|
|
29
|
+
# if str(s) in a['SECT'].keys() : b.update({s : a['SECT'][str(s)]})
|
|
30
|
+
# # if elem = [0] and sec!=0: b.update({sec : })
|
|
31
|
+
# if b == {}: b = "The required section ID is not defined in connected model file."
|
|
32
|
+
# return(b)
|
|
33
|
+
#---------------------------------------------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def sFlatten(list_of_list):
|
|
38
|
+
# list_of_list = [list_of_list]
|
|
39
|
+
return [item for elem in list_of_list for item in (elem if isinstance(elem, (list,np.ndarray)) else [elem])]
|
|
40
|
+
|
|
41
|
+
# def getID_orig(element_list):
|
|
42
|
+
# """Return ID of Node and Element"""
|
|
43
|
+
# return [beam.ID for beam in sFlatten(element_list)]
|
|
44
|
+
|
|
45
|
+
def getID(*objects):
|
|
46
|
+
objects = list(objects)
|
|
47
|
+
_getID2(objects)
|
|
48
|
+
return objects
|
|
49
|
+
|
|
50
|
+
def _getID2(objects):
|
|
51
|
+
for i in range(len(objects)):
|
|
52
|
+
if isinstance(objects[i], list):
|
|
53
|
+
_getID2(objects[i]) # Recursive call for sublist
|
|
54
|
+
else:
|
|
55
|
+
objects[i] = objects[i].ID
|
|
56
|
+
|
|
57
|
+
def getLOC(objects):
|
|
58
|
+
''' Get location for multiple node objects'''
|
|
59
|
+
_getLOC2(objects)
|
|
60
|
+
return objects
|
|
61
|
+
|
|
62
|
+
def _getLOC2(objects):
|
|
63
|
+
for i in range(len(objects)):
|
|
64
|
+
if isinstance(objects[i], list):
|
|
65
|
+
_getLOC2(objects[i]) # Recursive call for sublist
|
|
66
|
+
else:
|
|
67
|
+
objects[i] = objects[i].LOC
|
|
68
|
+
|
|
69
|
+
def getNodeID(*objects):
|
|
70
|
+
objects = list(objects)
|
|
71
|
+
_getNodeID2(objects)
|
|
72
|
+
return objects
|
|
73
|
+
|
|
74
|
+
def _getNodeID2(objects):
|
|
75
|
+
for i in range(len(objects)):
|
|
76
|
+
if isinstance(objects[i], list):
|
|
77
|
+
_getNodeID2(objects[i]) # Recursive call for sublist
|
|
78
|
+
else:
|
|
79
|
+
objects[i] = objects[i].NODES
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# def getNodeID_orig(element_list):
|
|
85
|
+
# """Return Node IDs of Element"""
|
|
86
|
+
# # return list(sFlatten([beam.NODES for beam in sFlatten(element_list)]))
|
|
87
|
+
# return list(sFlatten([beam.NODES for beam in sFlatten(element_list)]))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def arr2csv(nlist):
|
|
91
|
+
strinff = ",".join(map(str,nlist))
|
|
92
|
+
return strinff
|
|
93
|
+
|
|
94
|
+
def zz_add_to_dict(dictionary, key, value):
|
|
95
|
+
if key in dictionary:
|
|
96
|
+
dictionary[key].append(value)
|
|
97
|
+
else:
|
|
98
|
+
dictionary[key] = [value]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _convItem2List(item):
|
|
102
|
+
if isinstance(item,(list,np.ndarray)):
|
|
103
|
+
return item
|
|
104
|
+
return [item]
|
|
105
|
+
|
|
106
|
+
def _matchArray(A,B):
|
|
107
|
+
'''Matches B to length of A
|
|
108
|
+
Return B'''
|
|
109
|
+
A = _convItem2List(A)
|
|
110
|
+
B = _convItem2List(B)
|
|
111
|
+
n = len(A)
|
|
112
|
+
if len(B) >= n:
|
|
113
|
+
return B[:n]
|
|
114
|
+
return B + [B[-1]] * (n - len(B))
|
|
115
|
+
|
|
116
|
+
def _longestList(A,B):
|
|
117
|
+
""" Matches A , B list and returns the list with longest length with last element repeated """
|
|
118
|
+
A = _convItem2List(A)
|
|
119
|
+
B = _convItem2List(B)
|
|
120
|
+
nA = len(A)
|
|
121
|
+
nB = len(B)
|
|
122
|
+
|
|
123
|
+
if nA >= nB:
|
|
124
|
+
return (A , B + [B[-1]] * (nA - nB))
|
|
125
|
+
return (A + [A[-1]] * (nB - nA),B)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
_alignType = Literal['cubic','akima','makima','pchip']
|
|
129
|
+
|
|
130
|
+
class utils:
|
|
131
|
+
''' Contains helper function and utilities'''
|
|
132
|
+
__RC_Grillage_nSpan = 1
|
|
133
|
+
class Alignment:
|
|
134
|
+
'''Defines alignment object passing through the points
|
|
135
|
+
X -> monotonous increasing'''
|
|
136
|
+
|
|
137
|
+
def __init__(self,points,type: _alignType = 'cubic'):
|
|
138
|
+
'''
|
|
139
|
+
**POINTS** -> Points on the alignment [[x,y] , [x,y] , [x,y] ....]
|
|
140
|
+
**TYPE** -> Type of interpolating curve
|
|
141
|
+
cubic , akima , makima , pchip
|
|
142
|
+
'''
|
|
143
|
+
from scipy.interpolate import CubicSpline , Akima1DInterpolator , PchipInterpolator
|
|
144
|
+
|
|
145
|
+
_pt_x = [pt[0] for pt in points]
|
|
146
|
+
_pt_y = [pt[1] for pt in points]
|
|
147
|
+
|
|
148
|
+
# _alignment = splrep(_pt_x, _pt_y)
|
|
149
|
+
if type == 'akima':
|
|
150
|
+
_alignment = Akima1DInterpolator(_pt_x, _pt_y,method='akima')
|
|
151
|
+
elif type == 'makima':
|
|
152
|
+
_alignment = Akima1DInterpolator(_pt_x, _pt_y,method='makima')
|
|
153
|
+
elif type == 'pchip':
|
|
154
|
+
_alignment = PchipInterpolator(_pt_x, _pt_y)
|
|
155
|
+
else :
|
|
156
|
+
_alignment = CubicSpline(_pt_x, _pt_y)
|
|
157
|
+
|
|
158
|
+
# _alignSlope = Akima1DInterpolator(_pt_x, _pt_y,method='akima') # Used for slope calculation
|
|
159
|
+
|
|
160
|
+
_n=100
|
|
161
|
+
# INITIAL ALGINMENT - Mapping U parameter to X (based on Distance)
|
|
162
|
+
_x_fine = np.linspace(_pt_x[0],_pt_x[-1],_n)
|
|
163
|
+
|
|
164
|
+
_y_fine = _alignment(_x_fine)
|
|
165
|
+
|
|
166
|
+
_dx = np.diff(_x_fine)
|
|
167
|
+
_dy = np.diff(_y_fine)
|
|
168
|
+
|
|
169
|
+
_dl=[]
|
|
170
|
+
for i in range(len(_dx)):
|
|
171
|
+
_dl.append(hypot(_dx[i],_dy[i]))
|
|
172
|
+
|
|
173
|
+
_cumLength = np.insert(np.cumsum(_dl),0,0)
|
|
174
|
+
_totalLength = _cumLength[-1]
|
|
175
|
+
|
|
176
|
+
_u_fine = _cumLength/_totalLength
|
|
177
|
+
|
|
178
|
+
self.ALIGNMENT = _alignment
|
|
179
|
+
# self.ALIGNSLOPE = _alignSlope
|
|
180
|
+
self.TOTALLENGTH = _totalLength
|
|
181
|
+
self.CUMLENGTH = _cumLength
|
|
182
|
+
self.PT_X = _pt_x
|
|
183
|
+
self.PT_Y = _pt_y
|
|
184
|
+
self.X_FINE = _x_fine
|
|
185
|
+
self.Y_FINE = _y_fine
|
|
186
|
+
self.U_FINE = _u_fine
|
|
187
|
+
|
|
188
|
+
def getPoint(self,distance):
|
|
189
|
+
x_interp = np.interp(distance,self.CUMLENGTH,self.X_FINE)
|
|
190
|
+
y_interp = np.interp(distance,self.CUMLENGTH,self.Y_FINE)
|
|
191
|
+
return x_interp , y_interp
|
|
192
|
+
|
|
193
|
+
def getSlope(self,distance):
|
|
194
|
+
'Returns theta in radians (-pi/2 to pi/2)'
|
|
195
|
+
x_interp = np.interp(distance,self.CUMLENGTH,self.X_FINE)
|
|
196
|
+
slope = self.ALIGNMENT(x_interp,1) # Tan theta
|
|
197
|
+
angle = np.atan(slope)
|
|
198
|
+
return angle
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@staticmethod
|
|
202
|
+
def transformPoint(point:tuple,initial_align:utils.Alignment,final_align:utils.Alignment) -> list :
|
|
203
|
+
'''
|
|
204
|
+
Transforms a point (x,y) => [X , Y]
|
|
205
|
+
Maps a point (x,y) wrt Initial alignment curve to a new Final alignment (X,Y)
|
|
206
|
+
'''
|
|
207
|
+
ptx = point[0]
|
|
208
|
+
pty = point[1]
|
|
209
|
+
distx = 100000 #Initial high distance
|
|
210
|
+
idx = 0
|
|
211
|
+
y_ref = 0
|
|
212
|
+
fact = 10000
|
|
213
|
+
for q in range(101):
|
|
214
|
+
x_onLine1 = ptx+initial_align.TOTALLENGTH*(q-50)/fact
|
|
215
|
+
if x_onLine1 < initial_align.PT_X[0]:
|
|
216
|
+
continue
|
|
217
|
+
if x_onLine1 > initial_align.PT_X[-1]:
|
|
218
|
+
break
|
|
219
|
+
# y_onLine1 = splev(x_onLine1, initial_align.ALIGNMENT)
|
|
220
|
+
y_onLine1 = initial_align.ALIGNMENT(x_onLine1)
|
|
221
|
+
dist = hypot(ptx-x_onLine1,pty-y_onLine1)
|
|
222
|
+
if dist <= distx:
|
|
223
|
+
distx = dist
|
|
224
|
+
idx = q
|
|
225
|
+
y_ref = y_onLine1
|
|
226
|
+
# print(f" > X location of line = {x_onLine1} Y on Line = {y_onLine1}| Distance = {dist} | Index = {q}")
|
|
227
|
+
|
|
228
|
+
final_u = np.interp(ptx+initial_align.TOTALLENGTH*(idx-50)/fact,initial_align.X_FINE,initial_align.U_FINE)
|
|
229
|
+
off = np.sign(pty-y_ref)*distx
|
|
230
|
+
x2_interp = np.interp(final_u,final_align.U_FINE,final_align.X_FINE)
|
|
231
|
+
|
|
232
|
+
# y2_interp = splev(x2_interp, final_align.ALIGNMENT)
|
|
233
|
+
y2_interp = final_align.ALIGNMENT(x2_interp)
|
|
234
|
+
|
|
235
|
+
slope = final_align.ALIGNMENT(x2_interp,1) # Tan theta
|
|
236
|
+
|
|
237
|
+
norm = sqrt(1+slope*slope)
|
|
238
|
+
x_off = -slope/norm
|
|
239
|
+
y_off = 1/norm
|
|
240
|
+
|
|
241
|
+
# print(f"Point loc = [{point}] , Index match = {idx} , Point X on Initial = {ptx+initial_align.TOTALLENGTH*(idx-50)/8000} , Point Y = {y_ref} , Distance = {off} , Xoff = {slope}")
|
|
242
|
+
|
|
243
|
+
return (round(x2_interp+x_off*off,5),round(y2_interp+y_off*off,5))
|
|
244
|
+
|
|
245
|
+
@staticmethod
|
|
246
|
+
def modifyNXModel(initial_align:utils.Alignment,final_align:utils.Alignment,bElement:bool=True,bUpdateModel=True,bSync=True):
|
|
247
|
+
'''
|
|
248
|
+
Modifies CIVIL NX model as per new alignment.
|
|
249
|
+
Meant for **standalone** use
|
|
250
|
+
Use transformPoint in other cases
|
|
251
|
+
|
|
252
|
+
:param initial_align: Intitial alignment of the model
|
|
253
|
+
:type initial_align: utils.Alignment
|
|
254
|
+
:param final_align: Final alignment of the model
|
|
255
|
+
:type final_align: utils.Alignment
|
|
256
|
+
:param bElement: If beta angle of element should be modified
|
|
257
|
+
:type bElement: bool
|
|
258
|
+
'''
|
|
259
|
+
from midas_civil import Node,Element,MidasAPI,nodeByID
|
|
260
|
+
if bSync:
|
|
261
|
+
Node.sync()
|
|
262
|
+
if bElement: Element.sync()
|
|
263
|
+
|
|
264
|
+
ptsXY = [(nd.X , nd.Y , nd.ID ) for nd in Node.nodes]
|
|
265
|
+
dist_range = 0.25*initial_align.TOTALLENGTH # 0.1 * total length
|
|
266
|
+
|
|
267
|
+
dist_array = [dist_range*0.5-i*dist_range/50 for i in range(51)] # 50 divisions
|
|
268
|
+
|
|
269
|
+
finalXY = []
|
|
270
|
+
for pt in ptsXY:
|
|
271
|
+
ptx = pt[0]
|
|
272
|
+
pty = pt[1]
|
|
273
|
+
|
|
274
|
+
if ptx < initial_align.PT_X[0]:
|
|
275
|
+
x_onLine1 = initial_align.PT_X[0]
|
|
276
|
+
y_onLine1 = initial_align.PT_Y[0]
|
|
277
|
+
slope_onLine1 = initial_align.ALIGNMENT(x_onLine1,1)
|
|
278
|
+
angle_onLine1 = np.atan(slope_onLine1)
|
|
279
|
+
|
|
280
|
+
dist = hypot(ptx-x_onLine1,pty-y_onLine1)
|
|
281
|
+
tangent_angleO = np.atan((pty-y_onLine1)/(ptx-x_onLine1)) # Radian theta
|
|
282
|
+
|
|
283
|
+
x_onLine2 = final_align.PT_X[0]
|
|
284
|
+
y_onLine2 = final_align.PT_Y[0]
|
|
285
|
+
slope_onLine2 = final_align.ALIGNMENT(x_onLine2,1)
|
|
286
|
+
angle_onLine2 = np.atan(slope_onLine2)
|
|
287
|
+
|
|
288
|
+
totalAngle = angle_onLine2-angle_onLine1+tangent_angleO
|
|
289
|
+
x_off = np.cos(totalAngle)
|
|
290
|
+
y_off = np.sin(totalAngle)
|
|
291
|
+
angle = np.degrees(angle_onLine2-angle_onLine1)
|
|
292
|
+
|
|
293
|
+
finalXY.append([x_onLine2-x_off*dist,y_onLine2-y_off*dist,angle])
|
|
294
|
+
|
|
295
|
+
elif ptx > initial_align.PT_X[-1]:
|
|
296
|
+
x_onLine1 = initial_align.PT_X[-1]
|
|
297
|
+
y_onLine1 = initial_align.PT_Y[-1]
|
|
298
|
+
slope_onLine1 = initial_align.ALIGNMENT(x_onLine1,1)
|
|
299
|
+
angle_onLine1 = np.atan(slope_onLine1)
|
|
300
|
+
|
|
301
|
+
dist = hypot(ptx-x_onLine1,pty-y_onLine1)
|
|
302
|
+
off = np.sign(pty-y_onLine1)*dist
|
|
303
|
+
tangent_angleO = np.atan((pty-y_onLine1)/(ptx-x_onLine1)) # Radian theta
|
|
304
|
+
|
|
305
|
+
x_onLine2 = final_align.PT_X[-1]
|
|
306
|
+
y_onLine2 = final_align.PT_Y[-1]
|
|
307
|
+
slope_onLine2 = final_align.ALIGNMENT(x_onLine2,1)
|
|
308
|
+
angle_onLine2 = np.atan(slope_onLine2)
|
|
309
|
+
|
|
310
|
+
totalAngle = angle_onLine2-angle_onLine1+tangent_angleO
|
|
311
|
+
|
|
312
|
+
x_off = np.cos(totalAngle)
|
|
313
|
+
y_off = np.sin(totalAngle)
|
|
314
|
+
angle = np.degrees(angle_onLine2-angle_onLine1)
|
|
315
|
+
|
|
316
|
+
finalXY.append([x_onLine2+x_off*dist,y_onLine2+y_off*dist,angle])
|
|
317
|
+
|
|
318
|
+
else:
|
|
319
|
+
x_onLine1 = np.add(ptx,dist_array)
|
|
320
|
+
y_onLine1 = initial_align.ALIGNMENT(x_onLine1)
|
|
321
|
+
|
|
322
|
+
sqDist = np.sum((np.array([ptx,pty]) - np.array(list(zip(x_onLine1,y_onLine1)))) ** 2, axis=1)
|
|
323
|
+
min_index = np.argmin(sqDist)
|
|
324
|
+
|
|
325
|
+
x_ref = x_onLine1[min_index]
|
|
326
|
+
y_ref = y_onLine1[min_index]
|
|
327
|
+
dist_ref = sqrt(sqDist[min_index])
|
|
328
|
+
|
|
329
|
+
final_u = np.interp(x_ref,initial_align.X_FINE,initial_align.U_FINE)
|
|
330
|
+
off = np.sign(pty-y_ref)*dist_ref
|
|
331
|
+
x2_interp = np.interp(final_u,final_align.U_FINE,final_align.X_FINE)
|
|
332
|
+
y2_interp = final_align.ALIGNMENT(x2_interp)
|
|
333
|
+
|
|
334
|
+
slope = final_align.ALIGNMENT(x2_interp,1) # Tan theta
|
|
335
|
+
norm = sqrt(1+slope*slope)
|
|
336
|
+
x_off = -slope/norm
|
|
337
|
+
y_off = 1/norm
|
|
338
|
+
|
|
339
|
+
angle = np.degrees(np.atan(slope))
|
|
340
|
+
|
|
341
|
+
finalXY.append([x2_interp+x_off*off,y2_interp+y_off*off,angle])
|
|
342
|
+
|
|
343
|
+
for i,nod in enumerate(Node.nodes):
|
|
344
|
+
nod.X , nod.Y , nod.TEMP_ANG = float(finalXY[i][0]),float(finalXY[i][1]),float(finalXY[i][2])
|
|
345
|
+
|
|
346
|
+
if bUpdateModel: Node.create()
|
|
347
|
+
|
|
348
|
+
#---------------- BLOCK START FOR VERTICAL ELEMENT -------------------------------------------
|
|
349
|
+
if bElement:
|
|
350
|
+
editedElemsJS = {"Assign":{}}
|
|
351
|
+
for elm in Element.elements:
|
|
352
|
+
if elm.TYPE in ['BEAM','TRUSS','TENSTR','COMPTR']:
|
|
353
|
+
if elm.LOCALX[0]==0 and elm.LOCALX[1]==0 :
|
|
354
|
+
elm.ANGLE += np.sign(elm.LOCALX[2])*nodeByID(elm.NODE[0]).TEMP_ANG
|
|
355
|
+
|
|
356
|
+
editedElemsJS["Assign"][elm.ID] = {"ANGLE":elm.ANGLE}
|
|
357
|
+
if bUpdateModel: MidasAPI("PUT","/db/ELEM",editedElemsJS)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
@staticmethod
|
|
362
|
+
def LineToPlate(nDiv:int = 10 , mSizeDiv:float = 0, bRigdLnk:bool=True , meshSize:float=0.5, elemList:list=None):
|
|
363
|
+
'''
|
|
364
|
+
Converts selected/entered line element to Shell elements
|
|
365
|
+
**nDiv** - No. of Division along the length of span
|
|
366
|
+
**mSizeDiv** - Division based on mesh size(in meter) along the length of span
|
|
367
|
+
division based on number -> **mSizeDiv = 0**
|
|
368
|
+
division based on meshSize(in meter) -> **nDiv = 0**
|
|
369
|
+
**bRigdLnk** - Whether to create Rigid links at the span ends
|
|
370
|
+
**meshSize** - Mesh size(in meter) of the plate elements
|
|
371
|
+
**elemList** - Element list which are to be converted . If None is passed, element are taken from selected elements in CIVIL NX
|
|
372
|
+
|
|
373
|
+
'''
|
|
374
|
+
from ._utilsFunc._line2plate import SS_create
|
|
375
|
+
SS_create(nDiv , mSizeDiv , bRigdLnk , meshSize ,elemList)
|
|
376
|
+
|
|
377
|
+
@staticmethod
|
|
378
|
+
def RC_Grillage(span_length = 20, width = 8, support:Literal['fix','pin']='fix', dia_no=2,start_loc = [0,0,0], girder_depth = 0, girder_width = 0, girder_no = 0,
|
|
379
|
+
web_thk = 0, slab_thk = 0, dia_depth = 0, dia_width = 0, overhang = 0, skew = 0, mat_E = 30_000_000):
|
|
380
|
+
|
|
381
|
+
"""
|
|
382
|
+
RC Grillage Utility wizard
|
|
383
|
+
Use Model.create() to create model in CIVIL NX
|
|
384
|
+
|
|
385
|
+
Parameters
|
|
386
|
+
----------
|
|
387
|
+
span_length : float, optional
|
|
388
|
+
Span length of the structure (default is 20).
|
|
389
|
+
width : float, optional
|
|
390
|
+
Overall deck width (default is 8).
|
|
391
|
+
support : {'fix', 'pin'}, optional
|
|
392
|
+
Support condition at the ends of the span.
|
|
393
|
+
'fix' for fixed support, 'pin' for pinned support (default is 'fix').
|
|
394
|
+
dia_no : int, optional
|
|
395
|
+
No of diaphragms (default is 2).
|
|
396
|
+
start_loc : list, optional
|
|
397
|
+
Start location for Grillage placement (default is [0,0,0]).
|
|
398
|
+
girder_depth : float, optional
|
|
399
|
+
Depth of the girder section (default is 0).
|
|
400
|
+
girder_width : float, optional
|
|
401
|
+
Width of the girder section (default is 0).
|
|
402
|
+
girder_no : int, optional
|
|
403
|
+
Number of girders in the system (default is 0).
|
|
404
|
+
web_thk : float, optional
|
|
405
|
+
Thickness of the girder web (default is 0).
|
|
406
|
+
slab_thk : float, optional
|
|
407
|
+
Thickness of the deck slab (default is 0).
|
|
408
|
+
dia_depth : float, optional
|
|
409
|
+
Depth of the diaphragm (default is 0).
|
|
410
|
+
dia_width : float, optional
|
|
411
|
+
Width of the diaphragm (default is 0).
|
|
412
|
+
overhang : float, optional
|
|
413
|
+
Overhang length beyond the outer girder (default is 0).
|
|
414
|
+
skew : float, optional
|
|
415
|
+
Skew angle of the structure in degrees (default is 0).
|
|
416
|
+
mat_E : float, optional
|
|
417
|
+
Modulus of elasticity of the material (default is 30,000,000).
|
|
418
|
+
"""
|
|
419
|
+
from midas_civil import Model,Material,Section,Offset,nodesInGroup,Element,Boundary,Load,elemsInGroup,Node
|
|
420
|
+
import math
|
|
421
|
+
|
|
422
|
+
Model.units()
|
|
423
|
+
|
|
424
|
+
cos_theta = math.cos(math.radians(skew))
|
|
425
|
+
tan_theta = math.tan(math.radians(skew))
|
|
426
|
+
nSec = len(Section.sect)
|
|
427
|
+
nMat = len(Material.mats)
|
|
428
|
+
|
|
429
|
+
# dia_no = 2
|
|
430
|
+
if span_length > 0 and width > 0:
|
|
431
|
+
#Data proofing and initial calcs:
|
|
432
|
+
if girder_depth == 0: girder_depth = max(1, round(span_length/20,3))
|
|
433
|
+
if girder_no == 0: girder_no = int(width/2)
|
|
434
|
+
if girder_width == 0: girder_width = width/girder_no
|
|
435
|
+
if slab_thk == 0: slab_thk = round(span_length/100,1)+0.05
|
|
436
|
+
if web_thk == 0: web_thk = round(girder_width/8,3)
|
|
437
|
+
if dia_depth == 0: dia_depth = girder_depth - slab_thk
|
|
438
|
+
if dia_width == 0: dia_width = web_thk
|
|
439
|
+
if dia_no <=1:
|
|
440
|
+
print("At least 2 diaphragms are required. No. of diaphragm is changed to 2.")
|
|
441
|
+
dia_no = 2
|
|
442
|
+
if dia_no >= 2:
|
|
443
|
+
overhang = max(overhang, dia_width/2)
|
|
444
|
+
cc_diaph = span_length / (dia_no - 1)
|
|
445
|
+
elem_len = round(cc_diaph / (round(cc_diaph,0)), 6)
|
|
446
|
+
if overhang > elem_len/2:
|
|
447
|
+
o_div = int(round(overhang/elem_len + 1, 0))
|
|
448
|
+
o_elem_len = overhang / o_div
|
|
449
|
+
if overhang > 0 and overhang <= elem_len/2:
|
|
450
|
+
o_div = 1
|
|
451
|
+
o_elem_len = overhang
|
|
452
|
+
if overhang == 0:
|
|
453
|
+
o_div = 0
|
|
454
|
+
o_elem_len = 0
|
|
455
|
+
|
|
456
|
+
Material.CONC.User('Concrete',mat_E,0.2,25,0,1.2e-5,id=nMat+1)
|
|
457
|
+
Material.CONC.User('Dummy',mat_E,0.2,0,0,1.2e-5,id=nMat+2)
|
|
458
|
+
|
|
459
|
+
if overhang > 0:
|
|
460
|
+
if o_div > 1:
|
|
461
|
+
Section.DBUSER(f"Overhang_Span{utils.__RC_Grillage_nSpan}",'SB',[slab_thk,o_elem_len*cos_theta],Offset('CT'),id=nSec+1)
|
|
462
|
+
Section.DBUSER(f"Start_Span{utils.__RC_Grillage_nSpan}",'SB',[slab_thk,o_elem_len*cos_theta/2],Offset('RT'),id=nSec+2)
|
|
463
|
+
Section.DBUSER(f"End_Span{utils.__RC_Grillage_nSpan}",'SB',[slab_thk,o_elem_len*cos_theta/2],Offset('LT'),id=nSec+3)
|
|
464
|
+
if dia_no >=2:
|
|
465
|
+
Section.DBUSER(f"Diap_Span{utils.__RC_Grillage_nSpan}",'SB',[dia_depth,dia_width*cos_theta],Offset('CT',UsrOffOpt=1,VOffOpt=1,VOffset=-slab_thk),id=nSec+4)
|
|
466
|
+
Section.DBUSER(f"T Beam_Span{utils.__RC_Grillage_nSpan}",'T',[girder_depth,girder_width,web_thk,slab_thk],Offset('CT'),id=nSec+5)
|
|
467
|
+
Section.DBUSER(f"Slab_Span{utils.__RC_Grillage_nSpan}",'SB',[slab_thk,elem_len*cos_theta],Offset('CT'),id=nSec+6)
|
|
468
|
+
Section.DBUSER(f"Slab_sup_st_Span{utils.__RC_Grillage_nSpan}",'SB',[slab_thk,(elem_len + o_elem_len)*cos_theta / 2],Offset('RT',UsrOffOpt=1,HOffOpt=1,HOffset=cos_theta*o_elem_len/2),id=nSec+7)
|
|
469
|
+
Section.DBUSER(f"Slab_sup_en_Span{utils.__RC_Grillage_nSpan}",'SB',[slab_thk,(elem_len + o_elem_len)*cos_theta / 2],Offset('LT',UsrOffOpt=1,HOffOpt=1,HOffset=cos_theta*o_elem_len/2),id=nSec+8)
|
|
470
|
+
|
|
471
|
+
Section.DBUSER("Dummy CB",'SB',[0.1,0.1],Offset('CC'),id=9)
|
|
472
|
+
|
|
473
|
+
offTrans = 0.5*width/girder_no
|
|
474
|
+
# Longitudinal
|
|
475
|
+
Element.Beam.SDL(np.add([0,0,0],start_loc),[1,0,0],span_length,int(span_length),nMat+2,9,group=f'CrashBarrier_R')
|
|
476
|
+
for i in range(girder_no):
|
|
477
|
+
Element.Beam.SDL(np.add([(2*i*offTrans+offTrans)*tan_theta,2*i*offTrans+offTrans,0],start_loc),[1,0,0],span_length,int(span_length),nMat+1,nSec+5,group=f'Girder {i+1} Span {utils.__RC_Grillage_nSpan}')
|
|
478
|
+
Boundary.Support(nodesInGroup(f'Girder {i+1} Span {utils.__RC_Grillage_nSpan}')[0],support,'Support')
|
|
479
|
+
Boundary.Support(nodesInGroup(f'Girder {i+1} Span {utils.__RC_Grillage_nSpan}')[-1],support,'Support')
|
|
480
|
+
Element.Beam.SDL(np.add([width*tan_theta,width,0],start_loc),[1,0,0],span_length,int(span_length),nMat+2,9,group=f'CrashBarrier_L')
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
spacing = span_length/int(span_length)
|
|
484
|
+
# Cross
|
|
485
|
+
Element.Beam.SE(start_loc,np.add([width*tan_theta,width,0],start_loc),2*girder_no,nMat+1,nSec+4,group='Diaphragm')
|
|
486
|
+
Element.Beam.SE(start_loc,np.add([width*tan_theta,width,0],start_loc),2*girder_no,nMat+2,nSec+7,group='CrossEnd')
|
|
487
|
+
for i in range(int(span_length)-1):
|
|
488
|
+
Element.Beam.SE(np.add([(i+1)*spacing,0,0],start_loc),np.add([(i+1)*spacing+width*tan_theta,width,0],start_loc),2*girder_no,nMat+2,nSec+6,group='Cross Slab')
|
|
489
|
+
|
|
490
|
+
Element.Beam.SE(np.add([span_length,0,0],start_loc),np.add([span_length+width*tan_theta,width,0],start_loc),2*girder_no,nMat+2,nSec+8,group='CrossEnd')
|
|
491
|
+
Element.Beam.SE(np.add([span_length,0,0],start_loc),np.add([span_length+width*tan_theta,width,0],start_loc),2*girder_no,nMat+1,nSec+4,group='Diaphragm')
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
# # Overhang
|
|
495
|
+
if o_elem_len!=0:
|
|
496
|
+
Element.Beam.SE(np.add([-o_elem_len,0,0],start_loc),np.add([width*tan_theta-o_elem_len,width,0],start_loc),2*girder_no,nMat+2,nSec+2)
|
|
497
|
+
Element.Beam.SE(np.add([span_length+o_elem_len,0,0],start_loc),np.add([width*tan_theta+span_length+o_elem_len,width,0],start_loc),2*girder_no,nMat+2,nSec+3)
|
|
498
|
+
|
|
499
|
+
Element.Beam.SDL(np.add([-o_elem_len,0,0],start_loc),[1,0,0],o_elem_len,1,nMat+2,9,group=f'CrashBarrier_R')
|
|
500
|
+
Element.Beam.SDL(np.add([span_length,0,0],start_loc),[1,0,0],o_elem_len,1,nMat+2,9,group=f'CrashBarrier_R')
|
|
501
|
+
for i in range(girder_no):
|
|
502
|
+
Element.Beam.SDL(np.add([-o_elem_len+(2*i*offTrans+offTrans)*tan_theta,2*i*offTrans+offTrans,0],start_loc),[1,0,0],o_elem_len,1,nMat+1,nSec+5,group=f'Girder {i+1}')
|
|
503
|
+
Element.Beam.SDL(np.add([span_length+(2*i*offTrans+offTrans)*tan_theta,2*i*offTrans+offTrans,0],start_loc),[1,0,0],o_elem_len,1,nMat+1,nSec+5,group=f'Girder {i+1}')
|
|
504
|
+
Element.Beam.SDL(np.add([-o_elem_len+width*tan_theta,width,0],start_loc),[1,0,0],o_elem_len,1,nMat+2,9,group=f'CrashBarrier_L')
|
|
505
|
+
Element.Beam.SDL(np.add([span_length+width*tan_theta,width,0],start_loc),[1,0,0],o_elem_len,1,nMat+2,9,group=f'CrashBarrier_L')
|
|
506
|
+
|
|
507
|
+
# extra diaphragm
|
|
508
|
+
span_idx = list(range(int(span_length+1)))
|
|
509
|
+
|
|
510
|
+
if dia_no > 2:
|
|
511
|
+
for i in range(dia_no-2):
|
|
512
|
+
Element.Beam.SE(np.add([span_idx[int((i+1)*span_length/(dia_no-1))]*spacing,0,0],start_loc),np.add([span_idx[int((i+1)*span_length/(dia_no-1))]*spacing+width*tan_theta,width,0],start_loc),2*girder_no,nMat+2,nSec+4,group='Diaphragm')
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
Load.SW('Self Weight',load_group='Self Weight')
|
|
517
|
+
|
|
518
|
+
# WCloading = -1.9
|
|
519
|
+
WCloading = -22 * 0.075 * cos_theta
|
|
520
|
+
Load.Beam(elemsInGroup('Cross Slab'),'Wearing Course','Wearing Course',WCloading)
|
|
521
|
+
Load.Beam(elemsInGroup('CrossEnd'),'Wearing Course','Wearing Course',WCloading*0.5)
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
CBloading = -22 * 0.5
|
|
525
|
+
Load.Beam(elemsInGroup(['CrashBarrier_R','CrashBarrier_L']),'Crash Barrier','Crash Barrier',CBloading)
|
|
526
|
+
|
|
527
|
+
utils.__RC_Grillage_nSpan+=1
|
|
528
|
+
#---------------------------------------------------------------------------------------
|
|
529
|
+
# Model.create()
|
|
File without changes
|