paint-brush
Python과 Viktor를 사용하여 강철 베이스 플레이트 디자인 웹 앱을 만드는 방법~에 의해@kamalsamaila
660 판독값
660 판독값

Python과 Viktor를 사용하여 강철 베이스 플레이트 디자인 웹 앱을 만드는 방법

~에 의해 Kamal samaila18m2024/05/06
Read on Terminal Reader

너무 오래; 읽다

이 기사에서는 기둥 하중을 기초에 안전하게 전달하는 데 필수적인 강철 베이스 플레이트를 설계하기 위한 Python 기반 애플리케이션을 만드는 과정을 안내합니다. T-stub 방법을 사용하여 베이스 플레이트 면적, 두께, 콘크리트 지지 강도 및 추가 폭을 계산하는 방법을 다룹니다. 그런 다음 Python 코드는 Viktor SDK를 사용하여 웹 앱으로 변환되므로 엔지니어는 매개변수를 입력하고 구조의 3D 모델을 시각화할 수 있습니다. 이 효율적인 도구는 베이스플레이트 설계의 정확성을 높이고 모바일 장치를 통한 현장 점검을 용이하게 하여 건설 작업 흐름을 간소화합니다.
featured image - Python과 Viktor를 사용하여 강철 베이스 플레이트 디자인 웹 앱을 만드는 방법
Kamal samaila HackerNoon profile picture

소개

강철 베이스 플레이트는 강철 기둥 아래에 배치되어 설계 하중을 기초에 안전하게 전달합니다.


철골기둥이 단면적이 작고 큰 하중을 받는 경우 기초에 직접 하중을 가하면 펀칭 불량이 발생할 수 있습니다. 따라서 더 넓은 영역에 하중을 분산하려면 기둥 아래에 베이스 플레이트를 사용하는 것이 중요합니다.


이 기사에서는 CSV 형식으로 저장된 철강 기하학적 속성을 활용하여 Python을 사용하여 베이스플레이트 설계 애플리케이션을 생성하기 위한 가이드를 제공합니다.


이 애플리케이션은 엔지니어가 필요한 베이스 플레이트 면적, 두께, 콘크리트 지지력 및 추가 폭을 쉽게 결정하는 데 도움이 됩니다.


또한 Viktor SDK를 활용하면 Python 구현을 웹 애플리케이션으로 원활하게 변환할 수 있습니다.


이 SDK는 구조를 3D 보기로 시각화하는 기능을 제공합니다. 바로 뛰어들어 조치를 취합시다!

베이스플레이트 설계의 기본원리

베이스 플레이트 설계에서는 축력에 대해 등가 T-스터브 방법을 사용합니다. 여기서 '유효 면적'은 압축 상태의 T-스터브에 대해 계산되고 베이스 플레이트 굽힘은 인장 상태의 T-스터브에 대해 평가됩니다. 수평 주요 및/또는 작은 전단은 허용되지만 모멘트는 허용되지 않습니다. 즉, 고정된 베이스 설계입니다.

우리가 계산한 첫 번째 것은 지지 콘크리트의 지지 강도 fjd입니다.

베이스 플레이트 밑면과 그라우트 공간의 기초 재료 사이의 설계 지지 강도 fjd는 다음과 같습니다.


fjd = βj * α * fcd

어디


βj = 기초 접합재료 계수 = (2/3)


α = 기초 내 집중된 힘의 확산을 설명하는 계수


fcd = 설계값 콘크리트 압축강도 = αcc * fck / ɣc


αcc = 장기 효과에 대한 계수


fck = 콘크리트 특성 실린더 강도


ɣc = 콘크리트의 부분 안전계수

두 번째 단계는 다음 공식으로 제공되는 필요한 베이스플레이트 면적을 계산하는 것입니다.

Areq = 네드 / fjd

여기서 Ned는 강철 기둥의 최종 하중입니다.

세 번째 단계는 유효 면적에서 벗어난 캔틸레버인 c를 계산하는 것입니다.

C는 아래 공식을 사용하여 계산됩니다.

Aeff = 4 *( c**2) + Pcol * c + Acol


따라서 c에 대해 해결합니다.


마지막으로 베이스플레이트의 두께 tp를 계산합니다.

tp = c * (3 * fjd* Ym0 / _page_fy)**0.50

