paint-brush
Como criar um aplicativo Web de design de placa de base de aço usando Python e Viktorpor@kamalsamaila
660 leituras
660 leituras

Como criar um aplicativo Web de design de placa de base de aço usando Python e Viktor

por Kamal samaila18m2024/05/06
Read on Terminal Reader

Muito longo; Para ler

Este artigo orienta você na criação de um aplicativo baseado em Python para projetar placas de base de aço, essencial para transferir com segurança cargas de colunas para fundações. Abrange o cálculo da área da placa de base, espessura, resistência ao suporte do concreto e largura adicional usando o método T-stub. O código Python é então transformado em um aplicativo web usando o Viktor SDK, permitindo que os engenheiros insiram parâmetros e visualizem modelos 3D da estrutura. Esta ferramenta eficiente aumenta a precisão dos projetos de placas de base e facilita as verificações no local através de dispositivos móveis, agilizando o fluxo de trabalho de construção.
featured image - Como criar um aplicativo Web de design de placa de base de aço usando Python e Viktor
Kamal samaila HackerNoon profile picture

Introdução

Placas de base de aço são colocadas sob colunas de aço para transferir com segurança as forças de projeto para as fundações.


Quando colunas de aço suportam cargas pesadas com seções transversais pequenas, a aplicação direta das cargas na fundação pode levar à falha por punção. Assim, é fundamental utilizar uma placa de base abaixo do pilar para distribuir a carga por uma área maior.


Este artigo fornece um guia para criar um aplicativo de projeto de placa de base usando Python, aproveitando as propriedades geométricas do aço armazenadas no formato CSV.


A aplicação ajudará os engenheiros a determinar facilmente a área necessária da placa de base, a espessura, a resistência do concreto e a largura adicional.


Além disso, ao utilizar o Viktor SDK, podemos transformar perfeitamente nossa implementação Python em um aplicativo web.


Este SDK oferece a capacidade de visualizar nossa estrutura em uma visualização 3D. Vamos mergulhar de cabeça e agir!

Princípio Básico para o Projeto da Placa de Base

O projeto da placa de base usa o método de ponta em T equivalente para forças axiais, onde uma 'área efetiva' é calculada para pontas em T em compressão, e a flexão da placa de base é avaliada para pontas em T em tensão. É permitido cisalhamento horizontal maior e/ou menor, mas sem momentos, ou seja, dimensionamento de base fixada.

A primeira coisa que calculamos é a resistência do concreto de suporte, fjd.

A resistência de cálculo, fjd, entre a parte inferior da placa de base e o material de assentamento no espaço de argamassa é dada por:


fjd = βj * α * fcd

onde


βj = coeficiente de material da junta de fundação = (2/3)


α = um coeficiente que leva em conta a difusão da força concentrada dentro da fundação


fcd = valor de projeto resistência à compressão do concreto = αcc * fck / ɣc


αcc = coeficiente para efeitos de longo prazo


fck = resistência característica do cilindro do concreto


ɣc = fator de segurança parcial para concreto

A segunda etapa é calcular a área necessária da placa de base, que é dada pela fórmula:

Areq = Ned / fjd

Onde Ned é a carga última do pilar de aço.

A terceira etapa é calcular c, que é o cantilever outstand da área efetiva:

C é calculado usando a fórmula abaixo:

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


Portanto, você resolve para c.


E finalmente, calculamos a espessura da placa de base, tp:

tp = c * (3 * fjd* Ym0 / _page_fy)**0,50

Implementação Python do fluxo de trabalho de design da placa base

 # 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

Finalmente, transformando o código Python em um aplicativo da Web para design de placa base

Entrada

Meu aplicativo final precisará de recursos de entrada onde o usuário possa especificar os seguintes parâmetros:

Isso é conseguido usando a classe de parametrização do 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")


Saída

Após o cálculo, o método de visualização de dados do Viktor SDK foi usado para exibir o resultado do cálculo ao usuário.

 @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)

onde:

Capacidade de carga do concreto (Fjd)

Área de aço necessária (Areq)

Projeção adicional da placa de base(c)

Espessura da placa de base

Finalmente, é criado um modelo 3D do pilar de aço, da placa de base e da fundação de concreto de suporte.

Um método get_3dview foi definido dentro da classe do controlador que é decorada com @GeometryView.


O método get_3dview é o que define a lógica de criação do modelo 3D e por fim retorna o objeto GeometryResult contendo o pilar de aço, placa de base e suporte de concreto criados.


A lógica está contida no código abaixo:

 @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]) 


O código completo pode ser encontrado abaixo:

 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 }


Conclusão

Sempre me deparo com o problema de verificar a espessura da placa de base e a área efetiva necessária que deve ser fornecida para que as cargas do pilar possam ser efetivamente transmitidas à fundação.


Utilizar um script Python que pode me ajudar com essas verificações e converter o script em um aplicativo da web compartilhável e de fácil acesso usando o Viktor SDK foi fácil e trouxe mais eficiência ao fluxo de trabalho de design da placa de base.


Construir esse tipo de aplicativo de engenharia pode deixá-lo confiante em seu canteiro de obras apenas com seu telefone celular e ser capaz de verificar a precisão do projeto de membros estruturais, como placas de base, antes de serem fabricados e colocados.