mrfhelper 1.2__tar.gz

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.
@@ -0,0 +1,42 @@
1
+ from . import func
2
+
3
+
4
+ class BuildingGeometry:
5
+
6
+ def __init__(self):
7
+ """Step-1:
8
+ Building geometry parameters
9
+
10
+ Properties:
11
+ * story_height (tuple): Story_height
12
+ * bay_length (tuple): Bay_length
13
+ * plan_dimensions (tuple): (main direction, secondary direction)
14
+ * MF_number (int): Number of moment frame
15
+ * exterior_column_tributary_area (tuple): (x, y), area = x * y
16
+ * interior_column_tributary_area (tuple): (x, y), area = x * y
17
+ """
18
+ self.story_height = None
19
+ self.bay_length = None
20
+ self.plane_dimensions = None
21
+ self.exterior_column_tributary_area = None
22
+ self.interior_column_tributary_area = None
23
+ self.MF_number = None
24
+
25
+ def _check(self):
26
+ func.check_list(self.story_height, min_length=1, max_length=98, name='story')
27
+ func.check_list(self.bay_length, min_length=1, max_length=98, name='story')
28
+ func.check_tuple(self.plane_dimensions, 2, name='plan_dimensions')
29
+ func.check_int(self.MF_number, [1, 99], name='MF_number')
30
+ func.check_tuple(self.exterior_column_tributary_area, 2, name='exterior_column_tributary_area')
31
+ func.check_tuple(self.interior_column_tributary_area, 2, name='exterior_column_tributary_area')
32
+
33
+ def _finish(self):
34
+ """Complete the definition of building geometry parameters"""
35
+ self._check()
36
+ self.N = len(self.story_height)
37
+ self.bays = len(self.bay_length)
38
+ self.axis = self.bays + 1
39
+ self.building_height = sum(self.story_height)
40
+
41
+
42
+
@@ -0,0 +1,78 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING
3
+ if TYPE_CHECKING:
4
+ from .MRFhelper import Frame
5
+ from . import func
6
+ from typing import Literal
7
+
8
+
9
+ class ConnectionAndBoundary:
10
+
11
+ def __init__(self, frame: Frame) -> None:
12
+ """Step-4:
13
+ Connection and boundary condition
14
+ """
15
+ self.frame = frame
16
+ self.base_support = 'Fixed'
17
+ self.beam_column_connection = 'Full'
18
+ self.RBS_paras = (0.625, 0.75, 0.25)
19
+ self.panel_zone_deformation = True
20
+ self.soil_constraint = []
21
+ self.rigid_disphragm = True
22
+
23
+
24
+ def set_base_support(self, type: Literal['Fixed', 'Pinned']='Fixed'):
25
+ """Defined column base support
26
+
27
+ Args:
28
+ type (str, optional):
29
+ * "Fixed": Full constrained conncetion
30
+ * "Pinned", Pinned connection
31
+ """
32
+ func.check_string(type, ['Fixed', 'Pinned'], 'type')
33
+ self.base_support = type
34
+
35
+
36
+ def set_beam_column_connection(self, type: Literal['Full', 'RBS', 'Hinged']='Full', a=0.625, b=0.75, c=0.25):
37
+ """Define beam to column connection
38
+
39
+ Args:
40
+ type (str, optional):
41
+ * "Full" - Full restrained
42
+ * "RBS" - Reduced beam section
43
+ * "Hinged" - Hinged connection
44
+
45
+ a, b, c: RBS parameters, default to 0.625, 0.75, and 0.25, respectively
46
+ """
47
+ func.check_int_float(a, [0, 10], name='a')
48
+ func.check_int_float(b, [0, 10], name='b')
49
+ func.check_int_float(c, [0, 1], name='c')
50
+ func.check_string(type, ['Full', 'RBS', 'Hinged'], 'type')
51
+ self.beam_column_connection = type
52
+ self.RBS_paras = (a, b, c)
53
+
54
+
55
+ def set_panel_zone_deformation(self, type: Literal[True, False]=True):
56
+ """Define whether the panel zone deformation is consdiered
57
+
58
+ Args:
59
+ type (bool, optional):
60
+ * True - Use a parrallelogram model
61
+ * False - Use a cruciform model
62
+ """
63
+ func.check_boolean(type, name='type')
64
+ self.panel_zone_deformation = type
65
+
66
+ def set_soil_constraint(self, floor: int):
67
+ """Set soil constraint at specified floor
68
+
69
+ Args:
70
+ floor (int): floor number with soil constraint
71
+ """
72
+ func.check_int(floor, [1, self.frame.N + 1])
73
+ if floor not in self.soil_constraint:
74
+ self.soil_constraint.append(floor)
75
+
76
+
77
+ def _finished(self):
78
+ pass
@@ -0,0 +1,282 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING
3
+ if TYPE_CHECKING:
4
+ from .MRFhelper import Frame
5
+ import numpy as np
6
+ from . import func
7
+
8
+
9
+ class LoadAndMaterial:
10
+ g = 9800
11
+
12
+ def __init__(self, frame: Frame) -> None:
13
+ self.N = frame.N
14
+ self.bays = frame.bays
15
+ self.axis = frame.axis
16
+ self.dead_load = dict()
17
+ self.live_load = dict()
18
+ self.cladding_load = dict()
19
+ self.E = 206000 # Necessary
20
+ self.fy_beam = None # Necessary
21
+ self.fy_column = None # Necessary
22
+ self.miu = 0.3 # Unnecessary
23
+ self.cc_weight = {'Dead': 1.05, 'Live': 0.25, 'Cladding': 1.05} # Combination coefficients of seismic weight, necessary
24
+ self.cc_mass = {'Dead': 1, 'Live': 0, 'Cladding': 1} # Combination coefficients of seismic mass, necessary
25
+ for floor in range(2, frame.N + 2):
26
+ self.dead_load[floor] = 1e-9
27
+ self.live_load[floor] = 1e-9
28
+ self.cladding_load[floor - 1] = 1e-9
29
+
30
+
31
+ def set_dead_load(self, floor: list[int], load_per_area: list[int | float]):
32
+ """Step-3:
33
+ Set dead load for each floor
34
+
35
+ Args:
36
+ floor (list[int]): Numbers of floor
37
+ load_per_area (list[int | float]): Values of dead load (surface load)
38
+ """
39
+ func.check_list(floor, length=self.N, name='floor')
40
+ for val in floor:
41
+ func.check_int(val, [2, self.N + 1], name='floor')
42
+ func.check_list(load_per_area, length=self.N, name='load_per_area')
43
+ for _, (a, b) in enumerate(zip(floor, load_per_area)):
44
+ self.dead_load[a] = b
45
+
46
+
47
+ def set_live_load(self, floor: list[int], load_per_area: list[int | float]):
48
+ """Set live load for each floor
49
+
50
+ Args:
51
+ floor (list[int]): Numbers of floor
52
+ load_per_area (list[int | float]): Values of live load (surface load)
53
+ """
54
+ func.check_list(floor, length=self.N, name='floor')
55
+ for val in floor:
56
+ func.check_int(val, [2, self.N + 1], name='floor')
57
+ func.check_list(load_per_area, length=self.N, name='load')
58
+ for _, (a, b) in enumerate(zip(floor, load_per_area)):
59
+ self.live_load[a] = b
60
+
61
+
62
+ def set_cladding_load(self, story: list[int], load_per_area: list[int | float]):
63
+ """Set cladding load for each story
64
+
65
+ Args:
66
+ story (list[int]): Numbers of story
67
+ load_per_area (list[int | float]): Values of cladding load (surface load)
68
+ """
69
+ func.check_list(story, length=self.N, name='story')
70
+ for val in story:
71
+ func.check_int(val, [1, self.N], name='story')
72
+ func.check_list(load_per_area, length=self.N, name='load')
73
+ for _, (a, b) in enumerate(zip(story, load_per_area)):
74
+ self.cladding_load[a] = b
75
+
76
+
77
+ def set_material(self, E: int | float, fy_beam: int | float, fy_column: int | float, miu: float=0.3):
78
+ """Set material properties for all steel components
79
+
80
+ Args:
81
+ E (int | float): Youngs modulus
82
+ fy_beam (int | float): Nominal yield strength of beams
83
+ fy_column (int | float): Nominal yield strength of column
84
+ miu (float, optional): possion ratio
85
+ """
86
+ func.check_int_float(E, name='E')
87
+ func.check_int_float(fy_beam, name='fy_beam')
88
+ func.check_int_float(fy_column, name='fy_column')
89
+ func.check_int_float(miu, [0, 0.5], name='miu')
90
+ self.E = E
91
+ self.fy_beam = fy_beam
92
+ self.fy_column = fy_column
93
+ self.miu = miu
94
+
95
+
96
+ def set_weight_combination_coefficients(self, coefficients: dict):
97
+ """Set seicmic weight combination coefficients
98
+ Note: Load type should be within ['Dead', 'Live', 'Cladding']
99
+
100
+ Args:
101
+ coefficients (dict): {load type: combination coefficient}
102
+ """
103
+ func.check_dict(coefficients, name='coefficients')
104
+ for key, val in coefficients.items():
105
+ if not key in ['Dead', 'Live', 'Cladding']:
106
+ raise ValueError("Load type should be within ['Dead', 'Live', 'Cladding']")
107
+ func.check_int_float(val, name='coefficient')
108
+ self.cc_weight[key] = val
109
+
110
+
111
+ def set_mass_combination_coefficients(self, coefficients: dict):
112
+ """Set seicmic mass combination coefficients
113
+ Note: Load type should be within ['Dead', 'Live', 'Cladding']
114
+
115
+ Args:
116
+ coefficients (dict): {load type: combination coefficient}
117
+ """
118
+ func.check_dict(coefficients, name='coefficients')
119
+ for key, val in coefficients.items():
120
+ if not key in ['Dead', 'Live', 'Cladding']:
121
+ raise ValueError("Load type should be within ['Dead', 'Live', 'Cladding']")
122
+ func.check_int_float(val, name='coefficient')
123
+ self.cc_mass[key] = val
124
+
125
+
126
+ def _finished(self):
127
+ if self.E is None:
128
+ raise ValueError("Young's modulus has not been difined")
129
+ if self.fy_beam is None:
130
+ raise ValueError("Nominal yield strength of beams has not been difined")
131
+ if self.fy_column is None:
132
+ raise ValueError("Nominal yield strength of columns has not been difined")
133
+ if not self.cc_weight:
134
+ raise ValueError("Combination coefficients of seismic weight have not been difined")
135
+ if not self.cc_mass:
136
+ raise ValueError("Combination coefficients of seismic mass have not been difined")
137
+ floor_set = set([2 + i for i in range(self.N)])
138
+ floor_defined_dead = set(self.dead_load.keys())
139
+ floor_defined_live = set(self.live_load.keys())
140
+ if floor_set == floor_defined_dead:
141
+ return
142
+ if floor_set - floor_defined_dead:
143
+ raise ValueError(f'Dead load for floor {floor_set - floor_defined_dead} have not been defined')
144
+ if floor_defined_dead - floor_set:
145
+ raise ValueError(f'Floor {floor_defined_dead - floor_set} are not existed')
146
+ if floor_set - floor_defined_live:
147
+ raise ValueError(f'Dead load for floor {floor_set - floor_defined_live} have not been defined')
148
+ if floor_defined_live - floor_set:
149
+ raise ValueError(f'Floor {floor_defined_live - floor_set} are not existed')
150
+ self._calculate_load()
151
+
152
+
153
+ def _calculate_load(self, frame: Frame):
154
+ """Calculate load and mass
155
+ * F_node (dict): Beam-column joint force ({floor: force})
156
+ * F_grav (dect): Leaning column joint force ({floor: force})
157
+ * mass_node (dict): Beam-column joint mass ({floor: mass})
158
+ * mass_grav (dect): Leaning column joint mass ({floor: mass})
159
+ """
160
+ plane_dimensions = frame.BuildingGeometry.plane_dimensions
161
+ N_MF = frame.BuildingGeometry.MF_number
162
+ area_ex = frame.BuildingGeometry.exterior_column_tributary_area
163
+ area_in = frame.BuildingGeometry.interior_column_tributary_area
164
+ h_list = frame.BuildingGeometry.story_height
165
+ # dead load
166
+ DL_node = dict()
167
+ DL_grav = dict()
168
+ S_3D = plane_dimensions[0] * plane_dimensions[1] # area of 3D building plane
169
+ for floor, DL_value in self.dead_load.items():
170
+ DL_3D = S_3D * DL_value # Dead load (N) for each floor of the 3D building
171
+ DL = DL_3D / N_MF # Dead load (N) for each floor of the 2D considered frame
172
+ r_rest = 1
173
+ DL_floor = []
174
+ for id_axis in range(self.axis):
175
+ if id_axis == 0 or id_axis == self.axis - 1:
176
+ r = area_ex[0] * area_ex[1] / (S_3D / N_MF) # area ratio for external columns
177
+ else:
178
+ r = area_in[0] * area_in[1] / (S_3D / N_MF) # area ratio for internal columns
179
+ r_rest -= r
180
+ DL_floor.append(DL * r)
181
+ DL_grav[floor] = DL * r_rest
182
+ DL_node[floor] = DL_floor
183
+ # live load (same as the dead load)
184
+ LL_node = dict()
185
+ LL_grav = dict()
186
+ S_3D = plane_dimensions[0] * plane_dimensions[1] # area of 3D building plane
187
+ for floor, LL_value in self.live_load.items():
188
+ LL_3D = S_3D * LL_value # Dead load (N) for each floor of the 3D building
189
+ LL = LL_3D / N_MF # Dead load (N) for each floor of the 2D considered frame
190
+ r_rest = 1
191
+ LL_floor = []
192
+ for id_axis in range(self.axis):
193
+ if id_axis == 0 or id_axis == self.axis - 1:
194
+ r = area_ex[0] * area_ex[1] / (S_3D / N_MF) # area ratio for external columns
195
+ else:
196
+ r = area_in[0] * area_in[1] / (S_3D / N_MF) # area ratio for internal columns
197
+ r_rest -= r
198
+ LL_floor.append(LL * r)
199
+ LL_grav[floor] = LL * r_rest
200
+ LL_node[floor] = LL_floor
201
+ # cladding load
202
+ CL_node = dict()
203
+ CL_grav = dict()
204
+ for story, CL_value in self.cladding_load.items():
205
+ floor = story + 1
206
+ story_b, story_t = floor - 1, floor # story number
207
+ CL_floor = []
208
+ h = h_list[story_b-1]/2 if floor==self.N+1 else (h_list[story_b-1] + h_list[story_t-1])/2 # tributary heigth of each floor
209
+ S_rest = plane_dimensions[0] * h
210
+ for id_axis in range(self.axis):
211
+ if id_axis == 0 or id_axis == self.axis - 1: # if external node
212
+ if floor == self.N + 1: # if top floor
213
+ S_node = area_ex[0] * h_list[story_b-1] / 2 # Node tributary facade area
214
+ else:
215
+ S_node = area_ex[0] * (h_list[story_b-1] + h_list[story_t-1]) / 2 # Node tributary facade area
216
+ else:
217
+ if floor == self.N + 1: # if top floor
218
+ S_node = area_in[0] * h_list[story_b-1] / 2 # Node tributary facade area
219
+ else:
220
+ S_node = area_in[0] * (h_list[story_b-1] + h_list[story_t-1]) / 2 # Node tributary facade area
221
+ S_rest -= S_node
222
+ CL_floor.append(S_node * CL_value)
223
+ CL_node[floor] = CL_floor
224
+ CL_grav[floor] = S_rest * CL_value + plane_dimensions[1] * h * CL_value # Consider the Y-direction cladding load
225
+ # CL_grav[floor] = S_rest * CL_value # TODO Did not consider the Y-direction cladding load
226
+ # node force
227
+ F_node = dict()
228
+ F_grav = dict()
229
+ mass_node = dict()
230
+ mass_grav = dict()
231
+ for floor in range(2, 2 + self.N):
232
+ DL_floor = np.array(DL_node[floor])
233
+ LL_floor = np.array(LL_node[floor])
234
+ CL_floor = np.array(CL_node[floor])
235
+ F_floor = DL_floor * self.cc_weight['Dead'] + LL_floor * self.cc_weight['Live'] + CL_floor + self.cc_weight['Cladding']
236
+ mass_floor = (DL_floor * self.cc_mass['Dead'] + LL_floor * self.cc_mass['Live'] + CL_floor + self.cc_mass['Cladding']) / self.g
237
+ F_floor = list(F_floor)
238
+ mass_floor = list(mass_floor)
239
+ F_node[floor] = F_floor
240
+ mass_node[floor] = mass_floor
241
+ F_grav[floor] = DL_grav[floor] * self.cc_weight['Dead'] + LL_grav[floor] * self.cc_weight['Live'] + CL_grav[floor] * self.cc_weight['Cladding']
242
+ mass_grav[floor] = (DL_grav[floor] * self.cc_mass['Dead'] + LL_grav[floor] * self.cc_mass['Live'] + CL_grav[floor] * self.cc_mass['Cladding']) / self.g
243
+ # TODO Beam and column component masses have not been considered, but FM2D also did not consider.
244
+ self.F_node, self.F_grav, self.mass_node, self.mass_grav = F_node, F_grav, mass_node, mass_grav
245
+
246
+
247
+ def _calculate_PPy(self, frame: Frame, PPy_scale: float=1.25):
248
+ """Calculate the axial compression ratio of columns
249
+ * PPy (dict): Compression ratio ({story: ratio})
250
+ * PPy_scale (float): Scale factor of compression ratio to consider the overturning effect,
251
+ defaults to 1.25
252
+
253
+ Args:
254
+ PPy_scale (float, optional): Scale factor of compression ratio, defaults to 1.25.
255
+ """
256
+ props_col = frame.StructuralComponents.column_properties
257
+ P_col = dict() # Axial forces of columns
258
+ P_temp = np.zeros(self.axis)
259
+ for story in list(1+i for i in range(self.N))[::-1]:
260
+ floor = story + 1
261
+ P_temp += np.array(self.F_node[floor])
262
+ P_col[story] = P_temp.tolist()
263
+ PPy = dict() # Column axial compression ratio
264
+ for story in range(1, self.N + 1):
265
+ prop_floor = props_col[story] # column properties for each story
266
+ PPy_story_b, PPy_story_t = [], []
267
+ for axis in range(1, self.axis + 1):
268
+ id_axis = axis - 1
269
+ A = prop_floor[id_axis][5] # Cross section aera of column
270
+ P = P_col[story][id_axis] # Axial force of column
271
+ PPy_story_b.append(P / (A * self.fy_column)) # Axial compression ratio of columns on the story
272
+ if story not in frame.StructuralComponents.column_splice:
273
+ PPy_story_t.append(P / (A * self.fy_column)) # Axial compression ratio of columns on the story
274
+ else:
275
+ A_t = props_col[story+1][id_axis][5] # Cross section aera of column
276
+ PPy_story_t.append(P / (A_t * self.fy_column)) # Axial compression ratio of columns on the story
277
+ PPy[f'{story}b'] = PPy_story_b
278
+ PPy[f'{story}t'] = PPy_story_t
279
+ self.PPy, self.PPy_scale = PPy, PPy_scale
280
+
281
+
282
+
@@ -0,0 +1,138 @@
1
+ import json
2
+ from pathlib import Path
3
+ from .BuildingGeometry import BuildingGeometry
4
+ from .StructuralComponents import StructuralComponents
5
+ from .ConnectionAndBoundary import ConnectionAndBoundary
6
+ from .LoadAndMaterial import LoadAndMaterial
7
+ from .UserCommand import UserCommand
8
+ from . import WriteInfo
9
+ from . import WriteScript
10
+
11
+
12
+ VERSION = '2.0'
13
+
14
+ class Frame:
15
+ version = VERSION
16
+
17
+ def __init__(self, frame_name: str, notes: str=None):
18
+ """Use this class to define structural parameters of steel moment resisting frame (MRF)
19
+ and write tcl script for analysis using OpenSees. Make sure all the units are [N, mm, t].
20
+
21
+ Args:
22
+ frame_name (str): Give a name for the considered frame
23
+ notes (str, optional): Optional notes
24
+ """
25
+ if not frame_name.isidentifier():
26
+ raise ValueError(f'Illegal frame name: {frame_name}')
27
+ self.frame_name = frame_name
28
+ self.notes = notes
29
+ self.BuildingGeometry = BuildingGeometry()
30
+
31
+ def step1_finished(self):
32
+ """Complete define building geometry"""
33
+ self.BuildingGeometry._finish()
34
+ self.N = self.BuildingGeometry.N # number of stories
35
+ self.bays = self.BuildingGeometry.bays # number of bays
36
+ self.axis = self.BuildingGeometry.axis # number of axes
37
+ self.StructuralComponents = StructuralComponents(self)
38
+
39
+ def step2_finished(self):
40
+ """Complete define structural components"""
41
+ self.StructuralComponents._finish()
42
+ self.LoadAndMaterial = LoadAndMaterial(self)
43
+
44
+ def step3_finished(self):
45
+ """Complete define load and material"""
46
+ self.LoadAndMaterial._finished()
47
+ self.ConnectionAndBoundary = ConnectionAndBoundary(self)
48
+
49
+ def step4_finished(self):
50
+ """Complete define connection and boundary"""
51
+ self.ConnectionAndBoundary._finished()
52
+ self.recorders = {
53
+ 'Reactions': True,
54
+ 'Drift': True,
55
+ 'FloorAccel': True,
56
+ 'FloorVel': True,
57
+ 'FloorDisp': True,
58
+ 'ColumnForce': True,
59
+ 'ColumnHinge': True,
60
+ 'BeamHinge': True,
61
+ 'PanelZone': True
62
+ }
63
+ self.UserComment = UserCommand()
64
+
65
+ def all_steps_finished(self):
66
+ """Calculate simulation parameters and write them into tcl script"""
67
+ self.StructuralComponents._get_section_properties(self)
68
+ self.StructuralComponents._get_panel_zone_thickness()
69
+ self.LoadAndMaterial._calculate_load(self)
70
+ self.LoadAndMaterial._calculate_PPy(self)
71
+ self.dict_info = WriteInfo.write_info_to_dict(self)
72
+
73
+ def generate_tcl_script(self, dir_):
74
+ """Write tcl script"""
75
+ self.output_path = Path(dir_)
76
+ if not self.output_path.exists():
77
+ Path.mkdir(self.output_path)
78
+ self.builiding_info = WriteInfo.write_info_to_tcl(self)
79
+ WriteScript.WriteScript(self)
80
+
81
+
82
+ def from_json(file: str | Path) -> Frame:
83
+ """Get an available model from json file
84
+
85
+ Args:
86
+ file (str | Path): file path
87
+
88
+ Returns:
89
+ Frame: Object of `Frame`
90
+ """
91
+ file = Path(file)
92
+ if not file.exists():
93
+ raise FileExistsError(f'file not found')
94
+ with open(file, 'r') as f:
95
+ dict_info = json.load(f)
96
+ frame = Frame(dict_info['name'])
97
+ # Step 1
98
+ frame.BuildingGeometry.story_height = dict_info['BuildingGeometry']['story_height']
99
+ frame.BuildingGeometry.bay_length = dict_info['BuildingGeometry']['bay_length']
100
+ frame.BuildingGeometry.plane_dimensions = tuple(dict_info['BuildingGeometry']['plane_dimensions'])
101
+ frame.BuildingGeometry.MF_number = dict_info['BuildingGeometry']['MF_number']
102
+ frame.BuildingGeometry.exterior_column_tributary_area = tuple(dict_info['BuildingGeometry']['exterior_column_tributary_area'])
103
+ frame.BuildingGeometry.interior_column_tributary_area = tuple(dict_info['BuildingGeometry']['interior_column_tributary_area'])
104
+ frame.step1_finished()
105
+ # Step 2
106
+ for FF, sections in dict_info['StructuralComponents']['beams'].items():
107
+ frame.StructuralComponents.set_beams(int(FF), sections)
108
+ for SS, sections in dict_info['StructuralComponents']['columns'].items():
109
+ frame.StructuralComponents.set_columns(int(SS), sections)
110
+ for FF, thickness in dict_info['StructuralComponents']['set_doubler_plate'].items():
111
+ frame.StructuralComponents.set_doubler_plate(int(FF), thickness)
112
+ frame.StructuralComponents.set_column_splice(*dict_info['StructuralComponents']['column_splice'])
113
+ frame.StructuralComponents.set_beam_splice(*dict_info['StructuralComponents']['beam_splice'])
114
+ if dict_info['StructuralComponents']['RBS_length']:
115
+ frame.StructuralComponents.set_RBS_length(dict_info['StructuralComponents']['RBS_length'])
116
+ frame.step2_finished()
117
+ # Step 3
118
+ FF_ls = list(int(i) for i in dict_info['LoadAndMaterial']['dead_load'].keys())
119
+ SS_ls = list(int(i) for i in dict_info['LoadAndMaterial']['clading_load'].keys())
120
+ frame.LoadAndMaterial.set_dead_load(FF_ls, list(dict_info['LoadAndMaterial']['dead_load'].values()))
121
+ frame.LoadAndMaterial.set_live_load(FF_ls, list(dict_info['LoadAndMaterial']['live_load'].values()))
122
+ frame.LoadAndMaterial.set_cladding_load(SS_ls, list(dict_info['LoadAndMaterial']['clading_load'].values()))
123
+ frame.LoadAndMaterial.set_weight_combination_coefficients(dict_info['LoadAndMaterial']['weight_combination_coefficients'])
124
+ frame.LoadAndMaterial.set_mass_combination_coefficients(dict_info['LoadAndMaterial']['mass_combination_coefficients'])
125
+ material = dict_info['LoadAndMaterial']['material']
126
+ frame.LoadAndMaterial.set_material(material['E'], material["fy_beam"], material["fy_column"], material["miu"])
127
+ frame.step3_finished()
128
+ # Step 4
129
+ frame.ConnectionAndBoundary.set_base_support(dict_info['ConnectionAndBoundary']['base_support'])
130
+ frame.ConnectionAndBoundary.set_beam_column_connection(dict_info['ConnectionAndBoundary']['beam_column_connection'])
131
+ frame.ConnectionAndBoundary.set_panel_zone_deformation(dict_info['ConnectionAndBoundary']['panel_zone_deformation'])
132
+ if dict_info['ConnectionAndBoundary']['soil_constraint']:
133
+ frame.ConnectionAndBoundary.set_soil_constraint(dict_info['ConnectionAndBoundary']['soil_constraint'])
134
+ frame.step4_finished()
135
+ # finish
136
+ frame.all_steps_finished()
137
+ frame.dict_info['References'] = dict_info['References']
138
+ return frame