베이스플레이트 설계 워크플로의 Python 구현

 # Partial factor of resistance of cross-sections whatever the class is as per EN 1993-1-1. Ym0 = 1.0 # Compute foundation bearing strength which is typically concrete #βj is the foundation joint material coefficient, typically taken as 0.67 as per clause 6.2.5(7) in EN 1993-1-8. beta_j=0.67 #α is a coefficient of diffusion of the vertical load being applied to the foundation. Conservatively this can be taken as 1.5 alpha= 1.5 # αcc is the coefficient that allows for long-term effects on the compressive strength of concrete vs applied actions. Taken as 0.85 in the UK National Annex -> on page # Define alpha_cc # Define gamma_c # define fck # γc is the partial factor of safety of concrete. Taken as 1.5 in the UK National Annex -> on page fjd = beta_j*alpha* (alpha_cc*fck )/gamma_c # Compute the area of the baseplate required Areq = (Ned *1000)/ fjd #Ned is the Ultimate load def calculate_c(Pcol, Acol, Areq): # """ # This function calculates the value of c for the given equation: # Areq = 4 * c^2 + P_col * c + A_col # Args: # Perimeter_of_section: Perimeter of the column section (mm) # Area_of_section: Area of the column section (mm²) # Areq: Required area of the baseplate (mm²) # Returns: # The value of c (mm) # """ a = 4 b = Pcol c = Acol-Areq # Assuming Areq is already calculated discriminant = b**2 - 4 * a * c c1 = (-b + (discriminant)**0.5) / (2 * a) c2 = (-b - (discriminant)**0.5) / (2 * a) return max(c1, c2) c = calculate_c(Pcol,Acol,Areq) # Compute the thickness of the baseplate (tp) tp = c * (3 * fjd* Ym0 / _page_fy)**0.50

마지막으로 Python 코드를 베이스플레이트 설계를 위한 웹 애플리케이션으로 전환

입력

최종 애플리케이션에는 사용자가 다음 매개변수를 지정할 수 있는 입력 기능이 필요합니다.

이는 Viktor SDK의 매개변수화 클래스를 사용하여 달성됩니다.

 class Parametrization(ViktorParametrization): input = Tab("Input") input.profile_type = OptionField( "Profile type", options=["IPE", "HEA", "HEB"], default="IPE", variant="radio-inline", flex=80, ) input.nl1 = LineBreak() input.profile = AutocompleteField( "Profile", options=get_profile_types, default="IPE240", description="The source of profile properties can be found [here](https://eurocodeapplied.com/design/en1993/ipe-hea-heb-hem-design-properties)", ) # input.steel_class = OptionField( # "Steel class", options=["S235", "S275", "S355"], default="S235" # ) input.fck = NumberField('Fck', default=25, suffix="MPa") input.Design_load = NumberField('Design_load', default=1000, suffix="KN") input.acc = NumberField('Concrete coeff(acc)', default=0.85) input.yc = NumberField('Partial factor of safety for concrete', default=1.5) input.steel_class = NumberField('steel_class', default=255, suffix="MPa")


산출

계산 후 Viktor SDK의 데이터 보기 방법을 사용하여 계산 결과를 사용자에게 표시했습니다.

 @DataView("Output", duration_guess=1) def Compute_output(self, params: Munch, **kwargs): Ym0, beta_j, alpha, fjd, Areq, c, tp = self.calculate_plate_geom(params) data = DataGroup( DataItem("ultimate load ", params.input.Design_load, suffix="KN"), DataItem("beta_j", 0.67), DataItem("alpha", 1.5), DataItem("Bearing capacity of concrete support(fjd) ", round(fjd), suffix="MPa"), DataItem("Areq ", round(Areq), suffix="mm2"), DataItem(" c", round(c), suffix="mm"), DataItem("Thickness of plate", round(tp), suffix="mm"), ) return DataResult(data)

어디:

콘크리트 지지력(Fjd)

필요한 철강 면적(Areq)

베이스플레이트 추가 돌출(c)

베이스플레이트의 두께

마지막으로 철골 기둥, 베이스플레이트, 지지 콘크리트 기초의 3D 모델이 생성됩니다.

@GeometryView로 장식된 컨트롤러 클래스 내부에 get_3dview 메소드가 정의되었습니다.


get_3dview 메소드는 3D 모델을 생성하기 위한 로직을 정의하고 마지막으로 생성된 철골 기둥, 베이스 플레이트 및 콘크리트 지지대가 포함된 GeometryResult 객체를 반환합니다.


논리는 아래 코드에 포함되어 있습니다.

 @GeometryView("3D baseplate View", duration_guess=1) def get_3dView(self, params: Munch, **kwargs): """Create geometry for column, base-plate and add a concrete slab underneath""" Ym0, beta_j, alpha, fjd, Areq, c, tp = self.calculate_plate_geom(params) concrete_thickness = 15 * tp steel = Material(color=Color(95, 158, 240), metalness=1) concrete = Material(metalness=0, roughness=1, opacity=0.6) h = self.get_profile_property(params.input.profile_type, params.input.profile, "Depth") b = self.get_profile_property(params.input.profile_type, params.input.profile, "Width") tw = self.get_profile_property(params.input.profile_type, params.input.profile, "Web thickness") tf = self.get_profile_property(params.input.profile_type, params.input.profile, "Flange thickness") r = self.get_profile_property(params.input.profile_type, params.input.profile, "Root radius") beam_profile = self.get_beam_profile(h, b, tw, tf, r) beam = Extrusion(beam_profile, Line(Point(0, 0, tp), Point(0, 0, 3 * h)), material=steel) base_plate = SquareBeam(sqrt(Areq), sqrt(Areq), tp, material=steel) # TODO: This area doesn't seem sufficient for large column sizes base_plate.translate((0, 0, tp / 2)) concrete_plate = SquareBeam(6 * h, 6 * h, concrete_thickness, material=concrete) concrete_plate.translate((0, 0, -concrete_thickness / 2)) return GeometryResult([beam, base_plate, concrete_plate]) 


전체 코드는 아래에서 확인할 수 있습니다.

 from math import sqrt # import plotly.express as px from pathlib import Path from typing import List import numpy as np import pandas as pd from munch import Munch from viktor import ViktorController, Color from viktor.geometry import Point, Extrusion, Line, Material, SquareBeam from viktor.parametrization import ( ViktorParametrization, OptionField, Text, Tab, AutocompleteField, LineBreak, NumberField ) # from viktor.external.spreadsheet import SpreadsheetCalculation, SpreadsheetCalculationInput from viktor.views import DataGroup, DataItem, DataResult, DataView, GeometryView, GeometryResult def get_profile_types(params: Munch, **kwargs): try: file_path = ( Path(__file__).parent / "profiles" / f"steel-profiles-{params.input.profile_type}.csv" ) df = pd.read_csv(file_path, header=[2], skiprows=[3, 4, 5]) return df["Profile"].values.tolist() except FileNotFoundError: return ["IPE80", "IPE100", "HEA100", "HEA120", "HEB100", "HEB120"] def calculate_c(Pcol, Acol, Areq): # """ # This function calculates the value of c for the given equation: # Areq = 4 * c^2 + P_col * c + A_col # Args: # Perimeter_of_section: Perimeter of the column section (mm) # Area_of_section: Area of the column section (mm²) # Areq: Required area of the baseplate (mm²) # Returns: # The value of c (mm) # """ a = 4 b = Pcol c = Acol - Areq # Assuming Areq is already calculated discriminant = b ** 2 - 4 * a * c c1 = (-b + (discriminant) ** 0.5) / (2 * a) c2 = (-b - (discriminant) ** 0.5) / (2 * a) return max(c1, c2) class Parametrization(ViktorParametrization): info = Tab("Info") info.text_01 = Text( """## Welcome to baseplate design app! """ ) input = Tab("Input") input.profile_type = OptionField( "Profile type", options=["IPE", "HEA", "HEB"], default="IPE", variant="radio-inline", flex=80, ) input.nl1 = LineBreak() input.profile = AutocompleteField( "Profile", options=get_profile_types, default="IPE240", description="The source of profile properties can be found [here](https://eurocodeapplied.com/design/en1993/ipe-hea-heb-hem-design-properties)", ) # input.steel_class = OptionField( # "Steel class", options=["S235", "S275", "S355"], default="S235" # ) input.fck = NumberField('Fck', default=25, suffix="MPa") input.Design_load = NumberField('Design_load', default=1000, suffix="KN") input.acc = NumberField('Concrete coeff(acc)', default=0.85) input.yc = NumberField('Partial factor of safety for concrete', default=1.5) input.steel_class = NumberField('steel_class', default=255, suffix="MPa") class Controller(ViktorController): label = 'My Entity Type' parametrization = Parametrization @DataView("profile geometrical Properties", duration_guess=1) def display_geometrical_properties(self, params: Munch, **kwargs): """Initiates the process of rendering an image of the bending moments of the structure, as well as a view of a few key values related to the bending moments.""" # results = self.calculate_allowable_bending_moment( # params.input.profile_type, params.input.profile # ) results = self.get_geometrical_properties( params.input.profile_type, params.input.profile ) data = DataGroup( DataItem("Depth", results["Depth"], suffix="mm"), DataItem("Width", results["Width"], suffix="mm"), DataItem("Thickness_of_web", results["Thickeness_of_web"], suffix="mm"), DataItem("Thickness_of_flange", results["Thickeness_of_flange"], suffix="mm"), DataItem("Area_col", results["Area_col"], suffix="mm2"), DataItem("Perimeter_col", results["Perimeter_col"], suffix="mm"), ) return DataResult(data) def calculate_plate_geom(self, params, **kwargs): results = self.get_geometrical_properties( params.input.profile_type, params.input.profile ) # Partial factor of resistance of cross-sections whatever the class is as per EN 1993-1-1. Ym0 = 1.0 # Compute ultimate load (Ned) -> on page # Compute foundation bearing strength which is typically concrete # βj is the foundation joint material coefficient, typically taken as 0.67 as per clause 6.2.5(7) in EN 1993-1-8. beta_j = 0.67 # α is a coefficient of diffusion of the vertical load being applied to the foundation. Conservatively this can be taken as 1.5 alpha = 1.5 # αcc is the coefficient that allows for long term effects on the compressive strength of concrete vs applied actions. Taken as 0.85 in the UK National Annex -> on page # γc is the partial factor of safety of concrete. Taken as 1.5 in the UK National Annex -> on page fjd = beta_j * alpha * (params.input.acc * params.input.fck) / params.input.yc # Compute area of baseplate required Areq = (params.input.Design_load * 1000) / fjd c = calculate_c(results["Perimeter_col"], results["Area_col"], Areq) # Compute the thickness of baseplate (tp) tp = c * (3 * fjd * Ym0 / params.input.steel_class) ** 0.50 return Ym0, beta_j, alpha, fjd, Areq, c, tp @DataView("Output", duration_guess=1) def Compute_output(self, params: Munch, **kwargs): Ym0, beta_j, alpha, fjd, Areq, c, tp = self.calculate_plate_geom(params) data = DataGroup( DataItem("ultimate load ", params.input.Design_load, suffix="KN"), DataItem("beta_j", 0.67), DataItem("alpha", 1.5), DataItem("Bearing capacity of concrete support(fjd) ", round(fjd), suffix="MPa"), DataItem("Areq ", round(Areq), suffix="mm2"), DataItem(" c", round(c), suffix="mm"), DataItem("Thickness of plate", round(tp), suffix="mm"), ) return DataResult(data) @staticmethod def get_beam_profile(h, b, tw, tf, r) -> List[Point]: """Generates the points which make up the chosen profile for the column cross-section""" # Get points for top flange points = [ Point(-b / 2, (h / 2) - tf), Point(-b / 2, h / 2), Point(b / 2, h / 2), Point(b / 2, (h / 2) - tf), ] # Get curve for top right angles = np.linspace(np.pi / 2, np.pi, 10) x = r * np.cos(angles) + tw / 2 + r y = r * np.sin(angles) + h / 2 - tf - r for _x, _y in zip(x, y): points.append(Point(_x, _y)) # Get curve for bottom right angles = np.linspace(-np.pi, -np.pi / 2, 10) x = r * np.cos(angles) + tw / 2 + r y = r * np.sin(angles) - h / 2 + tf + r for _x, _y in zip(x, y): points.append(Point(_x, _y)) # Get points for bottom flange points.extend([ Point(b / 2, - (h / 2) + tf), Point(b / 2, -h / 2), Point(-b / 2, -h / 2), Point(-b / 2, -(h / 2) + tf), ]) # Get curve for bottom left angles = np.linspace(1.5 * np.pi, 2 * np.pi, 10) x = r * np.cos(angles) - tw / 2 - r y = r * np.sin(angles) - h / 2 + tf + r for _x, _y in zip(x, y): points.append(Point(_x, _y)) # Get curve for top left angles = np.linspace(0, np.pi/2, 10) x = r * np.cos(angles) - tw / 2 - r y = r * np.sin(angles) + h / 2 - tf - r for _x, _y in zip(x, y): points.append(Point(_x, _y)) # Repeat the first point to close the profile points.append(Point(-b / 2, (h / 2) - tf)) return points @GeometryView("3D baseplate View", duration_guess=1) def get_3dView(self, params: Munch, **kwargs): """Create geometry for column, base-plate and add a concrete slab underneath""" Ym0, beta_j, alpha, fjd, Areq, c, tp = self.calculate_plate_geom(params) concrete_thickness = 15 * tp steel = Material(color=Color(95, 158, 240), metalness=1) concrete = Material(metalness=0, roughness=1, opacity=0.6) h = self.get_profile_property(params.input.profile_type, params.input.profile, "Depth") b = self.get_profile_property(params.input.profile_type, params.input.profile, "Width") tw = self.get_profile_property(params.input.profile_type, params.input.profile, "Web thickness") tf = self.get_profile_property(params.input.profile_type, params.input.profile, "Flange thickness") r = self.get_profile_property(params.input.profile_type, params.input.profile, "Root radius") beam_profile = self.get_beam_profile(h, b, tw, tf, r) beam = Extrusion(beam_profile, Line(Point(0, 0, tp), Point(0, 0, 3 * h)), material=steel) base_plate = SquareBeam(sqrt(Areq), sqrt(Areq), tp, material=steel) # TODO: This area doesn't seem sufficient for large column sizes base_plate.translate((0, 0, tp / 2)) concrete_plate = SquareBeam(6 * h, 6 * h, concrete_thickness, material=concrete) concrete_plate.translate((0, 0, -concrete_thickness / 2)) return GeometryResult([beam, base_plate, concrete_plate]) @staticmethod def get_profile_property( profile_type: str, profile: str, property_name: str ) -> float: """Retrieve the profile properties based on the profile type, profile and property :param profile_type: One of the following profile types: HEA, HEB or IPE. :param profile: Profile name, eg IPE80 (IPE was given as profile_type) :param property_name: The name of the property, eg Weight """ file_path = ( Path(__file__).parent / "profiles" / f"steel-profiles-{profile_type}.csv" ) df = pd.read_csv(file_path, header=[2], skiprows=[3, 4, 5]) return df.loc[df["Profile"] == profile, property_name].item() @staticmethod def get_geometrical_properties( profile_type: str, profile: str ): """Calculates the allowable bending moment based on the given parameters. :param profile_type: One of the following profile types: HEA, HEB or IPE. :param profile: Profile name, eg IPE80 (IPE was given as profile_type) :param steel_class: The steel class, eg S235 :return: A dict with the moment of inertia, profile height, yield strength and allowable bending moment. """ file_path = ( Path(__file__).parent / "profiles" / f"steel-profiles-{profile_type}.csv" ) df = pd.read_csv(file_path, header=[2], skiprows=[3, 4, 5]) Depth = df.loc[df["Profile"] == profile, "Depth"].item() Width = df.loc[df["Profile"] == profile, "Width"].item() Thickeness_of_web = df.loc[df["Profile"] == profile, "Web thickness"].item() Thickeness_of_flange = df.loc[df["Profile"] == profile, "Flange thickness"].item() Area_col = df.loc[df["Profile"] == profile, "Area"].item() Perimeter_col = df.loc[df["Profile"] == profile, "Perimeter"].item() Perimeter_col = Perimeter_col * 1000 return { "Depth": Depth, "Width": Width, "Thickeness_of_web": Thickeness_of_web, "Thickeness_of_flange": Thickeness_of_flange, "Area_col": Area_col, "Perimeter_col": Perimeter_col }


결론

기둥의 하중이 기초에 효과적으로 전달될 수 있도록 베이스플레이트의 두께와 필요한 유효면적을 확인하는 문제에 늘 직면하게 됩니다.


이러한 검사에 도움이 될 수 있는 Python 스크립트를 활용하고 Viktor SDK를 사용하여 스크립트를 공유 가능하고 액세스하기 쉬운 웹 애플리케이션으로 변환하는 것은 쉬웠으며 베이스플레이트 설계 작업 흐름에 더 많은 효율성을 가져왔습니다.


이러한 유형의 엔지니어링 애플리케이션을 구축하면 휴대폰만으로 건설 작업 현장에서 자신감을 가질 수 있으며 베이스플레이트와 같은 구조 부재를 제작 및 배치하기 전에 설계 정확성을 확인할 수 있습니다.