diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..894a44c --- /dev/null +++ b/.gitignore @@ -0,0 +1,104 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/Analysis/Frame_2D_GUI.py b/Analysis/Frame_2D_GUI.py new file mode 100644 index 0000000..e1272e7 --- /dev/null +++ b/Analysis/Frame_2D_GUI.py @@ -0,0 +1,1419 @@ +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' + +from __future__ import division +import Tkinter as tk +import tkMessageBox +import ttk +import tkFont +import tkFileDialog +import Frame_Moment_Distribution_2D as frame2d + +class main_window: + + def __init__(self, master): + + self.master = master + self.inputs = [] + self.beam_count = 0 + self.beam_inputs = [] + self.beam_gui_list = [] + self.cantL_count = 0 + self.cantL_beam_inputs = [] + self.cantL_beam_gui_list = [] + self.cantR_count = 0 + self.cantR_beam_inputs = [] + self.cantR_beam_gui_list = [] + self.column_up_inputs = [] + self.column_up_gui_list = [] + self.column_down_inputs = [] + self.column_down_gui_list = [] + self.nodetorsion_inputs = [] + self.nodetorsion_gui_list = [] + self.beam_labels = [] + self.gui_load_list = [] + self.load_change_index = 0 + self.frame_built = 0 + self.frame_solved = 0 + self.max_h_up_graph = 0 + self.max_h_dwn_graph = 0 + + self.max_m = 0 + self.min_m = 0 + self.max_v = 0 + self.min_v = 0 + self.max_d = 0 + self.min_d = 0 + self.max_s = 0 + self.min_s = 0 + + self.nodes_analysis = [] + self.beams_analysis = [] + self.columns_analysis = [] + + self.load_types = ['Point','Moment','UDL','TRAP'] + + # Font Set + self.f_size = 10 + self.helv = tkFont.Font(family=' Courier New',size=self.f_size, weight='bold') + self.helv_norm = tkFont.Font(family=' Courier New',size=self.f_size) + self.helv_res = tkFont.Font(family=' Courier New',size=self.f_size, weight='bold', underline = True) + self.mono_f = tkFont.Font(family='Consolas',size=8) + self.mono_f_chart = tkFont.Font(family='Consolas',size=10) + + # Menubar + self.menubar = tk.Menu(self.master) + self.menu = tk.Menu(self.menubar, tearoff=0) + self.menu_props = tk.Menu(self.menubar, tearoff=0) + self.menubar.add_cascade(label = "File", menu=self.menu) + #self.menu.add_command(label="Save", command=self.save_inputs) + #self.menu.add_command(label="Open", command=self.open_existing) + self.menu.add_separator() + self.menu.add_command(label="Quit", command=self.quit_app) + try: + self.master.config(menu=self.menubar) + except AttributeError: + self.master.tk.call(master, "config", "-menu", self.menubar) + + #Base Frame + self.base_frame = tk.Frame(master, bd=2, relief='sunken', padx=1,pady=1) + self.base_frame.pack(side=tk.BOTTOM, padx= 1, pady= 1, fill=tk.X) + #Base Frame Items + w=20 + h=1 + + self.b_quit = tk.Button(self.base_frame,text="Quit", command=self.quit_app, font=self.helv, width=w, height=h, bg='red3') + self.b_quit.pack(side=tk.RIGHT) + + self.b_build_frame = tk.Button(self.base_frame,text="Build the Frame", command=self.build_frame_gui_func, font=self.helv, width=w, height=h, bg='cornflower blue') + self.b_build_frame.pack(side=tk.LEFT) + + self.b_solve_frame = tk.Button(self.base_frame,text="Solve the Frame",command=self.frame_analysis_gui, font=self.helv, width=w, height=h, bg='gray75',state=tk.DISABLED) + self.b_solve_frame.pack(side=tk.LEFT) + + self.data_frame = tk.Frame(master, bd=2, relief='sunken', padx=1,pady=1) + self.data_frame.pack(side=tk.LEFT, padx= 1, pady= 1, fill=tk.BOTH, expand=1) + + #Main Notebooks + self.nb_data = ttk.Notebook(self.data_frame) + self.nb_data.pack(fill=tk.BOTH, expand=1) + + # Initial Geometry Input + self.geo_tab = ttk.Frame(self.nb_data) + self.nb_data.add(self.geo_tab, text='Geometry') + + self.geo_tab_frame = tk.Frame(self.geo_tab, bd=2, relief='sunken', padx=1,pady=1) + + self.b_add_beam = tk.Button(self.geo_tab_frame, text="Add a Beam",command=self.add_beam_func, font=self.helv, width=w, height=h) + self.b_add_beam.grid(row=1,column=1) + + self.b_remove_beam = tk.Button(self.geo_tab_frame, text="Remove Last Beam",command=self.remove_last_beam_func, font=self.helv, width=w, height=h, state=tk.DISABLED) + self.b_remove_beam.grid(row=2,column=1) + + self.b_copy_beam = tk.Button(self.geo_tab_frame, text="Copy BM_1 to All",command=self.copy_beam_func, font=self.helv, width=w, height=h) + self.b_copy_beam.grid(row=3,column=1) + + self.b_add_left_cant = tk.Button(self.geo_tab_frame, text="Add Left Cantilever",command=self.add_cant_left_func, font=self.helv, width=w, height=h) + self.b_add_left_cant.grid(row=1,column=2) + + self.b_remove_left_cant = tk.Button(self.geo_tab_frame, text="Remove Left Cantilever",command=self.remove_left_cant_func, font=self.helv, width=w, height=h, state=tk.DISABLED) + self.b_remove_left_cant.grid(row=2,column=2) + + self.b_add_right_cant = tk.Button(self.geo_tab_frame, text="Add Right Cantilever",command=self.add_cant_right_func, font=self.helv, width=w, height=h) + self.b_add_right_cant.grid(row=1,column=3) + + self.b_remove_right_cant = tk.Button(self.geo_tab_frame, text="Remove Right Cantilever",command=self.remove_right_cant_func, font=self.helv, width=w, height=h, state=tk.DISABLED) + self.b_remove_right_cant.grid(row=2,column=3) + + self.precision = tk.StringVar() + self.precision.set('1e-5') + tk.Label(self.geo_tab_frame, text='Calc. Precision:').grid(row=1,column=4) + self.precision_entry = tk.Entry(self.geo_tab_frame, textvariable=self.precision, width=10) + self.precision_entry.grid(row=2, column=4) + + self.col_bm_notebook = ttk.Notebook(self.geo_tab_frame) + self.col_bm_notebook.grid(row=4,column=1, columnspan=4) + + self.bm_info_tab = ttk.Frame(self.col_bm_notebook) + self.col_bm_notebook.add(self.bm_info_tab, text='Beam Data') + + tk.Label(self.bm_info_tab, text='\nLabel:').grid(row=1, column=1) + tk.Label(self.bm_info_tab, text='\nLength (ft):').grid(row=1, column=2) + tk.Label(self.bm_info_tab, text='\nE (ksi):').grid(row=1, column=3) + tk.Label(self.bm_info_tab, text='\nI (in^4):').grid(row=1, column=4) + tk.Label(self.bm_info_tab, text='|\n|').grid(row=1, column=5) + tk.Label(self.bm_info_tab, text='Left Cant.\nLabel:').grid(row=1, column=6) + tk.Label(self.bm_info_tab, text='\nLength (ft):').grid(row=1, column=7) + tk.Label(self.bm_info_tab, text='\nE (ksi):').grid(row=1, column=8) + tk.Label(self.bm_info_tab, text='\nI (in^4):').grid(row=1, column=9) + tk.Label(self.bm_info_tab, text='|\n|').grid(row=1, column=10) + tk.Label(self.bm_info_tab, text='Right Cant.\nLabel:').grid(row=1, column=11) + tk.Label(self.bm_info_tab, text='\nLength (ft):').grid(row=1, column=12) + tk.Label(self.bm_info_tab, text='\nE (ksi):').grid(row=1, column=13) + tk.Label(self.bm_info_tab, text='\nI (in^4):').grid(row=1, column=14) + + self.colup_info_tab = ttk.Frame(self.col_bm_notebook) + self.col_bm_notebook.add(self.colup_info_tab, text='Column Up Data') + + tk.Label(self.colup_info_tab, text='N/A:').grid(row=1, column=1) + tk.Label(self.colup_info_tab, text='Label:').grid(row=1, column=2) + tk.Label(self.colup_info_tab, text='Height (ft):').grid(row=1, column=3) + tk.Label(self.colup_info_tab, text='E (ksi):').grid(row=1, column=4) + tk.Label(self.colup_info_tab, text='I (in^4):').grid(row=1, column=5) + tk.Label(self.colup_info_tab, text='A (in^2):').grid(row=1, column=6) + tk.Label(self.colup_info_tab, text='Fixed Top:').grid(row=1, column=7) + tk.Label(self.colup_info_tab, text='Hinge at Beam:').grid(row=1, column=8) + + self.b_copy_colup = tk.Button(self.colup_info_tab, text="Copy Col_1 to All",command=self.copy_colup_func, font=self.helv, width=w, height=h) + self.b_copy_colup.grid(row=1,column=9) + + self.coldwn_info_tab = ttk.Frame(self.col_bm_notebook) + self.col_bm_notebook.add(self.coldwn_info_tab, text='Column Down Data') + + tk.Label(self.coldwn_info_tab, text='Label:').grid(row=1, column=1) + tk.Label(self.coldwn_info_tab, text='Height (ft):').grid(row=1, column=2) + tk.Label(self.coldwn_info_tab, text='E (ksi):').grid(row=1, column=3) + tk.Label(self.coldwn_info_tab, text='I (in^4):').grid(row=1, column=4) + tk.Label(self.coldwn_info_tab, text='A (in^2):').grid(row=1, column=5) + tk.Label(self.coldwn_info_tab, text='Fixed Base:').grid(row=1, column=6) + tk.Label(self.coldwn_info_tab, text='Hinge at Beam:').grid(row=1, column=7) + + self.b_copy_coldwn = tk.Button(self.coldwn_info_tab, text="Copy Col_1 to All",command=self.copy_coldwn_func, font=self.helv, width=w, height=h) + self.b_copy_coldwn.grid(row=1,column=8) + + self.cols_compress = tk.IntVar() + self.cols_compress.set(1) + tk.Checkbutton(self.coldwn_info_tab, text=' : Columns are Compressible', variable=self.cols_compress,font=self.helv).grid(row=2, column=8, sticky = tk.W) + + + self.geo_tab_frame.pack(fill=tk.BOTH, expand=1) + + #Loads Frame tabs + #Loads + self.loads_tab = ttk.Frame(self.nb_data) + self.nb_data.add(self.loads_tab, text='Loads') + + self.g_loads_frame = tk.Frame(self.loads_tab, bd=2, relief='sunken', padx=1,pady=1) + + # Load Types and Combinations + self.g_load_types_frame = tk.Frame(self.g_loads_frame, bd=2, relief='sunken', padx=1,pady=1) + + self.load_kinds = ['SELF','DL','LL','LL_pat'] + self.load_kinds_var_list = [] + self.load_combinations = [['All_DL',1,1,0,0],['ALL_LL',0,0,1,1],['DL_LL',1,1,1,1],['CONC_D',3,3,1,1],['LRFD_1',1.4,1.4,0,0],['LRFD_2',1.2,1.2,1.6,1.6]] + self.load_combinations_var_list = [] + self.load_combo_gui_items = [] + + i=0 + for kind in self.load_kinds: + a = tk.Label(self.g_load_types_frame, text=kind) + a.grid(row=1,column=1+i) + i+=1 + self.load_combo_gui_items.append(a) + + i=0 + for combo in self.load_combinations: + var_list = [] + j=0 + for item in combo: + var_list.append(tk.StringVar()) + var_list[-1].set(item) + if j==0: + a = tk.Entry(self.g_load_types_frame, textvariable=var_list[-1], width=8) + else: + a = tk.Entry(self.g_load_types_frame, textvariable=var_list[-1], width=4) + a.grid(row=2+i,column=j) + self.load_combo_gui_items.append(a) + j+=1 + i+=1 + + self.g_load_types_frame.pack(side=tk.LEFT, fill=tk.Y) + + self.g_applied_loads_frame = tk.Frame(self.g_loads_frame, bd=2, relief='sunken', padx=1,pady=1) + + tk.Label(self.g_applied_loads_frame, text='On Beam:').grid(row=1,column=1) + tk.Label(self.g_applied_loads_frame, text='P,M,W1:').grid(row=1,column=2) + tk.Label(self.g_applied_loads_frame, text='W2:').grid(row=1,column=3) + tk.Label(self.g_applied_loads_frame, text='a:').grid(row=1,column=4) + tk.Label(self.g_applied_loads_frame, text='b:').grid(row=1,column=5) + tk.Label(self.g_applied_loads_frame, text='kind:').grid(row=1,column=6) + tk.Label(self.g_applied_loads_frame, text='type:').grid(row=1,column=7) + + self.load_span_select = tk.StringVar() + self.load_span_select.set('BM_1') + spans = ['BM_1'] + self.load_span_selection = tk.OptionMenu(self.g_applied_loads_frame, self.load_span_select, *spans) + self.load_span_selection.grid(row=2,column=1, sticky = tk.W) + + self.w1_gui = tk.StringVar() + self.w2_gui = tk.StringVar() + self.a_gui = tk.StringVar() + self.b_gui = tk.StringVar() + + self.w1_gui.set(0) + self.w2_gui.set(0) + self.a_gui.set(0) + self.b_gui.set(0) + + self.w1_gui_entry = tk.Entry(self.g_applied_loads_frame, textvariable=self.w1_gui, width=8) + self.w1_gui_entry.grid(row=2,column=2, sticky = tk.W) + self.w2_gui_entry = tk.Entry(self.g_applied_loads_frame, textvariable=self.w2_gui, width=8) + self.w2_gui_entry.grid(row=2,column=3, sticky = tk.W) + self.a_gui_entry = tk.Entry(self.g_applied_loads_frame, textvariable=self.a_gui, width=8) + self.a_gui_entry.grid(row=2,column=4, sticky = tk.W) + self.b_gui_entry = tk.Entry(self.g_applied_loads_frame, textvariable=self.b_gui, width=8) + self.b_gui_entry.grid(row=2,column=5, sticky = tk.W) + + self.load_type = tk.StringVar() + self.load_type.set('Point') + load_types = ['Point','Moment','UDL','TRAP'] + self.load_type_selection = tk.OptionMenu(self.g_applied_loads_frame, self.load_type, *load_types) + self.load_type_selection.grid(row=2,column=6, sticky = tk.W) + + self.load_kind_select = tk.StringVar() + self.load_kind_select.set('DL') + load_kinds = ['SELF','DL','LL','LL_pat'] + self.load_kind_selection = tk.OptionMenu(self.g_applied_loads_frame, self.load_kind_select, *load_kinds) + self.load_kind_selection.grid(row=2,column=7, sticky = tk.W) + + self.loads_list_bframe = tk.Frame(self.g_applied_loads_frame, pady=5) + self.b_add_load = tk.Button(self.loads_list_bframe, text="Add Load",command=self.add_load_gui, font=self.helv, width=12, height=h) + self.b_add_load.grid(row=1,column=1) + + self.b_change_load = tk.Button(self.loads_list_bframe, text="Edit Load",command=self.change_load_gui, font=self.helv, width=12, height=h, state=tk.DISABLED, bg='gray75') + self.b_change_load.grid(row=2,column=1) + + self.b_remove_load = tk.Button(self.loads_list_bframe, text="Del Load",command=self.remove_load_gui, font=self.helv, width=12, height=h, state=tk.DISABLED, bg='gray75') + self.b_remove_load.grid(row=3,column=1) + + self.b_add_all_load = tk.Button(self.loads_list_bframe, text='Add to All', command=self.add_load_to_all_gui, font=self.helv, width=12, height=h) + self.b_add_all_load.grid(row=4,column=1) + + self.b_remove_all_loads = tk.Button(self.loads_list_bframe, text='*Del All*', command=self.remove_all_loads_gui, font=self.helv, width=12, height=h, bg='red3') + self.b_remove_all_loads.grid(row=5,column=1) + + self.loads_list_bframe.grid(row=3, column=1, sticky=tk.N) + + self.loads_list_frame = tk.Frame(self.g_applied_loads_frame, pady=5) + + self.loads_scrollbar = tk.Scrollbar(self.loads_list_frame, orient="vertical") + self.loads_scrollbar.grid(row=1, column=2, sticky=tk.NS) + + self.load_listbox = tk.Listbox(self.loads_list_frame, height = 20, width = 50, font=self.helv, yscrollcommand=self.loads_scrollbar.set) + self.load_listbox.grid(row=1, column=1) + self.load_listbox.bind("<>",self.load_listbox_click) + + self.loads_scrollbar.configure(command=self.load_listbox.yview) + + self.loads_list_frame.grid(row=3, column=2, columnspan=6) + + self.g_applied_loads_frame.pack(side=tk.RIGHT, fill=tk.Y) + + self.g_loads_frame.pack(fill=tk.BOTH,expand=1, padx=5, pady=5) + + #Graphics Frame tabs and canvases + #Geometry - Graph + self.graph_tab = ttk.Frame(self.nb_data) + self.nb_data.add(self.graph_tab, text='Graph') + + self.g_a_frame = tk.Frame(self.graph_tab, bd=2, relief='sunken', padx=1,pady=1) + self.g_a_frame.pack(fill=tk.BOTH,expand=1, padx=5, pady=5) + + self.g_plan_canvas = tk.Canvas(self.g_a_frame, width=50, height=50, bd=2, relief='sunken', background="black") + #self.g_plan_canvas.bind("", self.build_frame_graph) + self.g_plan_canvas.pack(side = tk.LEFT, anchor='w', padx= 1, pady= 1, fill=tk.BOTH, expand=1) + + self.origin = self.g_plan_canvas.xview()[0], self.g_plan_canvas.yview()[0] + + self.g_plan_canvas.bind("", self.canvas_mouse_start) + self.g_plan_canvas.bind("", self.canvas_mouse_move) + self.g_plan_canvas.bind_all("", self.canvas_zoom) + self.g_plan_canvas.bind("", self.canvas_reset) + + self.graph_b_frame = tk.Frame(self.g_a_frame, bd=2, relief='sunken', padx=4 ,pady=1) + + self.show_l = tk.IntVar() + self.show_l.set(1) + tk.Checkbutton(self.graph_b_frame, text=' : Show Loads', variable=self.show_l, command=self.build_frame_graph,font=self.helv).grid(row=1, column=1, sticky = tk.W) + self.show_v = tk.IntVar() + tk.Checkbutton(self.graph_b_frame, text=' : Show V', variable=self.show_v, command=self.build_frame_graph, font=self.helv).grid(row=2, column=1, sticky = tk.W) + self.show_m = tk.IntVar() + tk.Checkbutton(self.graph_b_frame, text=' : Show M', variable=self.show_m, command=self.build_frame_graph, font=self.helv).grid(row=3, column=1, sticky = tk.W) + self.show_m_tension = tk.IntVar() + self.show_m_tension.set(1) + tk.Checkbutton(self.graph_b_frame, text=' : M on tension face', variable=self.show_m_tension, command=self.build_frame_graph, font=self.helv).grid(row=4, column=1, sticky = tk.E) + self.show_s = tk.IntVar() + tk.Checkbutton(self.graph_b_frame, text=' : Show S', variable=self.show_s, command=self.build_frame_graph, font=self.helv).grid(row=5, column=1, sticky = tk.W) + self.show_d = tk.IntVar() + tk.Checkbutton(self.graph_b_frame, text=' : Show D', variable=self.show_d, command=self.build_frame_graph, font=self.helv).grid(row=6, column=1, sticky = tk.W) + self.show_r = tk.IntVar() + tk.Checkbutton(self.graph_b_frame, text=' : Show Reactions', variable=self.show_r, command=self.build_frame_graph, font=self.helv).grid(row=7, column=1, sticky = tk.W) + self.show_dfs = tk.IntVar() + tk.Checkbutton(self.graph_b_frame, text=" : Show DF's", variable=self.show_dfs, command=self.build_frame_graph, font=self.helv).grid(row=8, column=1, sticky = tk.W) + + self.show_col_charts = tk.IntVar() + self.show_col_charts.set(1) + tk.Checkbutton(self.graph_b_frame, text=' : Show Col\nCharts', variable=self.show_col_charts, command=self.build_frame_graph, font=self.helv).grid(row=9, column=1, sticky = tk.W) + self.show_bm_charts = tk.IntVar() + self.show_bm_charts.set(1) + tk.Checkbutton(self.graph_b_frame, text=' : Show Bm\nCharts', variable=self.show_bm_charts, command=self.build_frame_graph, font=self.helv).grid(row=10, column=1, sticky = tk.W) + + self.show_stations = tk.IntVar() + self.show_stations.set(1) + tk.Checkbutton(self.graph_b_frame, text=' : Show Stations', variable=self.show_stations, command=self.build_frame_graph, font=self.helv).grid(row=11, column=1, sticky = tk.W) + + self.refresh_graphic = tk.Button(self.graph_b_frame, text="Refresh/Reset",command=self.build_frame_graph, font=self.helv, width=15, height=h) + self.refresh_graphic.grid(row=12, column=1) + + tk.Label(self.graph_b_frame, text='Result Scale:', font=self.helv).grid(row=13, column=1, sticky=tk.W) + self.res_scale = tk.StringVar() + self.res_scale.set('10') + self.res_scale_entry = tk.Entry(self.graph_b_frame, textvariable=self.res_scale, width=8) + self.res_scale_entry.grid(row=13, column=2, sticky=tk.W) + + self.graph_b_frame.pack(side=tk.RIGHT, anchor='e') + + # Call function to display license dialog on app start + self.add_beam_func() + self.license_display() + + def license_display(self, *event): + # Function to display license dialog on app start + license_string = ("Copyright (c) 2019, Donald N. Bockoven III\n" + "All rights reserved.\n\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" + " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" + " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" + " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" + " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" + " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" + " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," + " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" + "https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE" + ) + + tkMessageBox.showerror("License Information",license_string) + self.master.focus_force() + + def quit_app(self,*args): + self.master.quit() + self.master.destroy() + + def canvas_mouse_start(self, event): + self.g_plan_canvas.scan_mark(event.x, event.y) + + def canvas_mouse_move(self, event): + self.g_plan_canvas.scan_dragto(event.x, event.y, gain=1) + + def canvas_zoom(self, event): + #x = self.g_plan_canvas.canvasx(event.x) + #y = self.g_plan_canvas.canvasx(event.y) + + w = self.g_plan_canvas.winfo_width() + h = self.g_plan_canvas.winfo_height() + + x = w/2 + y = h/2 + + if event.delta > 0: + self.g_plan_canvas.scale('all', x, y, 1.1, 1.1) + elif event.delta < 0: + self.g_plan_canvas.scale('all', x, y, 0.9, 0.9) + + def canvas_reset(self, *args): + x, y = self.origin + self.g_plan_canvas.yview_moveto(x) + self.g_plan_canvas.xview_moveto(y) + + def add_beam_func(self, *event): + self.frame_built = 0 + self.frame_solved = 0 + self.beam_count +=1 + + self.b_remove_beam.configure(state=tk.NORMAL) + self.b_solve_frame.configure(state=tk.DISABLED, bg='red3') + + self.beam_inputs.append([tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar()]) + self.beam_inputs[-1][1].set(10) + self.beam_inputs[-1][2].set(29000) + self.beam_inputs[-1][3].set(30.8) + + + if self.beam_count == 1: + self.column_up_inputs.append([tk.IntVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.IntVar(),tk.IntVar()]) + self.column_up_inputs.append([tk.IntVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.IntVar(),tk.IntVar()]) + self.column_down_inputs.append([tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.IntVar(),tk.IntVar()]) + self.column_down_inputs.append([tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.IntVar(),tk.IntVar()]) + + self.column_up_inputs[-2][1].set('COL_UP_{0}'.format(self.beam_count)) + self.column_up_inputs[-2][2].set(10) + self.column_up_inputs[-2][3].set(29000) + self.column_up_inputs[-2][4].set(30.8) + self.column_up_inputs[-2][5].set(2.96) + self.column_up_inputs[-2][6].set(1) + + self.column_up_inputs[-1][1].set('COL_UP_{0}'.format(self.beam_count+1)) + self.column_up_inputs[-1][2].set(10) + self.column_up_inputs[-1][3].set(29000) + self.column_up_inputs[-1][4].set(30.8) + self.column_up_inputs[-1][5].set(2.96) + self.column_up_inputs[-1][6].set(1) + + self.column_down_inputs[-2][0].set('COL_DWN_{0}'.format(self.beam_count)) + self.column_down_inputs[-2][1].set(10) + self.column_down_inputs[-2][2].set(29000) + self.column_down_inputs[-2][3].set(30.8) + self.column_down_inputs[-2][4].set(2.96) + self.column_down_inputs[-2][5].set(1) + + self.column_down_inputs[-1][0].set('COL_DWN_{0}'.format(self.beam_count+1)) + self.column_down_inputs[-1][1].set(10) + self.column_down_inputs[-1][2].set(29000) + self.column_down_inputs[-1][3].set(30.8) + self.column_down_inputs[-1][4].set(2.96) + self.column_down_inputs[-1][5].set(1) + else: + self.column_up_inputs.append([tk.IntVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.IntVar(),tk.IntVar()]) + self.column_down_inputs.append([tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.IntVar(),tk.IntVar()]) + + self.column_up_inputs[-1][1].set('COL_UP_{0}'.format(self.beam_count+1)) + self.column_up_inputs[-1][2].set(self.column_up_inputs[-2][2].get()) + self.column_up_inputs[-1][3].set(self.column_up_inputs[-2][3].get()) + self.column_up_inputs[-1][4].set(self.column_up_inputs[-2][4].get()) + self.column_up_inputs[-1][5].set(self.column_up_inputs[-2][5].get()) + self.column_up_inputs[-1][6].set(self.column_up_inputs[-2][6].get()) + + self.column_down_inputs[-1][0].set('COL_DWN_{0}'.format(self.beam_count+1)) + self.column_down_inputs[-1][1].set(self.column_down_inputs[-2][1].get()) + self.column_down_inputs[-1][2].set(self.column_down_inputs[-2][2].get()) + self.column_down_inputs[-1][3].set(self.column_down_inputs[-2][3].get()) + self.column_down_inputs[-1][4].set(self.column_down_inputs[-2][4].get()) + self.column_down_inputs[-1][5].set(self.column_down_inputs[-2][5].get()) + + self.beam_inputs[-1][0].set('BM_{0}'.format(self.beam_count)) + self.beam_labels.append('BM_{0}'.format(self.beam_count)) + self.refesh_span_options() + + self.build_bm_gui_table() + self.build_colup_gui_table() + self.build_coldwn_gui_table() + + def copy_beam_func(self, *args): + + l = self.beam_inputs[0][1].get() + E = self.beam_inputs[0][2].get() + I = self.beam_inputs[0][3].get() + + for i, bm in enumerate(self.beam_inputs): + bm[1].set(l) + bm[2].set(E) + bm[3].set(I) + + def copy_colup_func(self, *args): + + na = self.column_up_inputs[0][0].get() + h = self.column_up_inputs[0][2].get() + E = self.column_up_inputs[0][3].get() + I = self.column_up_inputs[0][4].get() + A = self.column_up_inputs[0][5].get() + fix = self.column_up_inputs[0][6].get() + hinge = self.column_up_inputs[0][7].get() + + for i, col in enumerate(self.column_up_inputs): + col[0].set(na) + col[2].set(h) + col[3].set(E) + col[4].set(I) + col[5].set(A) + col[6].set(fix) + col[7].set(hinge) + + def copy_coldwn_func(self, *args): + + h = self.column_down_inputs[0][1].get() + E = self.column_down_inputs[0][2].get() + I = self.column_down_inputs[0][3].get() + A = self.column_down_inputs[0][4].get() + fix = self.column_down_inputs[0][5].get() + hinge = self.column_down_inputs[0][6].get() + + for i, col in enumerate(self.column_down_inputs): + col[1].set(h) + col[2].set(E) + col[3].set(I) + col[4].set(A) + col[5].set(fix) + col[6].set(hinge) + + def add_cant_left_func(self,*event): + + if self.cantL_count == 0: + self.frame_built = 0 + self.frame_solved = 0 + self.cantL_count +=1 + self.b_remove_left_cant.configure(state=tk.NORMAL) + self.b_add_left_cant.configure(state=tk.DISABLED) + self.b_solve_frame.configure(state=tk.DISABLED, bg='red3') + self.cantL_beam_inputs.append([tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar()]) + self.cantL_beam_inputs[-1][1].set(5) + self.cantL_beam_inputs[-1][2].set(29000) + self.cantL_beam_inputs[-1][3].set(30.8) + + bm = self.cantL_beam_inputs[0] + bm[0].set('CantL') + self.beam_labels.append('CantL') + self.refesh_span_options() + + a = tk.Entry(self.bm_info_tab,textvariable=bm[0], width=8, state=tk.DISABLED) + a.grid(row=2,column=6) + b = tk.Entry(self.bm_info_tab,textvariable=bm[1], width=8) + b.grid(row=2,column=7) + c = tk.Entry(self.bm_info_tab,textvariable=bm[2], width=8) + c.grid(row=2,column=8) + d = tk.Entry(self.bm_info_tab,textvariable=bm[3], width=8) + d.grid(row=2,column=9) + + self.cantL_beam_gui_list.extend([a,b,c,d]) + + else: + pass + + def remove_left_cant_func(self,*event): + if self.cantL_count > 0: + self.frame_built = 0 + self.frame_solved = 0 + self.cantL_count -=1 + self.beam_labels.remove('CantL') + self.refesh_span_options() + self.b_remove_left_cant.configure(state=tk.DISABLED) + self.b_solve_frame.configure(state=tk.DISABLED, bg='red3') + self.b_add_left_cant.configure(state=tk.NORMAL) + for element in self.cantL_beam_gui_list: + element.destroy() + + del self.cantL_beam_gui_list[:] + + def remove_right_cant_func(self,*event): + if self.cantR_count > 0: + self.frame_built = 0 + self.frame_solved = 0 + self.cantR_count -=1 + self.beam_labels.remove('CantR') + self.refesh_span_options() + self.b_remove_right_cant.configure(state=tk.DISABLED) + self.b_add_right_cant.configure(state=tk.NORMAL) + self.b_solve_frame.configure(state=tk.DISABLED, bg='red3') + for element in self.cantR_beam_gui_list: + element.destroy() + + del self.cantR_beam_gui_list[:] + + def add_cant_right_func(self,*event): + if self.cantR_count == 0: + self.frame_built = 0 + self.frame_solved = 0 + self.cantR_count +=1 + self.b_remove_right_cant.configure(state=tk.NORMAL) + self.b_add_right_cant.configure(state=tk.DISABLED) + self.b_solve_frame.configure(state=tk.DISABLED, bg='red3') + self.cantR_beam_inputs.append([tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar()]) + self.cantR_beam_inputs[-1][1].set(5) + self.cantR_beam_inputs[-1][2].set(29000) + self.cantR_beam_inputs[-1][3].set(30.8) + + bm = self.cantR_beam_inputs[0] + bm[0].set('CantR') + self.beam_labels.append('CantR') + self.refesh_span_options() + + a = tk.Entry(self.bm_info_tab,textvariable=bm[0], width=8, state=tk.DISABLED) + a.grid(row=2,column=11) + b = tk.Entry(self.bm_info_tab,textvariable=bm[1], width=8) + b.grid(row=2,column=12) + c = tk.Entry(self.bm_info_tab,textvariable=bm[2], width=8) + c.grid(row=2,column=13) + d = tk.Entry(self.bm_info_tab,textvariable=bm[3], width=8) + d.grid(row=2,column=14) + + self.cantR_beam_gui_list.extend([a,b,c,d]) + + else: + pass + + def remove_last_beam_func(self,*event): + if self.beam_count <= 1: + pass + else: + self.b_solve_frame.configure(state=tk.DISABLED, bg='red3') + self.beam_count -=1 + self.frame_built = 0 + self.frame_solved = 0 + self.beam_labels.remove(self.beam_inputs[-1][0].get()) + + self.refesh_span_options() + + del self.beam_inputs[-1] + del self.column_up_inputs[-1] + del self.column_down_inputs[-1] + #del self.nodetorsion_inputs[-1] + + self.build_bm_gui_table() + self.build_colup_gui_table() + self.build_coldwn_gui_table() + + def build_bm_gui_table(self,*event): + + for element in self.beam_gui_list: + element.destroy() + + del self.beam_gui_list[:] + + for i,bm in enumerate(self.beam_inputs): + + a = tk.Entry(self.bm_info_tab,textvariable=bm[0], width=8, state=tk.DISABLED) + a.grid(row=i+2,column=1, pady=4) + b = tk.Entry(self.bm_info_tab,textvariable=bm[1], width=8) + b.grid(row=i+2,column=2) + c = tk.Entry(self.bm_info_tab,textvariable=bm[2], width=8) + c.grid(row=i+2,column=3) + d = tk.Entry(self.bm_info_tab,textvariable=bm[3], width=8) + d.grid(row=i+2,column=4) + + self.beam_gui_list.extend([a,b,c,d]) + + def build_colup_gui_table(self,*event): + for element in self.column_up_gui_list: + element.destroy() + + del self.column_up_gui_list[:] + + for i,col in enumerate(self.column_up_inputs): + + a = tk.Checkbutton(self.colup_info_tab,variable=col[0]) + a.grid(row=i+2,column=1) + b = tk.Entry(self.colup_info_tab,textvariable=col[1], width=12, state=tk.DISABLED) + b.grid(row=i+2,column=2) + c = tk.Entry(self.colup_info_tab,textvariable=col[2], width=8) + c.grid(row=i+2,column=3) + d = tk.Entry(self.colup_info_tab,textvariable=col[3], width=8) + d.grid(row=i+2,column=4) + e = tk.Entry(self.colup_info_tab,textvariable=col[4], width=8) + e.grid(row=i+2,column=5) + f = tk.Entry(self.colup_info_tab,textvariable=col[5], width=8) + f.grid(row=i+2,column=6) + g = tk.Checkbutton(self.colup_info_tab,variable=col[6]) + g.grid(row=i+2,column=7) + h = tk.Checkbutton(self.colup_info_tab,variable=col[7]) + h.grid(row=i+2,column=8) + + self.column_up_gui_list.extend([a,b,c,d,e,f,g,h]) + + def build_coldwn_gui_table(self,*event): + for element in self.column_down_gui_list: + element.destroy() + + del self.column_down_gui_list[:] + + for i,col in enumerate(self.column_down_inputs): + + b = tk.Entry(self.coldwn_info_tab,textvariable=col[0], width=12, state=tk.DISABLED) + b.grid(row=i+2,column=1) + c = tk.Entry(self.coldwn_info_tab,textvariable=col[1], width=8) + c.grid(row=i+2,column=2) + d = tk.Entry(self.coldwn_info_tab,textvariable=col[2], width=8) + d.grid(row=i+2,column=3) + e = tk.Entry(self.coldwn_info_tab,textvariable=col[3], width=8) + e.grid(row=i+2,column=4) + f = tk.Entry(self.coldwn_info_tab,textvariable=col[4], width=8) + f.grid(row=i+2,column=5) + g = tk.Checkbutton(self.coldwn_info_tab,variable=col[5]) + g.grid(row=i+2,column=6) + h = tk.Checkbutton(self.coldwn_info_tab,variable=col[6]) + h.grid(row=i+2,column=7) + + self.column_down_gui_list.extend([b,c,d,e,f,g,h]) + + def refesh_span_options(self,*event): + self.load_span_selection['menu'].delete(0,'end') + for choice in self.beam_labels: + self.load_span_selection['menu'].add_command(label=choice, command=tk._setit(self.load_span_select, choice)) + + def add_load_gui(self,*event): + span = self.load_span_select.get() + w1 = float(self.w1_gui.get()) + w2 = float(self.w2_gui.get()) + a = float(self.a_gui.get()) + b = float(self.b_gui.get()) + type = self.load_type.get() + kind = self.load_kind_select.get() + + self.gui_load_list.append([span,w1,w2,a,b,type,kind]) + self.b_change_load.configure(state=tk.DISABLED, bg='gray75') + self.b_remove_load.configure(state=tk.DISABLED, bg='gray75') + + self.fill_load_listbox() + + def remove_load_gui(self,*event): + if len(self.gui_load_list)==0: + pass + else: + del self.gui_load_list[self.load_change_index] + self.b_change_load.configure(state=tk.DISABLED, bg='gray75') + self.b_remove_load.configure(state=tk.DISABLED, bg='gray75') + self.fill_load_listbox() + + def change_load_gui(self,*event): + del self.gui_load_list[self.load_change_index] + self.b_change_load.configure(state=tk.DISABLED, bg='gray75') + self.b_remove_load.configure(state=tk.DISABLED, bg='gray75') + self.add_load_gui() + + def add_load_to_all_gui(self,*event): + + w1 = float(self.w1_gui.get()) + w2 = float(self.w2_gui.get()) + a = float(self.a_gui.get()) + b = float(self.b_gui.get()) + type = self.load_type.get() + kind = self.load_kind_select.get() + + for beam_gui in self.beam_inputs: + + span = beam_gui[0].get() + b_max = float(beam_gui[1].get()) + + b_use = min(b,b_max) + + self.gui_load_list.append([span,w1,w2,a,b_use,type,kind]) + + self.fill_load_listbox() + + def remove_all_loads_gui(self,*event): + if len(self.gui_load_list)==0: + pass + else: + del self.gui_load_list[:] + self.b_change_load.configure(state=tk.DISABLED, bg='gray75') + self.b_remove_load.configure(state=tk.DISABLED, bg='gray75') + self.fill_load_listbox() + + def load_listbox_click(self,*event): + if self.load_listbox.size()==0: + pass + else: + self.b_change_load.configure(state=tk.NORMAL, bg='yellow2') + self.b_remove_load.configure(state=tk.NORMAL, bg='red3') + + self.selected_load = self.load_listbox.get(self.load_listbox.curselection()[0]).split(',') + self.load_change_index = self.load_listbox.curselection()[0] + + self.load_span_select.set(self.selected_load[0]) + self.w1_gui.set(self.selected_load[1]) + self.w2_gui.set(self.selected_load[2]) + self.a_gui.set(self.selected_load[3]) + self.b_gui.set(self.selected_load[4]) + self.load_type.set(self.selected_load[5]) + self.load_kind_select.set(self.selected_load[6]) + + def fill_load_listbox(self,*event): + self.b_solve_frame.configure(state=tk.DISABLED, bg='red3') + self.frame_solved = 0 + + self.load_listbox.delete(0,tk.END) + + color = "pale green" + i=0 + for x in self.gui_load_list: + self.load_listbox.insert(tk.END,'{0},{1:.3f},{2:.3f},{3:.3f},{4:.3f},{5},{6}'.format(x[0],x[1],x[2],x[3],x[4],x[5],x[6])) + + if i % 2 == 0: + self.load_listbox.itemconfigure(i, background=color) + else: + pass + i+=1 + + def build_frame_gui_func(self,*event): + + del self.beams_analysis[:] + del self.nodes_analysis[:] + del self.columns_analysis[:] + self.max_h_up_graph = 0 + self.max_h_dwn_graph = 0 + + if self.cantL_count == 0: + self.nodes_analysis.append(frame2d.node(0)) + else: + cantL_label = self.cantL_beam_inputs[-1][0].get() + cantL_span = float(self.cantL_beam_inputs[-1][1].get()) + E_ksf = float(self.cantL_beam_inputs[-1][2].get())*144.0 # k/in^2 * 144 in^2 / 1 ft^2 = 144 k/ft^2 + I_ft4 = float(self.cantL_beam_inputs[-1][3].get())*(1 / 20736.0) # in^4 * 1 ft^4 / 12^4 in^4 = ft^4 + self.nodes_analysis.append(frame2d.node(cantL_span)) + j = self.nodes_analysis[-1] + + cantL = frame2d.CantBeam(j, E_ksf, I_ft4, cantL_span, [], 1, cantL_label) + + self.beams_analysis.append(cantL) + + for beam_gui in self.beam_inputs: + + label = beam_gui[0].get() + span = float(beam_gui[1].get()) + j = self.nodes_analysis[-1].x + span + self.nodes_analysis.append(frame2d.node(j)) + newi = self.nodes_analysis[-2] + newj = self.nodes_analysis[-1] + E_ksf = float(beam_gui[2].get())*144.0 # k/in^2 * 144 in^2 / 1 ft^2 = 144 k/ft^2 + I_ft4 = float(beam_gui[3].get())*(1 / 20736.0) # in^4 * 1 ft^4 / 12^4 in^4 = ft^4 + + beam = frame2d.Beam(newi,newj,E_ksf,I_ft4, [], label) + + self.beams_analysis.append(beam) + + if self.cantR_count == 0: + pass + + else: + cantR_label = self.cantR_beam_inputs[-1][0].get() + cantR_span = float(self.cantR_beam_inputs[-1][1].get()) + E_ksf = float(self.cantR_beam_inputs[-1][2].get())*144.0 # k/in^2 * 144 in^2 / 1 ft^2 = 144 k/ft^2 + I_ft4 = float(self.cantR_beam_inputs[-1][3].get())*(1 / 20736.0) # in^4 * 1 ft^4 / 12^4 in^4 = ft^4 + i = self.nodes_analysis[-1] + + cantR = frame2d.CantBeam(i, E_ksf, I_ft4, cantR_span, [], 0, cantR_label) + + self.beams_analysis.append(cantR) + + for i,col in enumerate(self.column_down_inputs): + j_node = self.nodes_analysis[i] + height=float(col[1].get()) + E=float(col[2].get())*144.0 # k/in^2 * 144 in^2 / 1 ft^2 = 144 k/ft^2 + I=float(col[3].get())*(1 / 20736.0) # in^4 * 1 ft^4 / 12^4 in^4 = ft^4 + A=float(col[4].get())/144.0 + support=col[5].get() + hinge_near=col[6].get() + + column_dwn = frame2d.Column_Down(j_node, height, E, I, A, support, hinge_near) + + self.max_h_dwn_graph = max(self.max_h_dwn_graph,height) + + self.columns_analysis.append(column_dwn) + + for i,col in enumerate(self.column_up_inputs): + + if col[0].get() == 1: + pass + + else: + i_node = self.nodes_analysis[i] + height=float(col[2].get()) + E=float(col[3].get())*144.0 # k/in^2 * 144 in^2 / 1 ft^2 = 144 k/ft^2 + I=float(col[4].get())*(1 / 20736.0) # in^4 * 1 ft^4 / 12^4 in^4 = ft^4 + A=float(col[5].get())/144.0 + support=col[6].get() + hinge_near=col[7].get() + + self.max_h_up_graph = max(self.max_h_up_graph,height) + + column_up = frame2d.Column_Up(i_node, height, E, I, A, support, hinge_near) + + self.columns_analysis.append(column_up) + + + self.frame_built = 1 + self.frame_solved = 0 + + self.b_solve_frame.configure(state=tk.NORMAL, bg='cornflower blue') + + self.build_frame_graph() + + def build_frame_graph(self,*event): + if self.frame_built == 0: + pass + + else: + self.g_plan_canvas.delete("all") + self.canvas_reset() + w = self.g_plan_canvas.winfo_width() + h = self.g_plan_canvas.winfo_height() + hg = (h/2.0) + + spacer= 60 + + if self.cantR_count == 0: + total_length = self.nodes_analysis[-1].x + else: + total_length = self.nodes_analysis[-1].x + self.beams_analysis[-1].Length + + scale_x = (w - 2*spacer) / total_length + + scale_y = (hg-spacer)/ max(self.max_h_dwn_graph,self.max_h_up_graph) + + scale = min(scale_x, scale_y) + + v_scale = float(self.res_scale.get()) + + s_scale = float(self.res_scale.get()) + + d_scale = float(self.res_scale.get()) + + if self.show_m_tension.get() == 1: + m_scale = float(self.res_scale.get())* -1 + else: + m_scale = float(self.res_scale.get()) + + for i,node in enumerate(self.nodes_analysis): + if node == self.nodes_analysis[-1]: + pass + else: + x1 = (node.x*scale) + spacer + x2 = (self.nodes_analysis[i+1].x*scale)+spacer + self.g_plan_canvas.create_line(x1, hg, x2, hg, fill="white", width=2) + + max_x = x2 + + if self.cantL_count == 0: + pass + else: + x1 = spacer + x2 = (node.x*scale) + spacer + self.g_plan_canvas.create_line(x1, hg, x2, hg, fill="white", width=2) + + if self.cantR_count == 0: + pass + else: + + x1 = (self.nodes_analysis[-1].x*scale)+spacer + x2 = ((self.nodes_analysis[-1].x+self.beams_analysis[-1].Length)*scale)+spacer + self.g_plan_canvas.create_line(x1, hg, x2, hg, fill="white", width=2) + + max_x = x2 + + if self.frame_solved == 0: + pass + else: + for beam in self.beams_analysis: + values, end_delta = beam.station_values() + stations = values[0] + shears = values[1] + moments = values[2] + eislopes = values[3] + eideltas = values[4] + + if self.show_l.get() == 1 and self.show_bm_charts.get()==1: + for load in beam.Loads: + if load == beam.Loads[-1] or load == beam.Loads[-2] and beam.type == 'span': + pass + else: + y_scale = float(self.res_scale.get()) + x_scale = scale + + x0 = (beam.i.x)*x_scale + + x,y = load.chart_load(x_scale,y_scale,1) + + x = [i+x0 for i in x] + + for i in range(1,len(x)): + self.g_plan_canvas.create_line((x[i-1]+spacer),hg - (y[i-1]),(x[i])+spacer,hg - (y[i]), fill = "blue", width=2) + + if self.show_dfs.get() == 1 and self.show_bm_charts.get()==1: + + string = 'DFi: {0:.3f}\nDFj: {1:.3f} '.format(beam.dfi,beam.dfj) + x0 = (((beam.i.x+beam.j.x)/2)*scale) + spacer + + self.g_plan_canvas.create_text(x0, hg+12, anchor=tk.N, font=self.mono_f_chart, text=string, fill='cyan') + + if self.show_r.get() == 1 and self.show_bm_charts.get()==1: + string = 'Riy: {0:.3f} kips\nRjy: {1:.3f} kips'.format(beam.reactions()[0],beam.reactions()[1]) + x0 = (((beam.i.x+beam.j.x)/2)*scale) + spacer + + self.g_plan_canvas.create_text(x0, hg+12, anchor=tk.N, font=self.mono_f_chart, text=string, fill='red') + + if self.show_v.get()==1 and self.show_bm_charts.get()==1: + for i in range(1,len(stations)): + x1 = (stations[i-1]+beam.i.x)*scale + spacer + x2 = (stations[i]+beam.i.x)*scale + spacer + y1 = hg - (shears[i-1] * v_scale) + y2 = hg - (shears[i] * v_scale) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="red", width=2) + + if self.show_stations.get() == 1: + if i == 1: + self.g_plan_canvas.create_line(x1, hg, x1, y1, fill="salmon", width=1) + self.g_plan_canvas.create_line(x2, hg, x2, y2, fill="salmon", width=1) + + string = 'Vi: {0:.3f} kips\nVj: {1:.3f} kips'.format(shears[0],shears[-1]) + x0 = (((beam.i.x+beam.j.x)/2)*scale) + spacer + + self.g_plan_canvas.create_text(x0, hg+12, anchor=tk.N, font=self.mono_f_chart, text=string, fill='red') + + if self.show_m.get()==1 and self.show_bm_charts.get()==1: + string_max = '' + string_min = '' + for i in range(1,len(stations)): + x1 = (stations[i-1]+beam.i.x)*scale + spacer + x2 = (stations[i]+beam.i.x)*scale + spacer + y1 = hg - (moments[i-1] * m_scale) + y2 = hg - (moments[i] * m_scale) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="green", width=2) + + if self.show_stations.get() == 1: + if i == 1: + self.g_plan_canvas.create_line(x1, hg, x1, y1, fill="SeaGreen2", width=1) + self.g_plan_canvas.create_line(x2, hg, x2, y2, fill="SeaGreen2", width=1) + + + if moments[i] == max(moments) and moments[i] != moments[-1]: + string_max = '\nM,max {0:.3f} ft-kips @ {1:.3f} ft'.format(moments[i],stations[i]) + + + if moments[i] == min(moments) and moments[i] != moments[-1]: + string_min = '\nM,min {0:.3f} ft-kips @ {1:.3f} ft'.format(moments[i],stations[i]) + + x0 = (((beam.i.x+beam.j.x)/2)*scale) + spacer + string = 'Mi {0:.3f} ft-kips\nMj {1:.3f} ft-kips'.format(moments[0],moments[-1]) + self.g_plan_canvas.create_text(x0, hg+12, anchor=tk.N, font=self.mono_f_chart, text=string+string_max+string_min, fill='green') + + if self.show_s.get()==1 and self.show_bm_charts.get()==1: + + for i in range(1,len(beam.chart_stations)): + x1 = (stations[i-1]+beam.i.x)*scale + spacer + x2 = (stations[i]+beam.i.x)*scale + spacer + y1 = hg - ((eislopes[i-1]/(beam.E*beam.I)) * s_scale) + y2 = hg - ((eislopes[i]/(beam.E*beam.I)) * s_scale) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="magenta", width=2) + + if self.show_stations.get() == 1: + if i == 1: + self.g_plan_canvas.create_line(x1, hg, x1, y1, fill="orchid1", width=1) + self.g_plan_canvas.create_line(x2, hg, x2, y2, fill="orchid1", width=1) + + si = (eislopes[0]) /(beam.E*beam.I) + sj = (eislopes[-1]) /(beam.E*beam.I) + + string = 'Si: {0:.5f} rad\nSj: {1:.5f} rad'.format(si,sj) + x0 = (((beam.i.x+beam.j.x)/2)*scale) + spacer + + self.g_plan_canvas.create_text(x0, hg+12, anchor=tk.N, font=self.mono_f_chart, text=string, fill='magenta') + + if self.show_d.get()==1 and self.show_bm_charts.get()==1: + + string_max = '' + string_min = '' + for i in range(1,len(beam.chart_stations)): + if beam.type == 'cantilever' and beam.isleft == 1: + d0 = (self.beams_analysis[1].station_values()[0][4][0]/(self.beams_analysis[1].E*self.beams_analysis[1].I))*12.0 + elif beam.type == 'cantilever' and beam.isleft == 0: + d0 = (self.beams_analysis[-2].station_values()[0][4][-1]/(self.beams_analysis[-2].E*self.beams_analysis[-2].I))*12.0 + else: + d0 = 0 + x1 = (stations[i-1]+beam.i.x)*scale + spacer + x2 = (stations[i]+beam.i.x)*scale + spacer + y1 = hg - ((eideltas[i-1]/(beam.E*beam.I)) * d_scale * 12.0) - (d0*d_scale) + y2 = hg - ((eideltas[i]/(beam.E*beam.I)) * d_scale * 12.0) - (d0*d_scale) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="yellow", width=2) + + if self.show_stations.get() == 1: + if i==1: + self.g_plan_canvas.create_line(x1, hg, x1, y1, fill="khaki", width=1) + self.g_plan_canvas.create_line(x2, hg, x2, y2, fill="khaki", width=1) + + if eideltas[i] == max(eideltas) and eideltas[i] != eideltas[-1] and beam.type=='span': + string_max = '\nD,max {0:.3f} in @ {1:.3f} ft'.format(12.0*eideltas[i]/(beam.E*beam.I),stations[i]) + + if eideltas[i] == min(eideltas) and eideltas[i] != eideltas[-1] and beam.type=='span': + string_min = '\nD,min {0:.3f} in @ {1:.3f} ft'.format(12.0*eideltas[i]/(beam.E*beam.I),stations[i]) + + if beam.type == 'cantilever' and beam.isleft == 1: + string_max = '\nD {0:.3f} in @ 0 ft'.format(12.0*eideltas[0]/(beam.E*beam.I)) + + if beam.type == 'cantilever' and beam.isleft == 0: + string_max = '\nD {0:.3f} in @ {1:.3f} ft'.format(12.0*eideltas[-1]/(beam.E*beam.I), beam.Length) + + x0 = (((beam.i.x+beam.j.x)/2)*scale) + spacer + self.g_plan_canvas.create_text(x0, hg+12, anchor=tk.N, font=self.mono_f_chart, text=string_max+string_min, fill='yellow') + + count = 0 + non_sway_reaction = 0 + for col in self.columns_analysis: + + values = col.station_values() + stations = values[0] + shears = values[1] + moments = values[2] + eislopes = values[3] + eideltas = values[4] + + if col.type == 'UP': + x = (col.i.x * scale) + spacer + h1 = hg + h2 = h1 - (col.orig_Length*scale) + self.g_plan_canvas.create_line(x, h1, x, h2, fill="white", width=2) + else: + x = (col.j.x * scale) + spacer + h1 = hg + h2 = h1 + (col.orig_Length*scale) + self.g_plan_canvas.create_line(x, h1, x, h2, fill="white", width=2) + + if self.frame_solved == 0: + pass + else: + + if self.show_r.get() == 1 and self.show_col_charts.get()==1: + if col.type == 'DOWN': + col.base_reaction() + string = 'Riy: {0:.3f} kips\n'.format(col.riy) + non_sway_reaction += col.rjx + else: + string = '' + non_sway_reaction += col.rix + + string += 'Rix: {0:.3f} kips\nRjx: {1:.3f} kips'.format(col.rix,col.rjx) + + + if col.type == 'UP': + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.S,font=self.mono_f_chart, text=string, fill='red') + else: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.N,font=self.mono_f_chart, text=string, fill='red') + + if col == self.columns_analysis[-1]: + non_sway_string = 'Non-Sway Reaction:\nRx: {0:.3f} kips'.format(non_sway_reaction) + + self.g_plan_canvas.create_text(max_x+5, hg, anchor=tk.SW,font=self.mono_f_chart, text=non_sway_string, fill='red') + + if self.show_dfs.get()==1 and self.show_col_charts.get()==1: + dfb = col.dfi + dft = col.dfj + string = 'DFj: {1:.3f}\nDFi: {0:.3f}'.format(dfb,dft) + + if col.type == 'UP': + if count == 0: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.SW,font=self.mono_f_chart, text=string, fill='cyan') + else: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.S,font=self.mono_f_chart, text=string, fill='cyan') + else: + if count == 0: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.NW,font=self.mono_f_chart, text=string, fill='cyan') + else: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.N,font=self.mono_f_chart, text=string, fill='cyan') + + if self.show_v.get()==1 and self.show_col_charts.get()==1: + for i in range(1,len(col.chart_stations)): + if col.type == 'UP': + y1 = h1 - (stations[i-1]*scale) + y2 = h1 - (stations[i]*scale) + else: + y1 = h2 - (stations[i-1]*scale) + y2 = h2 - (stations[i]*scale) + x1 = x + (shears[i-1] * v_scale) + x2 = x + (shears[i] * v_scale) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="red", width=1) + + if self.show_stations.get() == 1: + if i==1: + self.g_plan_canvas.create_line(x, y1, x1, y1, fill="salmon", width=1) + + self.g_plan_canvas.create_line(x, y2, x2, y2, fill="salmon", width=1) + + vb = shears[0] + vt = shears[-1] + string = 'Vj: {1:.3f} kips\nVi: {0:.3f} kips'.format(vb,vt) + + if col.type == 'UP': + if count == 0: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.SW,font=self.mono_f_chart, text=string, fill='red') + else: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.S,font=self.mono_f_chart, text=string, fill='red') + else: + if count == 0: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.NW,font=self.mono_f_chart, text=string, fill='red') + else: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.N,font=self.mono_f_chart, text=string, fill='red') + + if self.show_m.get()==1 and self.show_col_charts.get()==1: + for i in range(1,len(col.chart_stations)): + if col.type == 'UP': + y1 = h1 - (stations[i-1]*scale) + y2 = h1 - (stations[i]*scale) + else: + y1 = h2 - (stations[i-1]*scale) + y2 = h2 - (stations[i]*scale) + x1 = x - (moments[i-1] * m_scale) + x2 = x - (moments[i] * m_scale) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="green", width=1) + + if self.show_stations.get() == 1: + if i==1: + self.g_plan_canvas.create_line(x, y1, x1, y1, fill="SeaGreen2", width=1) + self.g_plan_canvas.create_line(x, y2, x2, y2, fill="SeaGreen2", width=1) + + mb = moments[0] + mt = moments[-1] + string = 'Mj: {1:.3f} ft-kips\nMi: {0:.3f} ft-kips'.format(mb,mt) + + if col.type == 'UP': + if count == 0: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.SW,font=self.mono_f_chart, text=string, fill='green') + else: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.S,font=self.mono_f_chart, text=string, fill='green') + else: + if count == 0: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.NW,font=self.mono_f_chart, text=string, fill='green') + else: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.N,font=self.mono_f_chart, text=string, fill='green') + + if self.show_s.get()==1 and self.show_col_charts.get()==1: + for i in range(1,len(col.chart_stations)): + if col.type == 'UP': + y1 = h1 - (stations[i-1]*scale) + y2 = h1 - (stations[i]*scale) + else: + y1 = h2 - (stations[i-1]*scale) + y2 = h2 - (stations[i]*scale) + x1 = x - ((eislopes[i-1]/(col.E*col.I)) * s_scale) + x2 = x - ((eislopes[i]/(col.E*col.I)) * s_scale) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="magenta", width=1) + + if self.show_stations.get() == 1: + if i==1: + self.g_plan_canvas.create_line(x, y1, x1, y1, fill="orchid1", width=1) + self.g_plan_canvas.create_line(x, y2, x2, y2, fill="orchid1", width=1) + + sb = eislopes[0]/(col.E*col.I) + st = eislopes[-1]/(col.E*col.I) + string = 'Sj: {1:.5f} kips\nSi: {0:.5f} kips'.format(sb,st) + + if col.type == 'UP': + if count == 0: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.SW,font=self.mono_f_chart, text=string, fill='magenta') + else: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.S,font=self.mono_f_chart, text=string, fill='magenta') + else: + if count == 0: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.NW,font=self.mono_f_chart, text=string, fill='magenta') + else: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.N,font=self.mono_f_chart, text=string, fill='magenta') + + if self.show_d.get()==1 and self.show_col_charts.get()==1: + for i in range(1,len(col.chart_stations)): + if col.type == 'UP': + y1 = h1 - (stations[i-1]*scale) + y2 = h1 - (stations[i]*scale) + else: + y1 = h2 - (stations[i-1]*scale) + y2 = h2 - (stations[i]*scale) + x1 = x - ((eideltas[i-1]/(col.E*col.I)) * d_scale * 12.0) + x2 = x - ((eideltas[i]/(col.E*col.I)) * d_scale * 12.0) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="yellow", width=1) + + if self.show_stations.get() == 1: + if i==1: + self.g_plan_canvas.create_line(x, y1, x1, y1, fill="khaki", width=1) + self.g_plan_canvas.create_line(x, y2, x2, y2, fill="khaki", width=1) + + count +=1 + + def frame_analysis_gui(self, *event): + sorted_load_list = [] + + #sort the load list by beam + for beam in self.beams_analysis: + beam.reset_fem() + sorted_load_list.append([load for load in self.gui_load_list if load[0]==beam.label]) + + for column in self.columns_analysis: + column.reset_fem() + # Determine number of Spans and load patterns + # load patterns will be returned as a list of + # off, on per span + + num_spans = len(self.beams_analysis) + + # Solve for each load case + + for i,beam in enumerate(self.beams_analysis): + beam.new_load_list(sorted_load_list[i]) + + Consider_shortening = self.cols_compress.get() + + precision = float(self.precision.get()) + + frame2d.moment_distribution(self.nodes_analysis,self.beams_analysis,self.columns_analysis,Consider_shortening,precision) + + for beam in self.beams_analysis: + if beam.type == 'span': + beam.build_load_function() + + max_m = 0 + min_m = 0 + for beam in self.beams_analysis: + + if beam.type=='cantilever' and beam.isleft == 1: + start_slope = self.beams_analysis[1].station_values()[0][3][0]/(self.beams_analysis[1].E*self.beams_analysis[1].I) + + beam.add_starting_slope(start_slope) + beam.build_load_function() + + elif beam.type=='cantilever' and beam.isleft == 0: + start_slope = self.beams_analysis[-2].station_values()[0][3][-1]/(self.beams_analysis[-2].E*self.beams_analysis[-2].I) + beam.add_starting_slope(start_slope) + beam.build_load_function() + + + max_m = max(max_m,max(beam.station_values()[0][2])) + min_m = min(min_m,min(beam.station_values()[0][2])) + + self.max_m = max_m + self.min_m = min_m + + for column in self.columns_analysis: + column.build_load_function() + + self.frame_solved = 1 + + self.build_frame_graph() + + + +def main(): + root = tk.Tk() + root.title("2D Frame Analysis by Moment Distribution - Alpha") + main_window(root) + root.minsize(800,600) + root.mainloop() + +if __name__ == '__main__': + main() diff --git a/Analysis/Frame_2D_GUI_metric.py b/Analysis/Frame_2D_GUI_metric.py new file mode 100644 index 0000000..f9c581e --- /dev/null +++ b/Analysis/Frame_2D_GUI_metric.py @@ -0,0 +1,1413 @@ +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' + +from __future__ import division +import Tkinter as tk +import tkMessageBox +import ttk +import tkFont +import tkFileDialog +import Frame_Moment_Distribution_2D as frame2d +import math + +class main_window: + + def __init__(self, master): + + self.master = master + self.inputs = [] + self.beam_count = 0 + self.beam_inputs = [] + self.beam_gui_list = [] + self.cantL_count = 0 + self.cantL_beam_inputs = [] + self.cantL_beam_gui_list = [] + self.cantR_count = 0 + self.cantR_beam_inputs = [] + self.cantR_beam_gui_list = [] + self.column_up_inputs = [] + self.column_up_gui_list = [] + self.column_down_inputs = [] + self.column_down_gui_list = [] + self.nodetorsion_inputs = [] + self.nodetorsion_gui_list = [] + self.beam_labels = [] + self.gui_load_list = [] + self.load_change_index = 0 + self.frame_built = 0 + self.frame_solved = 0 + self.max_h_up_graph = 0 + self.max_h_dwn_graph = 0 + + self.max_m = 0 + self.min_m = 0 + self.max_v = 0 + self.min_v = 0 + self.max_d = 0 + self.min_d = 0 + self.max_s = 0 + self.min_s = 0 + + self.nodes_analysis = [] + self.beams_analysis = [] + self.columns_analysis = [] + + self.load_types = ['Point','Moment','UDL','TRAP'] + + # Font Set + self.f_size = 10 + self.helv = tkFont.Font(family=' Courier New',size=self.f_size, weight='bold') + self.helv_norm = tkFont.Font(family=' Courier New',size=self.f_size) + self.helv_res = tkFont.Font(family=' Courier New',size=self.f_size, weight='bold', underline = True) + self.mono_f = tkFont.Font(family='Consolas',size=8) + self.mono_f_chart = tkFont.Font(family='Consolas',size=10) + + # Menubar + self.menubar = tk.Menu(self.master) + self.menu = tk.Menu(self.menubar, tearoff=0) + self.menu_props = tk.Menu(self.menubar, tearoff=0) + self.menubar.add_cascade(label = "File", menu=self.menu) + #self.menu.add_command(label="Save", command=self.save_inputs) + #self.menu.add_command(label="Open", command=self.open_existing) + self.menu.add_separator() + self.menu.add_command(label="Quit", command=self.quit_app) + try: + self.master.config(menu=self.menubar) + except AttributeError: + self.master.tk.call(master, "config", "-menu", self.menubar) + + #Base Frame + self.base_frame = tk.Frame(master, bd=2, relief='sunken', padx=1,pady=1) + self.base_frame.pack(side=tk.BOTTOM, padx= 1, pady= 1, fill=tk.X) + #Base Frame Items + w=20 + h=1 + + self.b_quit = tk.Button(self.base_frame,text="Quit", command=self.quit_app, font=self.helv, width=w, height=h, bg='red3') + self.b_quit.pack(side=tk.RIGHT) + + self.b_build_frame = tk.Button(self.base_frame,text="Build the Frame", command=self.build_frame_gui_func, font=self.helv, width=w, height=h, bg='cornflower blue') + self.b_build_frame.pack(side=tk.LEFT) + + self.b_solve_frame = tk.Button(self.base_frame,text="Solve the Frame",command=self.frame_analysis_gui, font=self.helv, width=w, height=h, bg='gray75',state=tk.DISABLED) + self.b_solve_frame.pack(side=tk.LEFT) + + self.data_frame = tk.Frame(master, bd=2, relief='sunken', padx=1,pady=1) + self.data_frame.pack(side=tk.LEFT, padx= 1, pady= 1, fill=tk.BOTH, expand=1) + + #Main Notebooks + self.nb_data = ttk.Notebook(self.data_frame) + self.nb_data.pack(fill=tk.BOTH, expand=1) + + # Initial Geometry Input + self.geo_tab = ttk.Frame(self.nb_data) + self.nb_data.add(self.geo_tab, text='Geometry') + + self.geo_tab_frame = tk.Frame(self.geo_tab, bd=2, relief='sunken', padx=1,pady=1) + + self.b_add_beam = tk.Button(self.geo_tab_frame, text="Add a Beam",command=self.add_beam_func, font=self.helv, width=w, height=h) + self.b_add_beam.grid(row=1,column=1) + + self.b_remove_beam = tk.Button(self.geo_tab_frame, text="Remove Last Beam",command=self.remove_last_beam_func, font=self.helv, width=w, height=h, state=tk.DISABLED) + self.b_remove_beam.grid(row=2,column=1) + + self.b_copy_beam = tk.Button(self.geo_tab_frame, text="Copy BM_1 to All",command=self.copy_beam_func, font=self.helv, width=w, height=h) + self.b_copy_beam.grid(row=3,column=1) + + self.b_add_left_cant = tk.Button(self.geo_tab_frame, text="Add Left Cantilever",command=self.add_cant_left_func, font=self.helv, width=w, height=h) + self.b_add_left_cant.grid(row=1,column=2) + + self.b_remove_left_cant = tk.Button(self.geo_tab_frame, text="Remove Left Cantilever",command=self.remove_left_cant_func, font=self.helv, width=w, height=h, state=tk.DISABLED) + self.b_remove_left_cant.grid(row=2,column=2) + + self.b_add_right_cant = tk.Button(self.geo_tab_frame, text="Add Right Cantilever",command=self.add_cant_right_func, font=self.helv, width=w, height=h) + self.b_add_right_cant.grid(row=1,column=3) + + self.b_remove_right_cant = tk.Button(self.geo_tab_frame, text="Remove Right Cantilever",command=self.remove_right_cant_func, font=self.helv, width=w, height=h, state=tk.DISABLED) + self.b_remove_right_cant.grid(row=2,column=3) + + self.precision = tk.StringVar() + self.precision.set('1e-5') + tk.Label(self.geo_tab_frame, text='Calc. Precision:').grid(row=1,column=4) + self.precision_entry = tk.Entry(self.geo_tab_frame, textvariable=self.precision, width=10) + self.precision_entry.grid(row=2, column=4) + + self.col_bm_notebook = ttk.Notebook(self.geo_tab_frame) + self.col_bm_notebook.grid(row=4,column=1, columnspan=4) + + self.bm_info_tab = ttk.Frame(self.col_bm_notebook) + self.col_bm_notebook.add(self.bm_info_tab, text='Beam Data') + + tk.Label(self.bm_info_tab, text='\nLabel:').grid(row=1, column=1) + tk.Label(self.bm_info_tab, text='\nLength (m):').grid(row=1, column=2) + tk.Label(self.bm_info_tab, text='\nE (MPa):').grid(row=1, column=3) + tk.Label(self.bm_info_tab, text='\nI (mm^4):').grid(row=1, column=4) + tk.Label(self.bm_info_tab, text='|\n|').grid(row=1, column=5) + tk.Label(self.bm_info_tab, text='Left Cant.\nLabel:').grid(row=1, column=6) + tk.Label(self.bm_info_tab, text='\nLength (m):').grid(row=1, column=7) + tk.Label(self.bm_info_tab, text='\nE (MPa):').grid(row=1, column=8) + tk.Label(self.bm_info_tab, text='\nI (mm^4):').grid(row=1, column=9) + tk.Label(self.bm_info_tab, text='|\n|').grid(row=1, column=10) + tk.Label(self.bm_info_tab, text='Right Cant.\nLabel:').grid(row=1, column=11) + tk.Label(self.bm_info_tab, text='\nLength (m):').grid(row=1, column=12) + tk.Label(self.bm_info_tab, text='\nE (MPa):').grid(row=1, column=13) + tk.Label(self.bm_info_tab, text='\nI (mm^4):').grid(row=1, column=14) + + self.colup_info_tab = ttk.Frame(self.col_bm_notebook) + self.col_bm_notebook.add(self.colup_info_tab, text='Column Up Data') + + tk.Label(self.colup_info_tab, text='N/A:').grid(row=1, column=1) + tk.Label(self.colup_info_tab, text='Label:').grid(row=1, column=2) + tk.Label(self.colup_info_tab, text='Height (m):').grid(row=1, column=3) + tk.Label(self.colup_info_tab, text='E (MPa):').grid(row=1, column=4) + tk.Label(self.colup_info_tab, text='I (mm^4):').grid(row=1, column=5) + tk.Label(self.colup_info_tab, text='A (mm^2):').grid(row=1, column=6) + tk.Label(self.colup_info_tab, text='Fixed Top:').grid(row=1, column=7) + tk.Label(self.colup_info_tab, text='Hinge at Beam:').grid(row=1, column=8) + + self.b_copy_colup = tk.Button(self.colup_info_tab, text="Copy Col_1 to All",command=self.copy_colup_func, font=self.helv, width=w, height=h) + self.b_copy_colup.grid(row=1,column=9) + + self.coldwn_info_tab = ttk.Frame(self.col_bm_notebook) + self.col_bm_notebook.add(self.coldwn_info_tab, text='Column Down Data') + + tk.Label(self.coldwn_info_tab, text='Label:').grid(row=1, column=1) + tk.Label(self.coldwn_info_tab, text='Height (m):').grid(row=1, column=2) + tk.Label(self.coldwn_info_tab, text='E (MPa):').grid(row=1, column=3) + tk.Label(self.coldwn_info_tab, text='I (mm^4):').grid(row=1, column=4) + tk.Label(self.coldwn_info_tab, text='A (mm^2):').grid(row=1, column=5) + tk.Label(self.coldwn_info_tab, text='Fixed Base:').grid(row=1, column=6) + tk.Label(self.coldwn_info_tab, text='Hinge at Beam:').grid(row=1, column=7) + + self.b_copy_coldwn = tk.Button(self.coldwn_info_tab, text="Copy Col_1 to All",command=self.copy_coldwn_func, font=self.helv, width=w, height=h) + self.b_copy_coldwn.grid(row=1,column=8) + + self.cols_compress = tk.IntVar() + self.cols_compress.set(1) + tk.Checkbutton(self.coldwn_info_tab, text=' : Columns are Compressible', variable=self.cols_compress,font=self.helv).grid(row=2, column=8, sticky = tk.W) + + self.geo_tab_frame.pack(fill=tk.BOTH, expand=1) + + #Loads Frame tabs + #Loads + self.loads_tab = ttk.Frame(self.nb_data) + self.nb_data.add(self.loads_tab, text='Loads') + + self.g_loads_frame = tk.Frame(self.loads_tab, bd=2, relief='sunken', padx=1,pady=1) + + # Load Types and Combinations + self.g_load_types_frame = tk.Frame(self.g_loads_frame, bd=2, relief='sunken', padx=1,pady=1) + + self.load_kinds = ['SELF','DL','LL','LL_pat'] + self.load_kinds_var_list = [] + self.load_combinations = [['All_DL',1,1,0,0],['ALL_LL',0,0,1,1],['DL_LL',1,1,1,1],['CONC_D',3,3,1,1],['LRFD_1',1.4,1.4,0,0],['LRFD_2',1.2,1.2,1.6,1.6]] + self.load_combinations_var_list = [] + self.load_combo_gui_items = [] + + i=0 + for kind in self.load_kinds: + a = tk.Label(self.g_load_types_frame, text=kind) + a.grid(row=1,column=1+i) + i+=1 + self.load_combo_gui_items.append(a) + + i=0 + for combo in self.load_combinations: + var_list = [] + j=0 + for item in combo: + var_list.append(tk.StringVar()) + var_list[-1].set(item) + if j==0: + a = tk.Entry(self.g_load_types_frame, textvariable=var_list[-1], width=8) + else: + a = tk.Entry(self.g_load_types_frame, textvariable=var_list[-1], width=4) + a.grid(row=2+i,column=j) + self.load_combo_gui_items.append(a) + j+=1 + i+=1 + + self.g_load_types_frame.pack(side=tk.LEFT, fill=tk.Y) + + self.g_applied_loads_frame = tk.Frame(self.g_loads_frame, bd=2, relief='sunken', padx=1,pady=1) + + tk.Label(self.g_applied_loads_frame, text='On Beam:').grid(row=1,column=1) + tk.Label(self.g_applied_loads_frame, text='P,M,W1:\n(kN,kN*m,kN/m)').grid(row=1,column=2) + tk.Label(self.g_applied_loads_frame, text='W2:\n(kN/m)').grid(row=1,column=3) + tk.Label(self.g_applied_loads_frame, text='a:\n(m)').grid(row=1,column=4) + tk.Label(self.g_applied_loads_frame, text='b:\n(m)').grid(row=1,column=5) + tk.Label(self.g_applied_loads_frame, text='kind:').grid(row=1,column=6) + tk.Label(self.g_applied_loads_frame, text='type:').grid(row=1,column=7) + + self.load_span_select = tk.StringVar() + self.load_span_select.set('BM_1') + spans = ['BM_1'] + self.load_span_selection = tk.OptionMenu(self.g_applied_loads_frame, self.load_span_select, *spans) + self.load_span_selection.grid(row=2,column=1, sticky = tk.W) + + self.w1_gui = tk.StringVar() + self.w2_gui = tk.StringVar() + self.a_gui = tk.StringVar() + self.b_gui = tk.StringVar() + + self.w1_gui.set(0) + self.w2_gui.set(0) + self.a_gui.set(0) + self.b_gui.set(0) + + self.w1_gui_entry = tk.Entry(self.g_applied_loads_frame, textvariable=self.w1_gui, width=8) + self.w1_gui_entry.grid(row=2,column=2, sticky = tk.W) + self.w2_gui_entry = tk.Entry(self.g_applied_loads_frame, textvariable=self.w2_gui, width=8) + self.w2_gui_entry.grid(row=2,column=3, sticky = tk.W) + self.a_gui_entry = tk.Entry(self.g_applied_loads_frame, textvariable=self.a_gui, width=8) + self.a_gui_entry.grid(row=2,column=4, sticky = tk.W) + self.b_gui_entry = tk.Entry(self.g_applied_loads_frame, textvariable=self.b_gui, width=8) + self.b_gui_entry.grid(row=2,column=5, sticky = tk.W) + + self.load_type = tk.StringVar() + self.load_type.set('Point') + load_types = ['Point','Moment','UDL','TRAP'] + self.load_type_selection = tk.OptionMenu(self.g_applied_loads_frame, self.load_type, *load_types) + self.load_type_selection.grid(row=2,column=6, sticky = tk.W) + + self.load_kind_select = tk.StringVar() + self.load_kind_select.set('DL') + load_kinds = ['SELF','DL','LL','LL_pat'] + self.load_kind_selection = tk.OptionMenu(self.g_applied_loads_frame, self.load_kind_select, *load_kinds) + self.load_kind_selection.grid(row=2,column=7, sticky = tk.W) + + self.loads_list_bframe = tk.Frame(self.g_applied_loads_frame, pady=5) + self.b_add_load = tk.Button(self.loads_list_bframe, text="Add Load",command=self.add_load_gui, font=self.helv, width=12, height=h) + self.b_add_load.grid(row=1,column=1) + + self.b_change_load = tk.Button(self.loads_list_bframe, text="Edit Load",command=self.change_load_gui, font=self.helv, width=12, height=h, state=tk.DISABLED, bg='gray75') + self.b_change_load.grid(row=2,column=1) + + self.b_remove_load = tk.Button(self.loads_list_bframe, text="Del Load",command=self.remove_load_gui, font=self.helv, width=12, height=h, state=tk.DISABLED, bg='gray75') + self.b_remove_load.grid(row=3,column=1) + + self.b_add_all_load = tk.Button(self.loads_list_bframe, text='Add to All', command=self.add_load_to_all_gui, font=self.helv, width=12, height=h) + self.b_add_all_load.grid(row=4,column=1) + + self.b_remove_all_loads = tk.Button(self.loads_list_bframe, text='*Del All*', command=self.remove_all_loads_gui, font=self.helv, width=12, height=h, bg='red3') + self.b_remove_all_loads.grid(row=5,column=1) + + self.loads_list_bframe.grid(row=3, column=1, sticky=tk.N) + + self.loads_list_frame = tk.Frame(self.g_applied_loads_frame, pady=5) + + self.loads_scrollbar = tk.Scrollbar(self.loads_list_frame, orient="vertical") + self.loads_scrollbar.grid(row=1, column=2, sticky=tk.NS) + + self.load_listbox = tk.Listbox(self.loads_list_frame, height = 20, width = 50, font=self.helv, yscrollcommand=self.loads_scrollbar.set) + self.load_listbox.grid(row=1, column=1) + self.load_listbox.bind("<>",self.load_listbox_click) + + self.loads_scrollbar.configure(command=self.load_listbox.yview) + + self.loads_list_frame.grid(row=3, column=2, columnspan=6) + + self.g_applied_loads_frame.pack(side=tk.RIGHT, fill=tk.Y) + + self.g_loads_frame.pack(fill=tk.BOTH,expand=1, padx=5, pady=5) + + #Graphics Frame tabs and canvases + #Geometry - Graph + self.graph_tab = ttk.Frame(self.nb_data) + self.nb_data.add(self.graph_tab, text='Graph') + + self.g_a_frame = tk.Frame(self.graph_tab, bd=2, relief='sunken', padx=1,pady=1) + self.g_a_frame.pack(fill=tk.BOTH,expand=1, padx=5, pady=5) + + self.g_plan_canvas = tk.Canvas(self.g_a_frame, width=50, height=50, bd=2, relief='sunken', background="black") + #self.g_plan_canvas.bind("", self.build_frame_graph) + self.g_plan_canvas.pack(side = tk.LEFT, anchor='w', padx= 1, pady= 1, fill=tk.BOTH, expand=1) + + self.origin = self.g_plan_canvas.xview()[0], self.g_plan_canvas.yview()[0] + + self.g_plan_canvas.bind("", self.canvas_mouse_start) + self.g_plan_canvas.bind("", self.canvas_mouse_move) + self.g_plan_canvas.bind_all("", self.canvas_zoom) + self.g_plan_canvas.bind("", self.canvas_reset) + + self.graph_b_frame = tk.Frame(self.g_a_frame, bd=2, relief='sunken', padx=4 ,pady=1) + + self.show_l = tk.IntVar() + self.show_l.set(1) + tk.Checkbutton(self.graph_b_frame, text=' : Show Loads', variable=self.show_l, command=self.build_frame_graph,font=self.helv).grid(row=1, column=1, sticky = tk.W) + self.show_v = tk.IntVar() + tk.Checkbutton(self.graph_b_frame, text=' : Show V', variable=self.show_v, command=self.build_frame_graph, font=self.helv).grid(row=2, column=1, sticky = tk.W) + self.show_m = tk.IntVar() + tk.Checkbutton(self.graph_b_frame, text=' : Show M', variable=self.show_m, command=self.build_frame_graph, font=self.helv).grid(row=3, column=1, sticky = tk.W) + self.show_m_tension = tk.IntVar() + self.show_m_tension.set(1) + tk.Checkbutton(self.graph_b_frame, text=' : M on tension face', variable=self.show_m_tension, command=self.build_frame_graph, font=self.helv).grid(row=4, column=1, sticky = tk.E) + self.show_s = tk.IntVar() + tk.Checkbutton(self.graph_b_frame, text=' : Show S', variable=self.show_s, command=self.build_frame_graph, font=self.helv).grid(row=5, column=1, sticky = tk.W) + self.show_d = tk.IntVar() + tk.Checkbutton(self.graph_b_frame, text=' : Show D', variable=self.show_d, command=self.build_frame_graph, font=self.helv).grid(row=6, column=1, sticky = tk.W) + self.show_r = tk.IntVar() + tk.Checkbutton(self.graph_b_frame, text=' : Show Reactions', variable=self.show_r, command=self.build_frame_graph, font=self.helv).grid(row=7, column=1, sticky = tk.W) + self.show_dfs = tk.IntVar() + tk.Checkbutton(self.graph_b_frame, text=" : Show DF's", variable=self.show_dfs, command=self.build_frame_graph, font=self.helv).grid(row=8, column=1, sticky = tk.W) + self.show_col_charts = tk.IntVar() + self.show_col_charts.set(1) + tk.Checkbutton(self.graph_b_frame, text=' : Show Col\nCharts', variable=self.show_col_charts, command=self.build_frame_graph, font=self.helv).grid(row=9, column=1, sticky = tk.W) + self.show_bm_charts = tk.IntVar() + self.show_bm_charts.set(1) + tk.Checkbutton(self.graph_b_frame, text=' : Show Bm\nCharts', variable=self.show_bm_charts, command=self.build_frame_graph, font=self.helv).grid(row=10, column=1, sticky = tk.W) + + self.show_stations = tk.IntVar() + self.show_stations.set(1) + tk.Checkbutton(self.graph_b_frame, text=' : Show Stations', variable=self.show_stations, command=self.build_frame_graph, font=self.helv).grid(row=11, column=1, sticky = tk.W) + + self.refresh_graphic = tk.Button(self.graph_b_frame, text="Refresh/Reset",command=self.build_frame_graph, font=self.helv, width=15, height=h) + self.refresh_graphic.grid(row=12, column=1) + + tk.Label(self.graph_b_frame, text='Result Scale:', font=self.helv).grid(row=13, column=1, sticky=tk.W) + self.res_scale = tk.StringVar() + self.res_scale.set('10') + self.res_scale_entry = tk.Entry(self.graph_b_frame, textvariable=self.res_scale, width=8) + self.res_scale_entry.grid(row=13, column=2, sticky=tk.W) + + self.graph_b_frame.pack(side=tk.RIGHT, anchor='e') + + # Call function to display license dialog on app start + self.add_beam_func() + self.license_display() + + def license_display(self, *event): + # Function to display license dialog on app start + license_string = ("Copyright (c) 2019, Donald N. Bockoven III\n" + "All rights reserved.\n\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" + " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" + " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" + " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" + " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" + " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" + " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," + " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" + "https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE" + ) + + tkMessageBox.showerror("License Information",license_string) + self.master.focus_force() + + def quit_app(self,*args): + self.master.quit() + self.master.destroy() + + def canvas_mouse_start(self, event): + self.g_plan_canvas.scan_mark(event.x, event.y) + + def canvas_mouse_move(self, event): + self.g_plan_canvas.scan_dragto(event.x, event.y, gain=1) + + def canvas_zoom(self, event): + #x = self.g_plan_canvas.canvasx(event.x) + #y = self.g_plan_canvas.canvasx(event.y) + + w = self.g_plan_canvas.winfo_width() + h = self.g_plan_canvas.winfo_height() + + x = w/2 + y = h/2 + + if event.delta > 0: + self.g_plan_canvas.scale('all', x, y, 1.1, 1.1) + elif event.delta < 0: + self.g_plan_canvas.scale('all', x, y, 0.9, 0.9) + + def canvas_reset(self, *args): + x, y = self.origin + self.g_plan_canvas.yview_moveto(x) + self.g_plan_canvas.xview_moveto(y) + + def add_beam_func(self, *event): + self.frame_built = 0 + self.frame_solved = 0 + self.beam_count +=1 + + self.b_remove_beam.configure(state=tk.NORMAL) + self.b_solve_frame.configure(state=tk.DISABLED, bg='red3') + + self.beam_inputs.append([tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar()]) + self.beam_inputs[-1][1].set(1) + self.beam_inputs[-1][2].set(199948) + self.beam_inputs[-1][3].set(1.28199e7) + + + if self.beam_count == 1: + self.column_up_inputs.append([tk.IntVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.IntVar(),tk.IntVar()]) + self.column_up_inputs.append([tk.IntVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.IntVar(),tk.IntVar()]) + self.column_down_inputs.append([tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.IntVar(),tk.IntVar()]) + self.column_down_inputs.append([tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.IntVar(),tk.IntVar()]) + + self.column_up_inputs[-2][1].set('COL_UP_{0}'.format(self.beam_count)) + self.column_up_inputs[-2][2].set(1) + self.column_up_inputs[-2][3].set(199948) + self.column_up_inputs[-2][4].set(1.28199e7) + self.column_up_inputs[-2][5].set(1909.674) + self.column_up_inputs[-2][6].set(1) + + self.column_up_inputs[-1][1].set('COL_UP_{0}'.format(self.beam_count+1)) + self.column_up_inputs[-1][2].set(1) + self.column_up_inputs[-1][3].set(199948) + self.column_up_inputs[-1][4].set(1.28199e7) + self.column_up_inputs[-1][5].set(1909.674) + self.column_up_inputs[-1][6].set(1) + + self.column_down_inputs[-2][0].set('COL_DWN_{0}'.format(self.beam_count)) + self.column_down_inputs[-2][1].set(1) + self.column_down_inputs[-2][2].set(199948) + self.column_down_inputs[-2][3].set(1.28199e7) + self.column_down_inputs[-2][4].set(1909.674) + self.column_down_inputs[-2][5].set(1) + + self.column_down_inputs[-1][0].set('COL_DWN_{0}'.format(self.beam_count+1)) + self.column_down_inputs[-1][1].set(1) + self.column_down_inputs[-1][2].set(199948) + self.column_down_inputs[-1][3].set(1.28199e7) + self.column_down_inputs[-1][4].set(1909.674) + self.column_down_inputs[-1][5].set(1) + else: + self.column_up_inputs.append([tk.IntVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.IntVar(),tk.IntVar()]) + self.column_down_inputs.append([tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.IntVar(),tk.IntVar()]) + + self.column_up_inputs[-1][1].set('COL_UP_{0}'.format(self.beam_count+1)) + self.column_up_inputs[-1][2].set(self.column_up_inputs[-2][2].get()) + self.column_up_inputs[-1][3].set(self.column_up_inputs[-2][3].get()) + self.column_up_inputs[-1][4].set(self.column_up_inputs[-2][4].get()) + self.column_up_inputs[-1][5].set(self.column_up_inputs[-2][5].get()) + self.column_up_inputs[-1][6].set(self.column_up_inputs[-2][6].get()) + + self.column_down_inputs[-1][0].set('COL_DWN_{0}'.format(self.beam_count+1)) + self.column_down_inputs[-1][1].set(self.column_down_inputs[-2][1].get()) + self.column_down_inputs[-1][2].set(self.column_down_inputs[-2][2].get()) + self.column_down_inputs[-1][3].set(self.column_down_inputs[-2][3].get()) + self.column_down_inputs[-1][4].set(self.column_down_inputs[-2][4].get()) + self.column_down_inputs[-1][5].set(self.column_down_inputs[-2][5].get()) + + self.beam_inputs[-1][0].set('BM_{0}'.format(self.beam_count)) + self.beam_labels.append('BM_{0}'.format(self.beam_count)) + self.refesh_span_options() + + self.build_bm_gui_table() + self.build_colup_gui_table() + self.build_coldwn_gui_table() + + def copy_beam_func(self, *args): + + l = self.beam_inputs[0][1].get() + E = self.beam_inputs[0][2].get() + I = self.beam_inputs[0][3].get() + + for i, bm in enumerate(self.beam_inputs): + bm[1].set(l) + bm[2].set(E) + bm[3].set(I) + + def copy_colup_func(self, *args): + + na = self.column_up_inputs[0][0].get() + h = self.column_up_inputs[0][2].get() + E = self.column_up_inputs[0][3].get() + I = self.column_up_inputs[0][4].get() + A = self.column_up_inputs[0][5].get() + fix = self.column_up_inputs[0][6].get() + hinge = self.column_up_inputs[0][7].get() + + for i, col in enumerate(self.column_up_inputs): + col[0].set(na) + col[2].set(h) + col[3].set(E) + col[4].set(I) + col[5].set(A) + col[6].set(fix) + col[7].set(hinge) + + def copy_coldwn_func(self, *args): + + h = self.column_down_inputs[0][1].get() + E = self.column_down_inputs[0][2].get() + I = self.column_down_inputs[0][3].get() + A = self.column_down_inputs[0][4].get() + fix = self.column_down_inputs[0][5].get() + hinge = self.column_down_inputs[0][6].get() + + for i, col in enumerate(self.column_down_inputs): + col[1].set(h) + col[2].set(E) + col[3].set(I) + col[4].set(A) + col[5].set(fix) + col[6].set(hinge) + + def add_cant_left_func(self,*event): + + if self.cantL_count == 0: + self.frame_built = 0 + self.frame_solved = 0 + self.cantL_count +=1 + self.b_remove_left_cant.configure(state=tk.NORMAL) + self.b_add_left_cant.configure(state=tk.DISABLED) + self.b_solve_frame.configure(state=tk.DISABLED, bg='red3') + self.cantL_beam_inputs.append([tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar()]) + self.cantL_beam_inputs[-1][1].set(0.5) + self.cantL_beam_inputs[-1][2].set(199948) + self.cantL_beam_inputs[-1][3].set(1.28199e7) + + bm = self.cantL_beam_inputs[0] + bm[0].set('CantL') + self.beam_labels.append('CantL') + self.refesh_span_options() + + a = tk.Entry(self.bm_info_tab,textvariable=bm[0], width=8, state=tk.DISABLED) + a.grid(row=2,column=6) + b = tk.Entry(self.bm_info_tab,textvariable=bm[1], width=8) + b.grid(row=2,column=7) + c = tk.Entry(self.bm_info_tab,textvariable=bm[2], width=8) + c.grid(row=2,column=8) + d = tk.Entry(self.bm_info_tab,textvariable=bm[3], width=8) + d.grid(row=2,column=9) + + self.cantL_beam_gui_list.extend([a,b,c,d]) + + else: + pass + + def remove_left_cant_func(self,*event): + if self.cantL_count > 0: + self.frame_built = 0 + self.frame_solved = 0 + self.cantL_count -=1 + self.beam_labels.remove('CantL') + self.refesh_span_options() + self.b_remove_left_cant.configure(state=tk.DISABLED) + self.b_solve_frame.configure(state=tk.DISABLED, bg='red3') + self.b_add_left_cant.configure(state=tk.NORMAL) + for element in self.cantL_beam_gui_list: + element.destroy() + + del self.cantL_beam_gui_list[:] + + def remove_right_cant_func(self,*event): + if self.cantR_count > 0: + self.frame_built = 0 + self.frame_solved = 0 + self.cantR_count -=1 + self.beam_labels.remove('CantR') + self.refesh_span_options() + self.b_remove_right_cant.configure(state=tk.DISABLED) + self.b_add_right_cant.configure(state=tk.NORMAL) + self.b_solve_frame.configure(state=tk.DISABLED, bg='red3') + for element in self.cantR_beam_gui_list: + element.destroy() + + del self.cantR_beam_gui_list[:] + + def add_cant_right_func(self,*event): + if self.cantR_count == 0: + self.frame_built = 0 + self.frame_solved = 0 + self.cantR_count +=1 + self.b_remove_right_cant.configure(state=tk.NORMAL) + self.b_add_right_cant.configure(state=tk.DISABLED) + self.b_solve_frame.configure(state=tk.DISABLED, bg='red3') + self.cantR_beam_inputs.append([tk.StringVar(),tk.StringVar(),tk.StringVar(),tk.StringVar()]) + self.cantR_beam_inputs[-1][1].set(0.5) + self.cantR_beam_inputs[-1][2].set(199948) + self.cantR_beam_inputs[-1][3].set(1.28199e7) + + bm = self.cantR_beam_inputs[0] + bm[0].set('CantR') + self.beam_labels.append('CantR') + self.refesh_span_options() + + a = tk.Entry(self.bm_info_tab,textvariable=bm[0], width=8, state=tk.DISABLED) + a.grid(row=2,column=11) + b = tk.Entry(self.bm_info_tab,textvariable=bm[1], width=8) + b.grid(row=2,column=12) + c = tk.Entry(self.bm_info_tab,textvariable=bm[2], width=8) + c.grid(row=2,column=13) + d = tk.Entry(self.bm_info_tab,textvariable=bm[3], width=8) + d.grid(row=2,column=14) + + self.cantR_beam_gui_list.extend([a,b,c,d]) + + else: + pass + + def remove_last_beam_func(self,*event): + if self.beam_count <= 1: + pass + else: + self.b_solve_frame.configure(state=tk.DISABLED, bg='red3') + self.beam_count -=1 + self.frame_built = 0 + self.frame_solved = 0 + self.beam_labels.remove(self.beam_inputs[-1][0].get()) + + self.refesh_span_options() + + del self.beam_inputs[-1] + del self.column_up_inputs[-1] + del self.column_down_inputs[-1] + #del self.nodetorsion_inputs[-1] + + self.build_bm_gui_table() + self.build_colup_gui_table() + self.build_coldwn_gui_table() + + def build_bm_gui_table(self,*event): + + for element in self.beam_gui_list: + element.destroy() + + del self.beam_gui_list[:] + + for i,bm in enumerate(self.beam_inputs): + + a = tk.Entry(self.bm_info_tab,textvariable=bm[0], width=8, state=tk.DISABLED) + a.grid(row=i+2,column=1, pady=4) + b = tk.Entry(self.bm_info_tab,textvariable=bm[1], width=8) + b.grid(row=i+2,column=2) + c = tk.Entry(self.bm_info_tab,textvariable=bm[2], width=8) + c.grid(row=i+2,column=3) + d = tk.Entry(self.bm_info_tab,textvariable=bm[3], width=8) + d.grid(row=i+2,column=4) + + self.beam_gui_list.extend([a,b,c,d]) + + def build_colup_gui_table(self,*event): + for element in self.column_up_gui_list: + element.destroy() + + del self.column_up_gui_list[:] + + for i,col in enumerate(self.column_up_inputs): + + a = tk.Checkbutton(self.colup_info_tab,variable=col[0]) + a.grid(row=i+2,column=1) + b = tk.Entry(self.colup_info_tab,textvariable=col[1], width=12, state=tk.DISABLED) + b.grid(row=i+2,column=2) + c = tk.Entry(self.colup_info_tab,textvariable=col[2], width=8) + c.grid(row=i+2,column=3) + d = tk.Entry(self.colup_info_tab,textvariable=col[3], width=8) + d.grid(row=i+2,column=4) + e = tk.Entry(self.colup_info_tab,textvariable=col[4], width=8) + e.grid(row=i+2,column=5) + f = tk.Entry(self.colup_info_tab,textvariable=col[5], width=8) + f.grid(row=i+2,column=6) + g = tk.Checkbutton(self.colup_info_tab,variable=col[6]) + g.grid(row=i+2,column=7) + h = tk.Checkbutton(self.colup_info_tab,variable=col[7]) + h.grid(row=i+2,column=8) + + self.column_up_gui_list.extend([a,b,c,d,e,f,g,h]) + + def build_coldwn_gui_table(self,*event): + for element in self.column_down_gui_list: + element.destroy() + + del self.column_down_gui_list[:] + + for i,col in enumerate(self.column_down_inputs): + + b = tk.Entry(self.coldwn_info_tab,textvariable=col[0], width=12, state=tk.DISABLED) + b.grid(row=i+2,column=1) + c = tk.Entry(self.coldwn_info_tab,textvariable=col[1], width=8) + c.grid(row=i+2,column=2) + d = tk.Entry(self.coldwn_info_tab,textvariable=col[2], width=8) + d.grid(row=i+2,column=3) + e = tk.Entry(self.coldwn_info_tab,textvariable=col[3], width=8) + e.grid(row=i+2,column=4) + f = tk.Entry(self.coldwn_info_tab,textvariable=col[4], width=8) + f.grid(row=i+2,column=5) + g = tk.Checkbutton(self.coldwn_info_tab,variable=col[5]) + g.grid(row=i+2,column=6) + h = tk.Checkbutton(self.coldwn_info_tab,variable=col[6]) + h.grid(row=i+2,column=7) + + self.column_down_gui_list.extend([b,c,d,e,f,g,h]) + + def refesh_span_options(self,*event): + self.load_span_selection['menu'].delete(0,'end') + for choice in self.beam_labels: + self.load_span_selection['menu'].add_command(label=choice, command=tk._setit(self.load_span_select, choice)) + + def add_load_gui(self,*event): + span = self.load_span_select.get() + w1 = float(self.w1_gui.get()) + w2 = float(self.w2_gui.get()) + a = float(self.a_gui.get()) + b = float(self.b_gui.get()) + type = self.load_type.get() + kind = self.load_kind_select.get() + + self.gui_load_list.append([span,w1,w2,a,b,type,kind]) + self.b_change_load.configure(state=tk.DISABLED, bg='gray75') + self.b_remove_load.configure(state=tk.DISABLED, bg='gray75') + + self.fill_load_listbox() + + def remove_load_gui(self,*event): + if len(self.gui_load_list)==0: + pass + else: + del self.gui_load_list[self.load_change_index] + self.b_change_load.configure(state=tk.DISABLED, bg='gray75') + self.b_remove_load.configure(state=tk.DISABLED, bg='gray75') + self.fill_load_listbox() + + def change_load_gui(self,*event): + del self.gui_load_list[self.load_change_index] + self.b_change_load.configure(state=tk.DISABLED, bg='gray75') + self.b_remove_load.configure(state=tk.DISABLED, bg='gray75') + self.add_load_gui() + + def add_load_to_all_gui(self,*event): + + w1 = float(self.w1_gui.get()) + w2 = float(self.w2_gui.get()) + a = float(self.a_gui.get()) + b = float(self.b_gui.get()) + type = self.load_type.get() + kind = self.load_kind_select.get() + + for beam_gui in self.beam_inputs: + + span = beam_gui[0].get() + b_max = float(beam_gui[1].get()) + + b_use = min(b,b_max) + + self.gui_load_list.append([span,w1,w2,a,b_use,type,kind]) + + self.fill_load_listbox() + + def remove_all_loads_gui(self,*event): + if len(self.gui_load_list)==0: + pass + else: + del self.gui_load_list[:] + self.b_change_load.configure(state=tk.DISABLED, bg='gray75') + self.b_remove_load.configure(state=tk.DISABLED, bg='gray75') + self.fill_load_listbox() + + def load_listbox_click(self,*event): + if self.load_listbox.size()==0: + pass + else: + self.b_change_load.configure(state=tk.NORMAL, bg='yellow2') + self.b_remove_load.configure(state=tk.NORMAL, bg='red3') + + self.selected_load = self.load_listbox.get(self.load_listbox.curselection()[0]).split(',') + self.load_change_index = self.load_listbox.curselection()[0] + + self.load_span_select.set(self.selected_load[0]) + self.w1_gui.set(self.selected_load[1]) + self.w2_gui.set(self.selected_load[2]) + self.a_gui.set(self.selected_load[3]) + self.b_gui.set(self.selected_load[4]) + self.load_type.set(self.selected_load[5]) + self.load_kind_select.set(self.selected_load[6]) + + def fill_load_listbox(self,*event): + self.b_solve_frame.configure(state=tk.DISABLED, bg='red3') + self.frame_solved = 0 + + self.load_listbox.delete(0,tk.END) + + color = "pale green" + i=0 + for x in self.gui_load_list: + self.load_listbox.insert(tk.END,'{0},{1:.3f},{2:.3f},{3:.3f},{4:.3f},{5},{6}'.format(x[0],x[1],x[2],x[3],x[4],x[5],x[6])) + + if i % 2 == 0: + self.load_listbox.itemconfigure(i, background=color) + else: + pass + i+=1 + + def build_frame_gui_func(self,*event): + + del self.beams_analysis[:] + del self.nodes_analysis[:] + del self.columns_analysis[:] + self.max_h_up_graph = 0 + self.max_h_dwn_graph = 0 + + if self.cantL_count == 0: + self.nodes_analysis.append(frame2d.node(0)) + else: + cantL_label = self.cantL_beam_inputs[-1][0].get() + cantL_span = float(self.cantL_beam_inputs[-1][1].get()) + E_ksf = float(self.cantL_beam_inputs[-1][2].get())* (1/1000) * (1/math.pow(0.001,2)) #convert Mpa = N/mm^2 to kN/m^2 + I_ft4 = float(self.cantL_beam_inputs[-1][3].get()) * (math.pow(0.001,4)) #covert from mm^4 to m^4 + self.nodes_analysis.append(frame2d.node(cantL_span)) + j = self.nodes_analysis[-1] + + cantL = frame2d.CantBeam(j, E_ksf, I_ft4, cantL_span, [], 1, cantL_label) + + self.beams_analysis.append(cantL) + + for beam_gui in self.beam_inputs: + + label = beam_gui[0].get() + span = float(beam_gui[1].get()) + j = self.nodes_analysis[-1].x + span + self.nodes_analysis.append(frame2d.node(j)) + newi = self.nodes_analysis[-2] + newj = self.nodes_analysis[-1] + E_ksf = float(self.beam_inputs[-1][2].get())* (1/1000) * (1/math.pow(0.001,2)) #convert Mpa = N/mm^2 to kN/m^2 + I_ft4 = float(self.beam_inputs[-1][3].get()) * (math.pow(0.001,4)) #covert from mm^4 to m^4 + + beam = frame2d.Beam(newi,newj,E_ksf,I_ft4, [], label) + + self.beams_analysis.append(beam) + + if self.cantR_count == 0: + pass + + else: + cantR_label = self.cantR_beam_inputs[-1][0].get() + cantR_span = float(self.cantR_beam_inputs[-1][1].get()) + E_ksf = float(self.cantR_beam_inputs[-1][2].get())* (1/1000) * (1/math.pow(0.001,2)) #convert Mpa = N/mm^2 to kN/m^2 + I_ft4 = float(self.cantR_beam_inputs[-1][3].get()) * (math.pow(0.001,4)) #covert from mm^4 to m^4 + i = self.nodes_analysis[-1] + + cantR = frame2d.CantBeam(i, E_ksf, I_ft4, cantR_span, [], 0, cantR_label) + + self.beams_analysis.append(cantR) + + for i,col in enumerate(self.column_down_inputs): + j_node = self.nodes_analysis[i] + height=float(col[1].get()) + E=float(col[2].get())* (1/1000) * (1/math.pow(0.001,2)) #convert Mpa = N/mm^2 to kN/m^2 + I=float(col[3].get()) * (math.pow(0.001,4)) #covert from mm^4 to m^4 + A=float(col[4].get())*math.pow(0.001,2) #convert mm^2 to m^2 + support=col[5].get() + hinge_near=col[6].get() + + column_dwn = frame2d.Column_Down(j_node, height, E, I, A, support, hinge_near) + + self.max_h_dwn_graph = max(self.max_h_dwn_graph,height) + + self.columns_analysis.append(column_dwn) + + for i,col in enumerate(self.column_up_inputs): + + if col[0].get() == 1: + pass + + else: + i_node = self.nodes_analysis[i] + height=float(col[2].get()) + E=float(col[3].get())* (1/1000) * (1/math.pow(0.001,2)) #convert Mpa = N/mm^2 to kN/m^2 + I=float(col[4].get()) * (math.pow(0.001,4)) #covert from mm^4 to m^4 + A=float(col[5].get())*math.pow(0.001,2) #convert mm^2 to m^2 + support=col[6].get() + hinge_near=col[7].get() + + self.max_h_up_graph = max(self.max_h_up_graph,height) + + column_up = frame2d.Column_Up(i_node, height, E, I, A, support, hinge_near) + + self.columns_analysis.append(column_up) + + + self.frame_built = 1 + self.frame_solved = 0 + + self.b_solve_frame.configure(state=tk.NORMAL, bg='cornflower blue') + + self.build_frame_graph() + + def build_frame_graph(self,*event): + if self.frame_built == 0: + pass + + else: + self.g_plan_canvas.delete("all") + self.canvas_reset() + w = self.g_plan_canvas.winfo_width() + h = self.g_plan_canvas.winfo_height() + hg = (h/2.0) + + spacer= 30 + + if self.cantR_count == 0: + total_length = self.nodes_analysis[-1].x + else: + total_length = self.nodes_analysis[-1].x + self.beams_analysis[-1].Length + + scale_x = (w - 2*spacer) / total_length + + scale_y = (hg-spacer)/ max(self.max_h_dwn_graph,self.max_h_up_graph) + + scale = min(scale_x, scale_y) + + v_scale = float(self.res_scale.get()) + + s_scale = float(self.res_scale.get()) + + d_scale = float(self.res_scale.get()) + + if self.show_m_tension.get() == 1: + m_scale = float(self.res_scale.get())* -1 + else: + m_scale = float(self.res_scale.get()) + + for i,node in enumerate(self.nodes_analysis): + if node == self.nodes_analysis[-1]: + pass + else: + x1 = (node.x*scale) + spacer + x2 = (self.nodes_analysis[i+1].x*scale)+spacer + self.g_plan_canvas.create_line(x1, hg, x2, hg, fill="white", width=2) + + max_x = x2 + + if self.cantL_count == 0: + pass + else: + x1 = spacer + x2 = (node.x*scale) + spacer + self.g_plan_canvas.create_line(x1, hg, x2, hg, fill="white", width=2) + + if self.cantR_count == 0: + pass + else: + + x1 = (self.nodes_analysis[-1].x*scale)+spacer + x2 = ((self.nodes_analysis[-1].x+self.beams_analysis[-1].Length)*scale)+spacer + self.g_plan_canvas.create_line(x1, hg, x2, hg, fill="white", width=2) + max_x = x2 + + if self.frame_solved == 0: + pass + else: + for beam in self.beams_analysis: + values, end_delta = beam.station_values() + stations = values[0] + shears = values[1] + moments = values[2] + eislopes = values[3] + eideltas = values[4] + + if self.show_l.get() == 1 and self.show_bm_charts.get()==1: + + for load in beam.Loads: + if load == beam.Loads[-1] or load == beam.Loads[-2] and beam.type == 'span': + pass + else: + y_scale = float(self.res_scale.get()) + x_scale = scale + + x0 = (beam.i.x)*x_scale + + x,y = load.chart_load(x_scale,y_scale,1) + + x = [i+x0 for i in x] + + for i in range(1,len(x)): + self.g_plan_canvas.create_line((x[i-1]+spacer),hg - (y[i-1]),(x[i])+spacer,hg - (y[i]), fill = "blue", width=2) + + if self.show_dfs.get() == 1 and self.show_bm_charts.get()==1: + string = 'DFi: {0:.3f}\nDFj: {1:.3f} '.format(beam.dfi,beam.dfj) + x0 = (((beam.i.x+beam.j.x)/2)*scale) + spacer + + self.g_plan_canvas.create_text(x0, hg+12, anchor=tk.N, font=self.mono_f_chart, text=string, fill='cyan') + + if self.show_r.get() == 1 and self.show_bm_charts.get()==1: + string = 'Riy: {0:.3f} kN\nRjy: {1:.3f} kN'.format(beam.reactions()[0],beam.reactions()[1]) + x0 = (((beam.i.x+beam.j.x)/2)*scale) + spacer + + self.g_plan_canvas.create_text(x0, hg+12, anchor=tk.N, font=self.mono_f_chart, text=string, fill='red') + + if self.show_v.get()==1 and self.show_bm_charts.get()==1: + for i in range(1,len(stations)): + x1 = (stations[i-1]+beam.i.x)*scale + spacer + x2 = (stations[i]+beam.i.x)*scale + spacer + y1 = hg - (shears[i-1] * v_scale) + y2 = hg - (shears[i] * v_scale) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="red", width=2) + + if self.show_stations.get() == 1: + if i==1: + self.g_plan_canvas.create_line(x1, hg, x1, y1, fill="salmon", width=1) + self.g_plan_canvas.create_line(x2, hg, x2, y2, fill="salmon", width=1) + + string = 'Vi: {0:.3f} kN \nVj: {1:.3f} kN'.format(shears[0],shears[-1]) + x0 = (((beam.i.x+beam.j.x)/2)*scale) + spacer + + self.g_plan_canvas.create_text(x0, hg+12, anchor=tk.N, font=self.mono_f_chart, text=string, fill='red') + + if self.show_m.get()==1 and self.show_bm_charts.get()==1: + string_max = '' + string_min = '' + for i in range(1,len(stations)): + x1 = (stations[i-1]+beam.i.x)*scale + spacer + x2 = (stations[i]+beam.i.x)*scale + spacer + y1 = hg - (moments[i-1] * m_scale) + y2 = hg - (moments[i] * m_scale) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="green", width=2) + + if self.show_stations.get() == 1: + if i==1: + self.g_plan_canvas.create_line(x1, hg, x1, y1, fill="SeaGreen2", width=1) + self.g_plan_canvas.create_line(x2, hg, x2, y2, fill="SeaGreen2", width=1) + + if moments[i] == max(moments) and moments[i] != moments[-1]: + string_max = '\nM,max {0:.3f} kN*m @ {1:.3f} m'.format(moments[i],stations[i]) + + + if moments[i] == min(moments) and moments[i] != moments[-1]: + string_min = '\nM,min {0:.3f} kN*m @ {1:.3f} m'.format(moments[i],stations[i]) + + x0 = (((beam.i.x+beam.j.x)/2)*scale) + spacer + string = 'Mi {0:.3f} kN*m\nMj {1:.3f} kN*m'.format(moments[0],moments[-1]) + self.g_plan_canvas.create_text(x0, hg+12, anchor=tk.N, font=self.mono_f_chart, text=string+string_max+string_min, fill='green') + + if self.show_s.get()==1 and self.show_bm_charts.get()==1: + + for i in range(1,len(stations)): + x1 = (stations[i-1]+beam.i.x)*scale + spacer + x2 = (stations[i]+beam.i.x)*scale + spacer + y1 = hg - ((eislopes[i-1]/(beam.E*beam.I)) * s_scale) + y2 = hg - ((eislopes[i]/(beam.E*beam.I)) * s_scale) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="magenta", width=2) + + if self.show_stations.get() == 1: + if i==1: + self.g_plan_canvas.create_line(x1, hg, x1, y1, fill="orchid1", width=1) + self.g_plan_canvas.create_line(x2, hg, x2, y2, fill="orchid1", width=1) + + si = (eislopes[0]) /(beam.E*beam.I) + sj = (eislopes[-1]) /(beam.E*beam.I) + + string = 'Si: {0:.3E} rad\nSj: {1:.3E} rad'.format(si,sj) + x0 = (((beam.i.x+beam.j.x)/2)*scale) + spacer + + self.g_plan_canvas.create_text(x0, hg+12, anchor=tk.N, font=self.mono_f_chart, text=string, fill='magenta') + + if self.show_d.get()==1 and self.show_bm_charts.get()==1: + + string_max = '' + string_min = '' + for i in range(1,len(beam.chart_stations)): + if beam.type == 'cantilever' and beam.isleft == 1: + d0 = (self.beams_analysis[1].station_values()[0][4][0]/(self.beams_analysis[1].E*self.beams_analysis[1].I))*1000.0 + elif beam.type == 'cantilever' and beam.isleft == 0: + d0 = (self.beams_analysis[-2].station_values()[0][4][-1]/(self.beams_analysis[-2].E*self.beams_analysis[-2].I))*1000.0 + else: + d0 = 0 + x1 = (stations[i-1]+beam.i.x)*scale + spacer + x2 = (stations[i]+beam.i.x)*scale + spacer + y1 = hg - ((eideltas[i-1]/(beam.E*beam.I)) * d_scale * 1000.0) - (d0*d_scale) + y2 = hg - ((eideltas[i]/(beam.E*beam.I)) * d_scale * 1000.0) - (d0*d_scale) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="yellow", width=2) + + if self.show_stations.get() == 1: + if i==1: + self.g_plan_canvas.create_line(x1, hg, x1, y1, fill="khaki", width=1) + self.g_plan_canvas.create_line(x2, hg, x2, y2, fill="khaki", width=1) + + if eideltas[i] == max(eideltas) and eideltas[i] != eideltas[-1] and beam.type=='span': + string_max = '\nD,max {0:.3E} mm @ {1:.3E} m'.format(1000.0*eideltas[i]/(beam.E*beam.I),stations[i]) + + if eideltas[i] == min(eideltas) and eideltas[i] != eideltas[-1] and beam.type=='span': + string_min = '\nD,min {0:.3E} mm @ {1:.3E} m'.format(1000.0*eideltas[i]/(beam.E*beam.I),stations[i]) + + if beam.type == 'cantilever' and beam.isleft == 1: + string_max = '\nD {0:.3E} mm @ 0 m'.format(1000.0*eideltas[0]/(beam.E*beam.I)) + + if beam.type == 'cantilever' and beam.isleft == 0: + string_max = '\nD {0:.3E} mm @ {1:.3E} m'.format(1000.0*eideltas[-1]/(beam.E*beam.I), beam.Length) + + x0 = (((beam.i.x+beam.j.x)/2)*scale) + spacer + self.g_plan_canvas.create_text(x0, hg+12, anchor=tk.N, font=self.mono_f_chart, text=string_max+string_min, fill='yellow') + + count = 0 + non_sway_reaction = 0 + for col in self.columns_analysis: + + values = col.station_values() + stations = values[0] + shears = values[1] + moments = values[2] + eislopes = values[3] + eideltas = values[4] + + if col.type == 'UP': + x = (col.i.x * scale) + spacer + h1 = hg + h2 = h1 - (col.orig_Length*scale) + self.g_plan_canvas.create_line(x, h1, x, h2, fill="white", width=2) + else: + x = (col.j.x * scale) + spacer + h1 = hg + h2 = h1 + (col.orig_Length*scale) + self.g_plan_canvas.create_line(x, h1, x, h2, fill="white", width=2) + + if self.frame_solved == 0: + pass + else: + if self.show_r.get() == 1 and self.show_col_charts.get()==1: + if col.type == 'DOWN': + col.base_reaction() + string = 'Riy: {0:.3f} kN\n'.format(col.riy) + non_sway_reaction += col.rjx + else: + non_sway_reaction += col.rix + string = '' + + string += 'Rix: {0:.3f} kN\nRjx: {1:.3f} kN'.format(col.rix,col.rjx) + + + if col.type == 'UP': + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.S,font=self.mono_f_chart, text=string, fill='red') + else: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.N,font=self.mono_f_chart, text=string, fill='red') + + if col == self.columns_analysis[-1]: + non_sway_string = 'Non-Sway Reaction:\nRx: {0:.3f} kN'.format(non_sway_reaction) + + self.g_plan_canvas.create_text(max_x+5, hg, anchor=tk.SW,font=self.mono_f_chart, text=non_sway_string, fill='red') + + if self.show_dfs.get()==1 and self.show_col_charts.get()==1: + dfb = col.dfi + dft = col.dfj + string = 'DFj: {1:.3f}\nDFi: {0:.3f}'.format(dfb,dft) + + if col.type == 'UP': + if count == 0: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.SW,font=self.mono_f_chart, text=string, fill='cyan') + else: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.S,font=self.mono_f_chart, text=string, fill='cyan') + else: + if count == 0: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.NW,font=self.mono_f_chart, text=string, fill='cyan') + else: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.N,font=self.mono_f_chart, text=string, fill='cyan') + + if self.show_v.get()==1 and self.show_col_charts.get()==1: + for i in range(1,len(col.chart_stations)): + if col.type == 'UP': + y1 = h1 - (stations[i-1]*scale) + y2 = h1 - (stations[i]*scale) + else: + y1 = h2 - (stations[i-1]*scale) + y2 = h2 - (stations[i]*scale) + x1 = x + (shears[i-1] * v_scale) + x2 = x + (shears[i] * v_scale) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="red", width=1) + + if self.show_stations.get() == 1: + if i==1: + self.g_plan_canvas.create_line(x, y1, x1, y1, fill="salmon", width=1) + self.g_plan_canvas.create_line(x, y2, x2, y2, fill="salmon", width=1) + + vb = shears[0] + vt = shears[-1] + string = 'Vj: {1:.3f} kN\nVi: {0:.3f} kN'.format(vb,vt) + + if col.type == 'UP': + if count == 0: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.SW,font=self.mono_f_chart, text=string, fill='red') + else: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.S,font=self.mono_f_chart, text=string, fill='red') + else: + if count == 0: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.NW,font=self.mono_f_chart, text=string, fill='red') + else: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.N,font=self.mono_f_chart, text=string, fill='red') + + if self.show_m.get()==1 and self.show_col_charts.get()==1: + for i in range(1,len(col.chart_stations)): + if col.type == 'UP': + y1 = h1 - (stations[i-1]*scale) + y2 = h1 - (stations[i]*scale) + else: + y1 = h2 - (stations[i-1]*scale) + y2 = h2 - (stations[i]*scale) + x1 = x - (moments[i-1] * m_scale) + x2 = x - (moments[i] * m_scale) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="green", width=1) + + if self.show_stations.get() == 1: + if i==1: + self.g_plan_canvas.create_line(x, y1, x1, y1, fill="SeaGreen2", width=1) + self.g_plan_canvas.create_line(x, y2, x2, y2, fill="SeaGreen2", width=1) + + mb = moments[0] + mt = moments[-1] + string = 'Mj: {1:.3f} kN*m\nMi: {0:.3f} kN*m'.format(mb,mt) + + if col.type == 'UP': + if count == 0: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.SW,font=self.mono_f_chart, text=string, fill='green') + else: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.S,font=self.mono_f_chart, text=string, fill='green') + else: + if count == 0: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.NW,font=self.mono_f_chart, text=string, fill='green') + else: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.N,font=self.mono_f_chart, text=string, fill='green') + + if self.show_s.get()==1 and self.show_col_charts.get()==1: + for i in range(1,len(col.chart_stations)): + if col.type == 'UP': + y1 = h1 - (stations[i-1]*scale) + y2 = h1 - (stations[i]*scale) + else: + y1 = h2 - (stations[i-1]*scale) + y2 = h2 - (stations[i]*scale) + x1 = x - ((eislopes[i-1]/(col.E*col.I)) * s_scale) + x2 = x - ((eislopes[i]/(col.E*col.I)) * s_scale) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="magenta", width=1) + + if self.show_stations.get() == 1: + if i==1: + self.g_plan_canvas.create_line(x, y1, x1, y1, fill="orchid1", width=1) + self.g_plan_canvas.create_line(x, y2, x2, y2, fill="orchid1", width=1) + + sb = eislopes[0]/(col.E*col.I) + st = eislopes[-1]/(col.E*col.I) + string = 'Sj: {1:.3E} rad\nSi: {0:.3E} rad'.format(sb,st) + + if col.type == 'UP': + if count == 0: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.SW,font=self.mono_f_chart, text=string, fill='magenta') + else: + self.g_plan_canvas.create_text(x, h1 - (col.Length*scale), anchor=tk.S,font=self.mono_f_chart, text=string, fill='magenta') + else: + if count == 0: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.NW,font=self.mono_f_chart, text=string, fill='magenta') + else: + self.g_plan_canvas.create_text(x, h1 + (col.Length*scale), anchor=tk.N,font=self.mono_f_chart, text=string, fill='magenta') + + if self.show_d.get()==1 and self.show_col_charts.get()==1: + for i in range(1,len(col.chart_stations)): + if col.type == 'UP': + y1 = h1 - (stations[i-1]*scale) + y2 = h1 - (stations[i]*scale) + else: + y1 = h2 - (stations[i-1]*scale) + y2 = h2 - (stations[i]*scale) + x1 = x - ((eideltas[i-1]/(col.E*col.I)) * d_scale * 1000.0) + x2 = x - ((eideltas[i]/(col.E*col.I)) * d_scale * 1000.0) + + self.g_plan_canvas.create_line(x1, y1, x2, y2, fill="yellow", width=1) + + if self.show_stations.get() == 1: + if i==1: + self.g_plan_canvas.create_line(x, y1, x1, y1, fill="khaki", width=1) + self.g_plan_canvas.create_line(x, y2, x2, y2, fill="khaki", width=1) + count +=1 + + def frame_analysis_gui(self, *event): + sorted_load_list = [] + + #sort the load list by beam + for beam in self.beams_analysis: + beam.reset_fem() + sorted_load_list.append([load for load in self.gui_load_list if load[0]==beam.label]) + + for column in self.columns_analysis: + column.reset_fem() + # Determine number of Spans and load patterns + # load patterns will be returned as a list of + # off, on per span + + num_spans = len(self.beams_analysis) + + # Solve for each load case + + for i,beam in enumerate(self.beams_analysis): + beam.new_load_list(sorted_load_list[i]) + + Consider_shortening = self.cols_compress.get() + + precision = float(self.precision.get()) + + frame2d.moment_distribution(self.nodes_analysis,self.beams_analysis,self.columns_analysis,Consider_shortening,precision) + + for beam in self.beams_analysis: + if beam.type == 'span': + beam.build_load_function() + + max_m = 0 + min_m = 0 + for beam in self.beams_analysis: + + if beam.type=='cantilever' and beam.isleft == 1: + start_slope = self.beams_analysis[1].station_values()[0][3][0]/(self.beams_analysis[1].E*self.beams_analysis[1].I) + + beam.add_starting_slope(start_slope) + beam.build_load_function() + + elif beam.type=='cantilever' and beam.isleft == 0: + start_slope = self.beams_analysis[-2].station_values()[0][3][-1]/(self.beams_analysis[-2].E*self.beams_analysis[-2].I) + beam.add_starting_slope(start_slope) + beam.build_load_function() + + + max_m = max(max_m,max(beam.station_values()[0][2])) + min_m = min(min_m,min(beam.station_values()[0][2])) + + self.max_m = max_m + self.min_m = min_m + + for column in self.columns_analysis: + column.build_load_function() + + self.frame_solved = 1 + + self.build_frame_graph() + + + +def main(): + root = tk.Tk() + root.title("2D Frame Analysis by Moment Distribution - METRIC - Alpha") + main_window(root) + root.minsize(800,600) + root.mainloop() + +if __name__ == '__main__': + main() diff --git a/Analysis/Frame_Moment_Distribution_2D.py b/Analysis/Frame_Moment_Distribution_2D.py new file mode 100644 index 0000000..e76fbb6 --- /dev/null +++ b/Analysis/Frame_Moment_Distribution_2D.py @@ -0,0 +1,1272 @@ +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' + +from __future__ import division +import pin_pin_beam_equations_classes as ppbeam +#import matplotlib.pyplot as plt +import time + + +class node: + def __init__(self, x): + + self.x = x + self.K = 0 + self.ry = 0 + + def sum_node_k(self, beams, columns): + self.K = 0 + + for beam in beams: + if beam.i == self or beam.j == self: + self.K += beam.K + + for column in columns: + if column.i == self or column.j == self: + self.K += column.K + + def sum_node_moments(self, beams, columns): + self.m_unbalance = 0 + self.m_balance = 0 + + for beam in beams: + if beam.i == self: + self.m_unbalance += sum(beam.mi) + + elif beam.j == self: + self.m_unbalance += sum(beam.mj) + else: + pass + + for column in columns: + if column.i == self: + self.m_unbalance += sum(column.mi) + elif column.j == self: + self.m_unbalance += sum(column.mj) + else: + pass + + self.m_balance = -1.0*(self.m_unbalance) + + def sum_node_reactions(self, beams): + node_reaction = 0 + + for beam in beams: + r = beam.reactions() + + if self == beam.i: + node_reaction += r[0] + + elif self == beam.j: + node_reaction += r[1] + + else: + pass + + self.ry = node_reaction + + return node_reaction + +class CantBeam: + def __init__(self, ij, E=1, I=1, Length=1, Loads_list=1, left=1, label=''): + ''' + beam element + Loads = lists of loads in text form + E, I, and Loads should have consistent units + ''' + self.isleft = left + self.type = 'cantilever' + self.label = label + self.Length = Length + + + if self.isleft==1: + self.i = node(0) + self.j = ij + else: + self.i = ij + self.j = node(self.i.x + self.Length) + + self.E = E + self.I = I + self.Load_list = [load for load in Loads_list] + + + self.mi = [0] + self.mj = [0] + self.dfi = 0 + self.dfj = 0 + + self.K = 0 + + step = self.Length/20.0 + + self.chart_stations = [0] + + for i in range(1,20): + self.chart_stations.append(self.chart_stations[i-1]+step) + + self.chart_stations.append(self.Length) + + self.loads_built = 0 + + def new_load_list(self, load_list): + del self.Load_list[:] + self.Load_List = [load for load in load_list] + + def applied_loads(self): + + if self.isleft == 1: + self.applied_loads_left() + else: + self.applied_loads_right() + + def applied_loads_left(self): + self.Loads = [] + self.extra_station = [] + + for load in self.Load_List: + w1 = float(load[1]) + w2 = float(load[2]) + a = float(load[3]) + b = float(load[4]) + load_type = load[-2] + lc = self.Length + + #['Point','Moment','UDL','TRAP','SLOPE'] + if load_type == 'Point': + self.Loads.append(ppbeam.cant_left_point(w1,a,lc,0)) + b = min(lc,a + 0.01) + c = max(0,a - 0.01) + self.extra_station.extend([c,a,b]) + + elif load_type == 'Moment': + self.Loads.append(ppbeam.cant_left_point_moment(w1,a,lc,0)) + b = min(lc,a + 0.01) + c = max(0,a - 0.01) + self.extra_station.extend([c,a,b]) + + elif load_type == 'UDL': + self.Loads.append(ppbeam.cant_left_udl(w1,a,b,lc,0)) + self.extra_station.extend([a,b]) + + elif load_type == 'TRAP': + self.Loads.append(ppbeam.cant_left_trap(w1,w2,a,b,lc,0)) + self.extra_station.extend([a,b]) + + elif load_type == 'SLOPE': + self.Loads.append(ppbeam.cant_left_nl(w1,lc)) + + else: + pass + + self.chart_stations.extend(self.extra_station) + + self.chart_stations = list(set(self.chart_stations)) + + self.chart_stations.sort() + + def applied_loads_right(self): + + self.Loads = [] + self.extra_station = [] + + for load in self.Load_List: + w1 = float(load[1]) + w2 = float(load[2]) + a = float(load[3]) + b = float(load[4]) + load_type = load[-2] + lc = self.Length + + #['Point','Moment','UDL','TRAP','SLOPE'] + if load_type == 'Point': + self.Loads.append(ppbeam.cant_right_point(w1,a,lc,0)) + b = min(lc,a + 0.01) + c = max(0,a - 0.01) + self.extra_station.extend([c,a,b]) + + elif load_type == 'Moment': + self.Loads.append(ppbeam.cant_right_point_moment(w1,a,lc,0)) + b = min(lc,a + 0.01) + c = max(0,a - 0.01) + self.extra_station.extend([c,a,b]) + + elif load_type == 'UDL': + self.Loads.append(ppbeam.cant_right_udl(w1,a,b,lc,0)) + self.extra_station.extend([a,b]) + + elif load_type == 'TRAP': + self.Loads.append(ppbeam.cant_right_trap(w1,w2,a,b,lc,0)) + self.extra_station.extend([a,b]) + + elif load_type == 'SLOPE': + self.Loads.append(ppbeam.cant_right_nl(w1,lc)) + + else: + pass + + self.chart_stations.extend(self.extra_station) + + self.chart_stations = list(set(self.chart_stations)) + + self.chart_stations.sort() + + def fef(self): + + for load in self.Loads: + + if load.kind == "SLOPE": + pass + else: + if self.isleft == 1: + self.mi[0] += -1*load.fef()[1] + self.mj[0] += -1*load.fef()[3] + else: + self.mi[0] += load.fef()[1] + self.mj[0] += load.fef()[3] + + def reactions(self): + + rl = 0 + rr = 0 + + for load in self.Loads: + rl += load.rl + rr += load.rr + + return [rl,rr] + + def add_starting_slope(self, slope): + ''' + given the actual required starting slope + convert it to an EIS and add it to the cantilever + loads. + + cnoverting the slope will allow the cantilever + and adjacent beam span to have different E and I + but insure that the rotation is consistent between + the two + ''' + + slope_load = slope*self.E*self.I + + if self.isleft == 1: + self.Loads.append(ppbeam.cant_left_nl(slope_load,self.Length)) + else: + self.Loads.append(ppbeam.cant_right_nl(slope_load,self.Length)) + + def build_load_function(self): + + self.equations, self.equation_strings = ppbeam.center_span_piecewise_function(self.Loads) + + self.loads_built = 1 + + def station_values(self): + v = [] + m = [] + eis = [] + eid = [] + end_delta_d = [0]*len(self.chart_stations) + if self.loads_built == 1: + + for x in self.chart_stations: + res = ppbeam.eval_beam_piece_function(self.equations,x) + + v.append(res[0]) + m.append(res[1]) + eis.append(res[2]) + eid.append(res[3]) + + return [self.chart_stations, v, m, eis, eid],end_delta_d + + else: + zero_out = [0]*len(self.chart_stations) + + return [self.chart_stations, zero_out, zero_out, zero_out, zero_out],end_delta_d + +class Beam: + def __init__(self, i_node, j_node, E, I, Loads_List=[], label=''): + + ''' + beam element + Loads = lists of loads in text form + E, I, and Loads should have consistent units + ''' + + self.i = i_node + self.j = j_node + self.E = E + self.I = I + self.Load_List = [load for load in Loads_List] + self.Length = j_node.x - i_node.x + self.type = 'span' + self.label = label + + self.mi = [0] + self.mj = [0] + self.dfi = 0 + self.dfj = 0 + + self.K = self.E*self.I / self.Length + + step = self.Length/20.0 + + self.chart_stations = [0] + + for i in range(1,20): + self.chart_stations.append(self.chart_stations[i-1]+step) + + self.chart_stations.append(self.Length) + + self.loads_built = 0 + + def new_load_list(self, load_list): + del self.Load_List[:] + self.Load_List = [load for load in load_list] + + def applied_loads(self): + self.Loads = [] + self.extra_station = [] + + for load in self.Load_List: + w1 = float(load[1]) + w2 = float(load[2]) + a = float(load[3]) + b = float(load[4]) + load_type = load[-2] + lc = self.Length + + #['Point','Moment','UDL','TRAP','END_DELTA'] + if load_type == 'Point': + self.Loads.append(ppbeam.pl(w1,a,lc)) + b = min(lc,a + 0.01) + c = max(0,a - 0.01) + self.extra_station.extend([c,a,b]) + + elif load_type == 'Moment': + self.Loads.append(ppbeam.point_moment(w1,a,lc)) + b = min(lc,a + 0.01) + c = max(0,a - 0.01) + self.extra_station.extend([c,a,b]) + + elif load_type == 'UDL': + self.Loads.append(ppbeam.udl(w1,a,b,lc)) + self.extra_station.extend([a,b]) + + elif load_type == 'TRAP': + self.Loads.append(ppbeam.trap(w1,w2,a,b,lc)) + self.extra_station.extend([a,b]) + + elif load_type == 'END_DELTA': + self.Loads.append(ppbeam.end_delta(w1,w2,lc)) + + else: + pass + + self.chart_stations.extend(self.extra_station) + + self.chart_stations = list(set(self.chart_stations)) + + self.chart_stations.sort() + + def fef(self): + + for load in self.Loads: + + if load.kind == "END_DELTA": + self.mi[0] += load.fef()[1]*self.E*self.I + self.mj[0] += load.fef()[3]*self.E*self.I + else: + self.mi[0] += load.fef()[1] + self.mj[0] += load.fef()[3] + + def add_end_moments(self): + self.Loads.append(ppbeam.point_moment(sum(self.mi),0,self.Length)) + self.Loads.append(ppbeam.point_moment(sum(self.mj),self.Length,self.Length)) + + def reactions(self): + + rl = 0 + rr = 0 + + for load in self.Loads: + rl += load.rl + rr += load.rr + + return [rl,rr] + + def end_delta_fem(self): + ''' + update the beam end moments + for the support deflection + ''' + for load in self.Loads: + + if load.kind == "END_DELTA": + + self.mi.append(load.fef()[1]) + self.mj.append(load.fef()[3]) + + else: + pass + + def reset_fem(self): + self.mi = [0] + self.mj = [0] + + def build_load_function(self): + + self.loads_nodelta = [load for load in self.Loads if load.kind != "END_DELTA"] + self.loads_delta = [load for load in self.Loads if load.kind == "END_DELTA"] + + self.equations, self.equation_strings = ppbeam.center_span_piecewise_function(self.loads_nodelta) + + if len(self.loads_delta) == 0: + pass + else: + self.equations_delta, self.equations_strings_delta = ppbeam.center_span_piecewise_function(self.loads_delta) + + # points of inflection + self.zero_shear_loc = ppbeam.points_of_zero_shear(self.equations[0]) + + self.zero_moment_loc = ppbeam.points_of_zero_shear(self.equations[1]) + + self.zero_slope_loc = ppbeam.points_of_zero_shear(self.equations[2]) + + # add points of inflection to the charting stations + self.chart_stations.extend(self.zero_shear_loc) + self.chart_stations.extend(self.zero_moment_loc) + self.chart_stations.extend(self.zero_slope_loc) + self.chart_stations = list(set(self.chart_stations)) + self.chart_stations.sort() + + self.loads_built = 1 + + def max_min_moment(self): + + if self.loads_built == 1: + m_out = [] + for x in self.zero_shear_loc: + m_res = ppbeam.eval_beam_piece_function(self.equations,x) + + m_out.append([x,m_res[1]]) + + return m_out + else: + return [[0,0]] + + def max_min_eidelta(self): + if self.loads_built == 1: + eid_out = [] + for x in self.zero_slope_loc: + eid_res = ppbeam.eval_beam_piece_function(self.equations,x) + + eid_out.append([x,eid_res[3]]) + + return eid_out + else: + return [[0,0]] + + def station_values(self): + v = [] + m = [] + eis = [] + eid = [] + end_delta_d = [] + if self.loads_built == 1: + + for x in self.chart_stations: + res = ppbeam.eval_beam_piece_function(self.equations,x) + + if len(self.loads_delta) == 0: + v.append(res[0]) + m.append(res[1]) + eis.append(res[2]) + eid.append(res[3]) + else: + res_d = ppbeam.eval_beam_piece_function(self.equations_delta,x) + end_delta_d.append(res_d[3]) + + v.append(res[0]) + m.append(res[1]) + eis.append(res[2]+res_d[2]) + eid.append(res[3]+res_d[3]) + + return [self.chart_stations, v, m, eis, eid],end_delta_d + + +class Column_Up: + def __init__(self, i_node, height=1, E=1, I=1,A=1,support=1, hinge_near=0): + ''' + upper column element + I is about axis aligned with beams + E, I, and Height should have consistent units + ''' + + self.i = i_node + self.j = 0 + self.E = E + self.I = I + self.A = A + self.Length = height # Use Length to make loop plotting easier + self.orig_Length = height + self.type = 'UP' + self.rix = 0 + self.rjx = 0 + self.loads_built = 0 + + if support == 1: + self.fix = 1 + else: + self.fix = 0 + + self.hinge = hinge_near + + self.mi = [0] + self.mj = [0] + self.dfi = 0 + + step = self.Length/20.0 + + self.chart_stations = [0] + + for i in range(1,20): + self.chart_stations.append(self.chart_stations[i-1]+step) + + self.chart_stations.append(self.Length) + + if self.hinge == 1: + self.K = 0 + self.dfj = 0 + self.dfi = 0 + self.coi = 0 + else: + if self.fix == 1: + self.K = self.E*self.I / self.Length + self.dfj = 0 + self.coi = 0 + else: + self.K = (0.75)*(self.E*self.I / self.Length) + self.dfj = 1 + self.coi = 0.5 + + def reset_fem(self): + self.mi = [0] + self.mj = [0] + + def new_height(self, height): + + self.Length = height + + step = self.Length/20.0 + + self.chart_stations = [0] + + for i in range(1,20): + self.chart_stations.append(self.chart_stations[i-1]+step) + + self.chart_stations.append(self.Length) + + if self.fix == 1: + self.K = self.E*self.I / self.Length + self.dfj = 0 + self.coi = 0 + else: + self.K = (0.75)*(self.E*self.I / self.Length) + self.dfj = 1 + self.coi = 0.5 + + def build_load_function(self): + Mi = sum(self.mi) + Mj = sum(self.mj) + + L1 = ppbeam.point_moment(Mi,0,self.Length) + L2 = ppbeam.point_moment(Mj,self.Length,self.Length) + + self.equations, self.equation_strings = ppbeam.center_span_piecewise_function([L1,L2]) + + # points of inflection + self.zero_shear_loc = ppbeam.points_of_zero_shear(self.equations[0]) + + self.zero_moment_loc = ppbeam.points_of_zero_shear(self.equations[1]) + + self.zero_slope_loc = ppbeam.points_of_zero_shear(self.equations[2]) + + # add points of inflection to the charting stations + self.chart_stations.extend(self.zero_shear_loc) + self.chart_stations.extend(self.zero_moment_loc) + self.chart_stations.extend(self.zero_slope_loc) + self.chart_stations = list(set(self.chart_stations)) + self.chart_stations.sort() + + self.loads_built = 1 + + def station_values(self): + v = [] + m = [] + eis = [] + eid = [] + + if self.loads_built == 1: + + for x in self.chart_stations: + res = ppbeam.eval_beam_piece_function(self.equations,x) + + v.append(-1*res[0]) + m.append(res[1]) + eis.append(res[2]) + eid.append(res[3]) + + self.rix = v[0] + self.rjx = -1*v[-1] + + return [self.chart_stations, v, m, eis, eid] + + else: + zero_out = [0]*len(self.chart_stations) + return [self.chart_stations, zero_out, zero_out, zero_out, zero_out] + + +class Column_Down: + def __init__(self, j_node, height=1, E=1, I=1, A=1, support=1, hinge_near=0): + ''' + lower column element + I is about axis aligned with beams + E, I, and Height should have consistent units + ''' + + self.i = 0 + self.j = j_node + self.E = E + self.I = I + self.A = A + self.Length = height # Use Length to make loop plotting easier + self.orig_Length = height + self.type = 'DOWN' + self.rix = 0 + self.rjx = 0 + self.riy = 0 + self.loads_built = 0 + + if support == 1: + self.fix = 1 + else: + self.fix = 0 + + self.hinge = hinge_near + + self.mi = [0] + self.mj = [0] + self.dfj = 0 + + step = self.Length/20.0 + + self.chart_stations = [0] + + for i in range(1,20): + self.chart_stations.append(self.chart_stations[i-1]+step) + + self.chart_stations.append(self.Length) + + if self.hinge == 1: + self.K = 0 + self.dfj = 0 + self.dfi = 0 + self.coi = 0 + else: + if self.fix == 1: + self.K = self.E*self.I / self.Length + self.dfi = 0 + self.coj = 0 + else: + self.K = (0.75)*(self.E*self.I / self.Length) + self.dfi = 1 + self.coj = 0.5 + + def reset_fem(self): + self.mi = [0] + self.mj = [0] + + def new_height(self, height): + + self.Length = height + step = self.Length/20.0 + + self.chart_stations = [0] + + for i in range(1,20): + self.chart_stations.append(self.chart_stations[i-1]+step) + + self.chart_stations.append(self.Length) + + if self.fix == 1: + self.K = self.E*self.I / self.Length + self.dfj = 0 + self.coi = 0 + else: + self.K = (0.75)*(self.E*self.I / self.Length) + self.dfj = 1 + self.coi = 0.5 + + def build_load_function(self): + Mi = sum(self.mi) + Mj = sum(self.mj) + + L1 = ppbeam.point_moment(Mi,0,self.Length) + L2 = ppbeam.point_moment(Mj,self.Length,self.Length) + + self.equations, self.equation_strings = ppbeam.center_span_piecewise_function([L1,L2]) + + # points of inflection + self.zero_shear_loc = ppbeam.points_of_zero_shear(self.equations[0]) + + self.zero_moment_loc = ppbeam.points_of_zero_shear(self.equations[1]) + + self.zero_slope_loc = ppbeam.points_of_zero_shear(self.equations[2]) + + # add points of inflection to the charting stations + self.chart_stations.extend(self.zero_shear_loc) + self.chart_stations.extend(self.zero_moment_loc) + self.chart_stations.extend(self.zero_slope_loc) + self.chart_stations = list(set(self.chart_stations)) + self.chart_stations.sort() + + self.loads_built = 1 + + def station_values(self): + v = [] + m = [] + eis = [] + eid = [] + + if self.loads_built == 1: + + for x in self.chart_stations: + res = ppbeam.eval_beam_piece_function(self.equations,x) + + v.append(-1*res[0]) + m.append(res[1]) + eis.append(res[2]) + eid.append(res[3]) + + self.rix = v[0] + self.rjx = -1*v[-1] + + return [self.chart_stations, v, m, eis, eid] + else: + zero_out = [0]*len(self.chart_stations) + return [self.chart_stations, zero_out, zero_out, zero_out, zero_out] + + def base_reaction(self): + self.riy = self.j.ry + + +def beams_all_same(nodes, E, I, load): + beams = [] + spans = len(nodes)-1 + + loads = [] + loads.extend(load) + + for i in range(spans): + beams.append(Beam(nodes[i],nodes[i+1],E,I,loads)) + + return beams + +def col_up_same(nodes, E, I, A, height,support, hinge_near): + columns = [] + + for node in nodes: + columns.append(Column_Up(node,height,E,I,A,support,hinge_near)) + + return columns + +def col_dwn_same(nodes, E, I, A, height, support, hinge_near): + columns = [] + + for node in nodes: + columns.append(Column_Down(node,height,E,I,A,support,hinge_near)) + + return columns + +def moment_distribution_cycle(nodes, beams, columns, tolerance=1e-11): + # Moment Distribution Cycle - left to right + for node in nodes: + + node.sum_node_moments(beams, columns) + + for beam in beams: + if beam.type == 'span': + if beam.i == node: + beam.mi.append(node.m_balance*beam.dfi) + beam.mj.append(beam.mi[-1]*0.5) + + elif beam.j == node: + beam.mj.append(node.m_balance*beam.dfj) + beam.mi.append(beam.mj[-1]*0.5) + else: + pass + + for column in columns: + if column.i == node: + column.mi.append(node.m_balance*column.dfi) + if column.fix == 1: + column.mj.append(column.mi[-1]*0.5) + else: + pass + + elif column.j == node: + column.mj.append(node.m_balance*column.dfj) + if column.fix == 1: + column.mi.append(column.mj[-1]*0.5) + else: + pass + else: + pass + + # Moment Distribution Cycle - right to left + nodes_rev = nodes[::-1] + for node in nodes_rev: + node.sum_node_moments(beams, columns) + + m_bal = node.m_balance + + for beam in beams: + if beam.type == 'span': + if beam.i == node: + beam.mi.append(m_bal*beam.dfi) + beam.mj.append(beam.mi[-1]*0.5) + + elif beam.j == node: + beam.mj.append(m_bal*beam.dfj) + beam.mi.append(beam.mj[-1]*0.5) + + else: + pass + + for column in columns: + if column.i == node: + column.mi.append(m_bal*column.dfi) + if column.fix == 1: + column.mj.append(column.mi[-1]*0.5) + else: + pass + + elif column.j == node: + column.mj.append(m_bal*column.dfj) + if column.fix == 1: + column.mi.append(column.mj[-1]*0.5) + else: + pass + else: + pass + + check = all(abs(node.m_balance) < tolerance for node in nodes) + + return check + +def member_distribution_factors(nodes, beams, columns): + # Sum of EI/L for members at each Node + for node in nodes: + node.sum_node_k(beams,columns) + + # Beam Distribution Factors at each Node + bmdfs = [] + for beam in beams: + for node in nodes: + if node == beam.i: + beam.dfi = beam.K / node.K + + bmdfs.append(beam.dfi) + + elif node == beam.j: + beam.dfj = beam.K / node.K + bmdfs.append(beam.dfj) + else: + pass + + # Column Distribution Factors at each Node + coldfs = [] + for column in columns: + for node in nodes: + if node == column.i: + column.dfi = column.K / node.K + coldfs.append(column.dfi) + coldfs.append(column.dfj) + + elif node == column.j: + column.dfj = column.K / node.K + coldfs.append(column.dfi) + coldfs.append(column.dfj) + + else: + pass + +def beam_fef(beams): + # Beam Fixed End Forces + bmfef = [] + for beam in beams: + beam.applied_loads() + beam.fef() + bmfef.extend([beam.mi[0],beam.mj[0]]) + + +def moment_distribution(nodes, beams, columns, shortening=0, tolerance=1e-11): + member_distribution_factors(nodes, beams, columns) + + beam_fef(beams) + # Moment Distribution Pass 1 - left to right + moment_distribution_cycle(nodes, beams, columns, tolerance) + + # Moment Distrubution multiple passes + count = 0 + count_max = 100 + n_previous = [] + kick = 0 + test = False + while test == False and count < count_max and kick<1: + test = moment_distribution_cycle(nodes, beams, columns, tolerance) + + if count <=1: + n_m_unbalance = [node.m_unbalance for node in nodes] + n_previous.append(n_m_unbalance) + else: + n_m_unbalance = [node.m_unbalance for node in nodes] + + if n_m_unbalance == n_previous[-1]: + kick = 1 + else: + n_previous.append(n_m_unbalance) + + count +=1 + + print count + + # Add final Moments to Beams and Get individual Beam End Reactions + node_r = [] + for beam in beams: + if beam.type=='span': + beam.add_end_moments() + + for node in nodes: + node_r.append(node.sum_node_reactions(beams)) + + node_delta = [] + + if shortening == 1: + # Determine column shortening for reactions - PL/AE + i = 0 + for column in columns: + if column.type == 'DOWN': + p = node_r[i] + + node_delta.append((-1.0*p*column.Length) / (column.A * column.E)) + + i+=1 + + # Create New Beam Set with the column shortening as loads + delta_load = [] + i=0 + for beam in beams: + if beam.type == 'span': + load = ['a',(node_delta[i]*beam.I*beam.E),(node_delta[i+1]*beam.I*beam.E),0,10,'END_DELTA','a'] + delta_load.append(load) + beam.Load_List.append(load) + i+=1 + else: + delta_load.append([]) + + + + ''' + #going to try not reseting the FEF to see if it speeds + #up the second pass + # reset beam end moments + for beam in beams: + beam.reset_fem() + + # reset column end moments + for column in columns: + column.reset_fem() + ''' + + # Beam Fixed End Forces + delta_bmfef = [] + for beam in beams: + beam.applied_loads() + #beam.fef() + #delta_bmfef.extend([beam.mi[0],beam.mj[0]]) + if beam.type == 'span': + beam.end_delta_fem() + delta_bmfef.append([beam.mi,beam.mj]) + else: + pass + + # Moment Distribution Pass 1 + moment_distribution_cycle(nodes, beams, columns, tolerance) + + # Moment Distrubution multiple passes + + count_delta = 0 + test_delta = False + n_delta_previous = [] + delta_kick = 0 + + while test_delta == False and count_delta < count_max and delta_kick<1: + test_delta = moment_distribution_cycle(nodes, beams, columns, tolerance) + + + if count_delta <=1: + n_m_unbalance_delta = [node.m_unbalance for node in nodes] + n_delta_previous.append(n_m_unbalance_delta) + else: + n_m_unbalance_delta = [node.m_unbalance for node in nodes] + + if n_m_unbalance_delta == n_delta_previous[-1]: + delta_kick = 1 + else: + n_delta_previous.append(n_m_unbalance_delta) + + + count_delta +=1 + + print count_delta + + # Add final Moments to Beams and Get individual Beam End Reactions + delta_node_r = [] + for beam in beams: + if beam.type=='span': + beam.add_end_moments() + for node in nodes: + delta_node_r.append(node.sum_node_reactions(beams)) + + else: + delta_node_r = [0 for node in nodes] + + return [node_r, delta_node_r] + + +# tolerance = 1e-6 + +# n1 = node(0) +# n2 = node(10) +# n3 = node(20) +# n4 = node(30) +# n5 = node(40) +# n6 = node(50) +# n7 = node(60) +# n8 = node(70) +# n9 = node(80) +# n10 = node(90) +# n11 = node(100) + + +# nodes = [n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11] + +# start = time.time() + +# time_count = 0 + +# A_in2 = 2.96 +# A_ft2 = A_in2/144.0 + +# E_ksi = 29000.0 +# I_in4 = 30.8 + +# E_ksf = E_ksi*144.0 # k/in^2 * 144 in^2 / 1 ft^2 = 144 k/ft^2 +# I_ft4 = I_in4 * (1 / 20736.0) # in^4 * 1 ft^4 / 12^4 in^4 = ft^4 + + +# bm_load = ([[1,0,1,0,10,'Point'],[1,0,2,0,10,'Point'],[1,0,3,0,10,'Point'], + # [1,0,4,0,10,'Point'],[1,0,5,0,10,'Point'],[1,0,6,0,10,'Point'], + # [1,0,7,0,10,'Point'],[1,0,8,0,10,'Point'],[1,0,9,0,10,'Point'], + # [1,0,1,9,10,'UDL'],[1,0,2,8,'UDL'], + # [1,0.5,3,7,'TRAP'],[0.5,1,3,7,'TRAP']]) + + +# #bm_load = [] + +# cant_left = CantBeam(nodes[0],E_ksf,I_ft4,5,[[3,0,0,5,0,'UDL']],1) +# cant_right = CantBeam(nodes[-1],E_ksf,I_ft4,5,[[3,0,0,5,0,'UDL']],0) + +# beams = beams_all_same(nodes, E_ksf, I_ft4, bm_load) + +# beams.append(cant_left) +# beams.append(cant_right) + +# cantilevers = [bm for bm in beams if bm.type=='cantilever'] + +# Consider_shortening = 1 +# support = 1 +# support_dwn = 1 +# up_hinge = 0 +# down_hinge = 0 +# col_height = 10 + +# columns_down = col_dwn_same(nodes, E_ksf, I_ft4, A_ft2, col_height, support_dwn, down_hinge) + +# columns_up = col_up_same(nodes, E_ksf, I_ft4, A_ft2, col_height, support, up_hinge) + +# columns=[] +# columns.extend(columns_down) +# columns.extend(columns_up) + +# member_distribution_factors(nodes,beams,columns) + +# beam_fef(beams) + +# node_delta = moment_distribution(nodes,beams,columns,Consider_shortening,tolerance) + +# Build Beam Load Functions +# funcs = [] +# delta_func = [] +# for beam in beams: + # beam.build_load_function() + # funcs.append(beam.equation_strings) + + # if Consider_shortening == 1 and beam.type=='span': + # delta_func.append(beam.equations_delta) + # else: + # pass + +# Beam Max/Min Moments and EIDeltas +# and Beam charting values +# final_end_moments_bms = [] +# moments = [] +# EIdeltas = [] +# beam_charts = [] +# for beam in beams: + # final_end_moments_bms.extend([sum(beam.mi),sum(beam.mj)]) + # if beam.type == 'span': + # moments.append(beam.max_min_moment()) + # EIdeltas.append(beam.max_min_eidelta()) + + # if beam.type=='cantilever' and beam.isleft == 1: + # start_slope = beam_charts[0][0][3][0]/(beams[0].E*beams[0].I) + + # beam.add_starting_slope(start_slope) + # beam.build_load_function() + + # elif beam.type=='cantilever' and beam.isleft == 0: + # start_slope = beams[-3].station_values()[0][3][-1]/(beams[-1].E*beams[-1].I) + # beam.add_starting_slope(start_slope) + # beam.build_load_function() + + # beam_charts.append(beam.station_values()) + +# Column Load Function - only loads on columns = end moments +# if Consider_shortening == 1: + # i=0 + # for column in columns_down: + # h = column.Length+node_delta[i] + # column.new_height(h) + # i+=1 + +# final_end_moments_cols = [] +# col_funcs = [] +# for column in columns: + # final_end_moments_cols.extend([sum(column.mi),sum(column.mj)]) + # column.build_load_function() + # col_funcs.append(column.equation_strings) + +# Column - Charts +# column_charts = [] +# for column in columns: + # column_charts.append(column.station_values()) + + +# end = time.time() +# t = end-start +# print t + +#Beam plots - will show one at a time +#i = 1 +#for chart in beam_charts: +# plt.close('all') +# +# if Consider_shortening == 1: +# delta = [((delt*12.0)/(E_ksf*I_ft4))+supdelt for delt,supdelt in zip(chart[0][4],chart[1])] +# s = [sl/(E_ksf*I_ft4) for sl in chart[0][3]] +# else: +# delta = [((delt*12.0)/(E_ksf*I_ft4)) for delt in chart[0][4]] +# s = [sl/(E_ksf*I_ft4) for sl in chart[0][3]] +# +# f, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2) +# ax1.plot(chart[0][0], chart[0][1], 'r-') +# ax1.plot(chart[0][0], [0]*len(chart[0][0]), 'k-') +# ax1.set_title('Shear - kips') +# ax2.plot(chart[0][0], chart[0][2], 'b-') +# ax2.plot(chart[0][0], [0]*len(chart[0][0]), 'k-') +# ax2.set_title('Moment - ft-kips') +# ax3.plot(chart[0][0], s, 'g-') +# ax3.plot(chart[0][0], [0]*len(chart[0][0]), 'k-') +# ax3.set_title('Slope - Rad') +# ax3.ticklabel_format(axis='y',style='sci',scilimits=(1,3)) +# ax4.plot(chart[0][0], delta, 'c-') +# ax4.plot(chart[0][0], [0]*len(chart[0][0]), 'k-') +# ax4.set_title('Deflection - in') +# ax4.ticklabel_format(axis='y',style='sci',scilimits=(1,3)) +# +# f.suptitle('Beam {0}'.format(i)) +# +# plt.tight_layout() +# +# plt.show() +# +# i+=1 + +#Column plots - will show one at a time +#i = 1 +#for chart in column_charts: +# plt.close('all') +# +# delta = [((delt*12.0)/(E_ksf*I_ft4)) for delt in chart[4]] +# s = [sl/(E_ksf*I_ft4) for sl in chart[3]] +# +# f, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2) +# ax1.plot(chart[1], chart[0], 'r-') +# ax1.plot([0]*len(chart[0]), chart[0],'k-') +# ax1.set_title('Shear - kips') +# ax2.plot(chart[2], chart[0], 'b-') +# ax2.plot([0]*len(chart[0]), chart[0],'k-') +# ax2.set_title('Moment - ft-kips') +# ax3.plot(s, chart[0], 'g-') +# ax3.plot([0]*len(chart[0]),chart[0], 'k-') +# ax3.set_title('Slope - Rad') +# ax3.ticklabel_format(axis='x',style='sci',scilimits=(1,3)) +# ax4.plot(delta, chart[0], 'c-') +# ax4.plot([0]*len(chart[0]), chart[0], 'k-') +# ax4.set_title('Deflection - in') +# ax4.ticklabel_format(axis='x',style='sci',scilimits=(1,3)) +# +# f.suptitle('Column {0}'.format(i)) +# +# plt.tight_layout() +# +# plt.show() +# +# i+=1 diff --git a/Analysis/HardyColumn.py b/Analysis/HardyColumn.py new file mode 100644 index 0000000..d9c3e66 --- /dev/null +++ b/Analysis/HardyColumn.py @@ -0,0 +1,96 @@ +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' + +from __future__ import division + +''' +Example of the Hardy Cross Column Analogy to calculate non-prismatic +member end stiffnesses and carry over factors to be used in a moment +distribution analysis +''' + +segmentLengths = [12,12] #ft +E = [288000]*len(segmentLengths) #k/ft^2 +I = [0.667,5.333] #ft^4 + +L_tot = sum(segmentLengths) + +hardy_segment_widths = [1.0/(e*i) for e,i in zip(E,I)] + +hardy_segment_areas = [a*b for a,b in zip(segmentLengths,hardy_segment_widths)] + +hardy_Area = sum(hardy_segment_areas) + +hardy_segment_centers = [] +for i,L in enumerate(segmentLengths): + if i == 0: + hardy_segment_centers.append(L/2.0) + else: + x = L/2.0 + sum(segmentLengths[0:i]) + hardy_segment_centers.append(x) + +hardy_segment_Ax = [a*b for a,b in zip(hardy_segment_areas,hardy_segment_centers)] + +hardy_centroid = sum(hardy_segment_Ax) / hardy_Area + +hardy_segment_xbar = [a - hardy_centroid for a in hardy_segment_centers] + +hardy_segment_Icg = [(a*b*b*b)/ 12.0 for a,b in zip(hardy_segment_widths,segmentLengths)] + +hardy_segment_Ad2 = [a*b*b for a,b in zip(hardy_segment_areas,hardy_segment_xbar)] + +hardy_I = sum(hardy_segment_Icg)+sum(hardy_segment_Ad2) + +''' +ca = distance from left end to centroid +cb = distance from right end to centroid +''' +ca = -1.0*hardy_centroid +cb = L_tot - hardy_centroid + +''' +e_a = distance from point load @ end A to centroid = ca +e_b = distance from point load @ end B to centroid = cb +''' +e_a = ca +e_b = cb + +faa = (1.0/hardy_Area) + ((1.0*e_a*ca) / hardy_I) +fba = (1.0/hardy_Area) + ((1.0*e_a*cb) / hardy_I) + +Ka = faa +Ca = fba/faa + +fab = (1.0/hardy_Area) + ((1.0*e_b*cb) / hardy_I) +fbb = (1.0/hardy_Area) + ((1.0*e_b*ca) / hardy_I) + +Kb = fab +Cb = fbb/fab + +CaKa = Ca*Ka +CbKb = Cb*Kb + +check = CaKa == CbKb \ No newline at end of file diff --git a/Analysis/LoadTypes.py b/Analysis/LoadTypes.py new file mode 100644 index 0000000..f37ad48 --- /dev/null +++ b/Analysis/LoadTypes.py @@ -0,0 +1,353 @@ +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' + +from __future__ import division +import pin_pin_beam_equations_classes as ppbeam + +def load_patterns_by_span_ACI(n, byspan=True): + pat1 = [1 for i in range(1,n+1)] # all spans loaded + pat2 = [1 if i % 2 == 0 else 0 for i in range(1,n+1)] # even spans loaded + pat3 = [0 if i % 2 == 0 else 1 for i in range(1,n+1)] # odd spans loaded + + count = 0 + pat4 = [] + pat5 = [] + pat6 = [] + for i in range(1,n+1): + + if count<=1: + if count == 0: + pat4.append(1) + pat5.append(0) + pat6.append(1) + else: + pat4.append(1) + pat5.append(1) + pat6.append(0) + count+=1 + else: + pat4.append(0) + pat5.append(1) + pat6.append(1) + count=0 + + if n==1: + patterns = [pat1] + + elif n==2: + patterns = [pat1,pat2,pat3] + + elif n==3: + patterns = [pat1,pat2,pat3,pat4,pat5] + + else: + patterns = [pat1,pat2,pat3,pat4,pat5,pat6] + + if byspan == True: + patterns_transpose = map(list, zip(*patterns)) + + return patterns_transpose + else: + return patterns + +class Load: + def __init__(self, span=0, span_label='0', w1=0, w2=0, a=0, b=0, span_length=0, backspan_length=0, cantilever_side=0, load_kind = 'NL'): + ''' + A class to define loads vs using a list or dictionary + to allow for more consistent property definitions + and future embeded functions for things such as + fixed end forces + ''' + + self.span = span + self.span_label = span_label + self.w1 = w1 + self.w2 = w2 + self.a = a + self.b = b + self.span_length = span_length + self.backspan_length = backspan_length + self.cantilever_side = cantilever_side + self.load_kind = load_kind + + def make_analytical(self): + + if self.cantilever_side == 1: + + if self.load_kind == 'Point': + self.analytical = ppbeam.cant_left_point(self.w1,self.a,self.span_length,self.backspan_length) + + elif self.load_kind == 'Moment': + self.analytical = ppbeam.cant_left_point_moment(self.w1,self.a,self.span_length,self.backspan_length) + + elif self.load_kind == 'UDL': + self.analytical = ppbeam.cant_left_udl(self.w1,self.a,self.b,self.span_length,self.backspan_length) + + elif self.load_kind == 'TRAP': + self.analytical = ppbeam.cant_left_trap(self.w1, self.w2, self.a, self.b, self.span_length, self.backspan_length) + + elif self.load_kind == 'SLOPE': + self.analytical = ppbeam.cant_left_nl(self.w1,self.span_length) + + else: + self.analytical = ppbeam.no_load(0) + + elif self.cantilever_side == 2: + + if self.load_kind == 'Point': + self.analytical = ppbeam.cant_right_point(self.w1,self.a,self.span_length,self.backspan_length) + + elif self.load_kind == 'Moment': + self.analytical = ppbeam.cant_right_point_moment(self.w1,self.a,self.span_length,self.backspan_length) + + elif self.load_kind == 'UDL': + self.analytical = ppbeam.cant_right_udl(self.w1,self.a,self.b,self.span_length,self.backspan_length) + + elif self.load_kind == 'TRAP': + self.analytical = ppbeam.cant_right_trap(self.w1, self.w2, self.a, self.b, self.span_length, self.backspan_length) + + elif self.load_kind == 'SLOPE': + self.analytical = ppbeam.cant_right_nl(self.w1,self.span_length) + + else: + self.analytical = ppbeam.no_load(0) + else: + if self.load_kind == 'Point': + self.analytical = ppbeam.pl(self.w1,self.a,self.span_length) + + elif self.load_kind == 'Moment': + self.analytical = ppbeam.point_moment(self.w1,self.a,self.span_length) + + elif self.load_kind == 'UDL': + self.analytical = ppbeam.udl(self.w1,self.a,self.b,self.span_length) + + elif self.load_kind == 'TRAP': + self.analytical = ppbeam.trap(self.w1,self.w2,self.a,self.b,self.span_length) + + elif self.load_kind == 'END_DELTA': + self.analytical = ppbeam.end_delta(self.w1,self.w2,self.span_length) + + else: + self.analytical = ppbeam.no_load(0) + + + def fixed_end_forces(self): + self.make_analytical() + + self.fef = self.analytical.fef() + + def load_as_list(self): + + return [self.span, self.w1, self.w2, self.a, self.b, self.span_length, self.backspan_length, self.load_kind] + + + +class LoadType: + def __init__(self, pattern=False, off_pattern_factor=0, title='Dead',symbol='DL'): + ''' + A class to house loads to facilitate + performing load factoring, paterning, and combinations + + NOTE: unless a function notes otherwise everything expects to + be a getting list in the form of: + [span, w1,w2,a,b,L,'Load Type'] or + [span, w1,w2,a,b,L,L,'Load Type'] in the case of a load on a cantilever + + 'Load Type' should always be the last item + 'Span' should always be the first item + + ''' + + self.title = title + self.symbol = symbol + self.load_list = [] + self.pattern = pattern + self.off_pattern_factor = off_pattern_factor + self.factored_loads = 0 + self.all_factored_loads = [] + self.patterned_factored_loads = [] + self.all_patterned_factored_loads = [] + + def add_single_load(self,load=[0,0,0,10,10,10,'NL']): + self.load_list.append(load) + + def add_multi_loads(self,loads=[[0,0,0,10,10,10,'NL'],[0,0,0,10,10,10,'NL']]): + self.load_list.extend(loads) + + def remove_load_by_index(self, index): + num_loads = len(self.load_list) + + if num_loads == 0 or index > num_loads: + pass + else: + del self.load_list[index] + + def clear_loads(self): + + del self.load_list[:] + + def factor_loads(self,factor,on=1): + factored_loads = [] + + if self.pattern==False: + load_factor = factor + elif on == 1: + load_factor = factor + else: + load_factor = factor*self.off_pattern_factor + + for load in self.load_list: + w1 = load[1] + w2 = load[2] + + if w1*load_factor ==0 and w2*load_factor==0: + pass + + else: + w1_factored = w1*load_factor + w2_factored = w2*load_factor + + factored_loads.append([load[0],w1_factored,w2_factored]+load[3:]) + + self.factored_loads = factored_loads + + return factored_loads + + def multiple_factor_loads(self, factors=[1,1], on=1): + all_factored_loads = [] + + del self.all_factored_loads[:] + + for factor in factors: + all_factored_loads.append(self.factor_loads(factor,on)) + + self.all_factored_loads= all_factored_loads + + return all_factored_loads + + def pattern_and_factor_loads(self,factor,patterns = [1,0,1,1,0,1]): + + patterned_loads = [] + del self.patterned_factored_loads[:] + + for i, pattern in enumerate(patterns): + + for load in self.load_list: + + if load[0] == i: + + on = pattern + + if self.pattern==False: + load_factor = factor + elif on == 1: + load_factor = factor + else: + load_factor = factor*self.off_pattern_factor + + w1 = load[1] + w2 = load[2] + + if w1*load_factor ==0 and w2*load_factor==0: + pass + + else: + w1_factored = w1*load_factor + w2_factored = w2*load_factor + + patterned_loads.append([load[0],w1_factored,w2_factored]+load[3:]) + + else: + pass + + self.patterned_factored_loads = patterned_loads + + return patterned_loads + + +def load_combination(load_types, factors, patterns): + + load_set = [] + + for pattern in patterns: + pat_set = [] + for i,load in enumerate(load_types): + pat_set.extend(load.pattern_and_factor_loads(factors[i], pattern)) + load_set.append(pat_set) + + return load_set + +def load_combination_multi(load_types, factors, patterns): + + load_set = [] + + for factor in factors: + for pattern in patterns: + pat_set = [] + for i,load in enumerate(load_types): + pat_set.extend(load.pattern_and_factor_loads(factor[i], pattern)) + load_set.append(pat_set) + + return load_set + +Self = LoadType(False,1,'Self','SW') +Dead = LoadType(False,1,'Dead','DL') +Live = LoadType(False,0,'Live','LL') +Live_pat = LoadType(True,0,'Live_pat','LL_pat') + +Self.add_multi_loads([[0,1,0,0,10,30,0,'UDL'],[1,1,0,10,20,30,0,'UDL'],[2,1,0,20,30,30,0,'UDL']]) +Dead.add_multi_loads([[0,1,0,0,10,30,0,'UDL'],[1,1,0,10,20,30,0,'UDL'],[2,1,0,20,30,30,0,'UDL']]) + +Live.add_multi_loads([[0,1,0,0,10,30,0,'UDL'],[1,1,0,10,20,30,0,'UDL'],[2,1,0,20,30,30,0,'UDL']]) +Live_pat.add_multi_loads([[0,1,0,0,10,30,0,'UDL'],[1,1,0,10,20,30,0,'UDL'],[2,1,0,20,30,30,0,'UDL']]) + +patterns = load_patterns_by_span_ACI(3, False) + +combos = [[1,1,0,0],[0,0,1,1],[1,1,1,1],[3,3,1,1],[1.4,1.4,0,0],[1.2,1.2,1.6,1.6]] + +combined_loads = load_combination_multi([Self,Dead,Live,Live_pat],combos,patterns) + +unique_combo = [] + +for i, combined in enumerate(combined_loads): + if i == 0 or combined != combined_loads[i-1]: + unique_combo.append(combined) + else: + pass + +pat_live = [] +for i,pat in enumerate(patterns): + pat_live.append([]) + f = 1 + out = Live_pat.pattern_and_factor_loads(f,pat) + pat_live[i].extend(out) + +test_load = Load(0,'BM_1',1,0,0,10,10,0,0,'UDL') + +test_load.fixed_end_forces() + +print test_load.fef +print test_load.load_as_list() \ No newline at end of file diff --git a/Analysis/Section_Props_GUI.py b/Analysis/Section_Props_GUI.py index 71e5eaa..a30ba4c 100644 --- a/Analysis/Section_Props_GUI.py +++ b/Analysis/Section_Props_GUI.py @@ -1,18 +1,28 @@ -#!/usr/bin/env python - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import matplotlib @@ -157,20 +167,20 @@ def __init__(self, master): self.license_display() def license_display(self, *event): - license_string = ("This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n\n" - - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n\n" - - "You should have received a copy of the GNU General Public License along" - "with this program; if not, write to the Free Software Foundation, Inc.," - "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" - "\nA copy of the License can be viewed at:\n https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE") + license_string = ("Copyright (c) 2019, Donald N. Bockoven III\n" + "All rights reserved.\n\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" + " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" + " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" + " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" + " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" + " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" + " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," + " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" + "https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE" + ) tkMessageBox.showerror("License Information",license_string) self.master.focus_force() diff --git a/Analysis/TimoshenkoFormulas.py b/Analysis/TimoshenkoFormulas.py new file mode 100644 index 0000000..707c4f6 --- /dev/null +++ b/Analysis/TimoshenkoFormulas.py @@ -0,0 +1,1514 @@ +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' + +from __future__ import division +from numpy import sign +from numpy import zeros +import numpy as np +import math + +def fixedendmomentsTimoshenko(theta_0,theta_L, L, E, I, G, kA, fed=[1,1]): + ''' + Given the the start and end cross section rotations + Return the end moments that produce equal and opposite rotations + such that the net rotation at the member ends are 0 ie Fixed + + Sign convention is clockwise moments are positive + + [-Theta_0, -Theta_L] = [M_0,M_1] * [(1/kA G L)+(L/3EI), (1/kA G L)-(L/6EI) + (1/kA G L)-(L/6EI), (1/kA G L)+(L/3EI)] + + Using Numpy Linear Algebra to solve the simultaneous equations + ''' + + if fed[0] == 1 and fed[1] == 1: + s = np.array([[-1.0*theta_0],[-1.0*theta_L]]) + + ems = np.array([[(1.0/(kA*G*L))+(L/(3.0*E*I)) , (1.0/(kA*G*L))-(L/(6.0*E*I))], + [(1.0/(kA*G*L))-(L/(6.0*E*I)) , (1.0/(kA*G*L))+(L/(3.0*E*I))]]) + + fem = np.linalg.solve(ems,s) + + elif fed[0] == 1 and fed[1] == 0: + fel= (-1.0*theta_0) / ((1.0/(kA*G*L))+(L/(3.0*E*I))) + fem = np.array([[fel],[0]]) + + elif fed[0] == 0 and fed[1] == 1: + fer = (-1.0*theta_L) / ((1.0/(kA*G*L))+(L/(3.0*E*I))) + fem = np.array([[0],[fer]]) + + else: + fem = np.array([[0],[0]]) + + return fem + +class TimoshenkoBeam: + def __init__(L, E, I, G, kA): + ''' + Timoshenko General form equations for beam stiffness + and carry over factors + + + ** Maintain consistent units among the inputs ** + + L = beam span + E = beam modulus of elastacity + I = beam second moment of area about the axis of bending + G = beam shear modulus + kA = beam shear area, typically the beam web area for steel W shapes + + ''' + + self.L = L + self.E = E + self.I = I + self.G = G + self.kA = kA + + def cof(self, fixed=[1,1]): + ''' + carry over factor + g = 6EI / kAGL^2 + + ''' + + g = ((6*self.E*self.I) / (self.kA*self.G*self.L*self.L)) + + COF_fixed = (1-g) / (2+g) + + COF = [i*COF_fixed for i in fixed] + + return COF + + def k(self, fixed=[1,1]): + ''' + Stiffness factors + g = 6EI / kAGL^2 + ''' + g = ((6*self.E*self.I) / (self.kA*self.G*self.L*self.L)) + + K_farfixed = ((4*self.E*self.I) / self.L) * ((2+g)/(2*(1+(2*g)))) + + K_farpinned = ((3*self.E*self.I)/self.L) * (2/(2+g)) + + if fixed == [0,1]: + return [0,K_farpinned] + + elif fixed == [1,0]: + return [K_farpinned,0] + + elif fixed == [0,0]: + return [0,0] + + else: + return [K_farfixed,K_farfixed] + +class PointLoad: + def __init__(self, P, a, L, E, I, G, kA): + ''' + Timoshenko General form equations for a simply + supported beam with an applied Point load anywhere + along the beam span. + + Note unlike the Euler-Bernoulli beam formulas + the beam properties are needed as part of the + initial inputs. + + ** Maintain consistent units among the inputs ** + + P = load + a = load location from left end of beam + L = beam span + E = beam modulus of elastacity + I = beam second moment of area about the axis of bending + G = beam shear modulus + kA = beam shear area, typically the beam web area for steel W shapes + + sign convention: + (+) positive loads are applied in the (-) negative y direction + (+) positive reactions are in the (+) positive y direction + + ''' + + self.P = P + self.a = a + self.L = L + self.E = E + self.I = I + self.G = G + self.kA = kA + + # b = L-a + self.b = self.L - self.a + + self.kind = 'Point' + + self.error = '' + + if self.a > self.L: + self.error = 'Error a > l' + + # Simple End Reactions from statics + # Sum V = 0 and Sum M = 0 + + self.rl = (self.P*self.b)/self.L + self.rr = (self.P*self.a)/self.L + + ''' + Integration constants + resulting from integration of the two formulas + M = -EI dtheta/dx + V = kAG (-theta + ddelta/dx) + + Initial conditions: + delta = 0 at x=0 and x = L + + Compatibility conditions: + theta = constant at x = a + delta = constant at x = a + ''' + + self.c1 = ((-1*self.P*math.pow(self.a,2)) / (2*self.E*self.I) + + ((self.P*math.pow(self.a,3)) / (6*self.E*self.I*self.L)) + + ((self.P*self.a*self.L) / (3*self.E*self.I))) + + self.c2 = 0 + + self.c3 = (((self.P*math.pow(self.a,3))/(6*self.E*self.I*self.L)) + + ((self.P*self.a*self.L)/(3*self.E*self.I))) + + self.c4 = (((self.P*self.a)/(self.kA*self.G)) - + ((self.P*math.pow(self.a,3))/(6*self.E*self.I))) + + + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + ''' + function returns x and y coordinate data to facilitate + chart plotting + + y scaling is applied to the load value + x scaling only impacts the arrow head if arrows are + selected to be included + + arrows simply places two diagonal lines at the load intersection with + the beam line. + + ''' + + if arrows == 1: + arrow_height = (self.P/6.0) + #30 degree arrow + arrow_plus= (self.a+(arrow_height*math.tan(math.radians(30)))) + arrow_minus= (self.a-(arrow_height*math.tan(math.radians(30)))) + + x=[arrow_minus,self.a,arrow_plus,self.a,self.a] + x = [i*x_scale for i in x] + y=[arrow_height,0,arrow_height,0,self.P] + y = [j*y_scale for j in y] + else: + x = [self.a*x_scale, self.a*x_scale] + y = [0,self.P*y_scale] + + return x,y + + def fef(self): + ''' + fixed end forces + g = 6EI / kAGL^2 + + Sign convention: + (+) positive moments are clock-wise + + ''' + + # redefine variables from self. to local to + # make formulas easier to read + P = self.P + a = self.a + b = self.b + L = self.L + + g = ((6*self.E*self.I) / (self.kA*self.G*self.L*self.L)) + + ML = -1.0 * ((P*a*b*b) / (L*L))*((1+((L/b)*g))/(1+(2*g))) + MR = ((P*a*a*b) / (L*L))*((1+((L/a)*g))/(1+(2*g))) + + # additional vertical reactions caused by fixed end moments + + MRL = -1.0*(ML+MR)/L + MRR = -1.0*MRL + + RL = self.rl + MRL + RR = self.rr + MRR + + return [RL, ML, RR, MR] + + def v(self,x): + ''' + function takes an array of x locations along the beam and + returns the associated internal beam shear + ''' + + iters = len(x) + v=zeros(iters) + + for i in range(0,iters): + if x[i] <= self.a: + if x[i] == 0 and self.a == 0: + v[i] = 0 + else: + v[i] = self.rl + else: + v[i] = -1 * self.rr + return v + + def m(self,x): + ''' + function takes an array of x locations along the beam and + returns the associated internal beam moment + ''' + + iters = len(x) + m=zeros(iters) + + for i in range(0,iters): + if x[i] <= self.a: + m[i] = self.rl * x[i] + else: + m[i] = (-1 * self.rr * x[i]) + (self.rr * self.L) + return m + + def theta(self,x): + ''' + function takes an array of x locations along the beam and + returns the associated internal rotation of the cross-section vertical + axis + ''' + + iters = len(x) + theta = zeros(iters) + + for i in range(0,iters): + if x[i] <= self.a: + theta[i] = (((-1*self.rl*math.pow(x[i],2))/(2*self.E*self.I)) + + self.c1) + else: + theta[i] = (((self.P*self.a*math.pow(x[i],2)) / (2*self.E*self.I*self.L)) - + ((self.P*self.a*x[i]) / (self.E*self.I)) + + self.c3) + return theta + + def delta(self,x): + ''' + function takes an array of x locations along the beam and + returns the associated beam vertical deflection + ''' + + iters = len(x) + delta = zeros(iters) + + for i in range(0,iters): + if x[i] <= self.a: + delta[i] = (((self.rl*x[i])/(self.kA*self.G)) - + ((self.rl*math.pow(x[i],3))/(6*self.E*self.I)) + + (self.c1*x[i]) + self.c2) + + else: + delta[i] = (((-1.0*self.rr*x[i])/(self.kA*self.G)) + + ((self.P*self.a*math.pow(x[i],3))/(6*self.E*self.I*self.L)) - + ((self.P*self.a*math.pow(x[i],2))/(2*self.E*self.I)) + + (self.c3*x[i]) + self.c4) + + return delta + + ''' + The below functions do the same as above with the exception that they only + accept a single x location and report a single result. + ''' + + def vx(self,x): + if x <= self.a: + if x == 0 and self.a == 0: + vx = 0 + else: + vx = self.rl + else: + vx = -1 * self.rr + return vx + + def mx(self,x): + if x <= self.a: + mx = self.rl * x + else: + mx = (-1 * self.rr * x) + (self.rr * self.L) + return mx + + def thetax(self,x): + if x <= self.a: + thetax = (((-1*self.rl*math.pow(x,2))/(2*self.E*self.I)) + + self.c1) + else: + thetax = (((self.rr*math.pow(x,2)) / (2*self.E*self.I)) - + ((self.rr*self.L*x) / (self.E*self.I)) + + self.c3) + return thetax + + def deltax(self,x): + if x <= self.a: + deltax = (((self.rl*x)/(self.kA*self.G)) - + ((self.rl*math.pow(x,3))/(6*self.E*self.I)) + + (self.c1*x) + self.c2) + + else: + deltax = (((-1.0*self.rr*x)/(self.kA*self.G)) + + ((self.P*self.a*math.pow(x,3))/(6*self.E*self.I*self.L)) - + ((self.P*self.a*math.pow(x,2))/(2*self.E*self.I)) + + (self.c3*x) + self.c4) + + return deltax + +class PointMoment: + def __init__(self, M, a, L, E, I, G, kA): + ''' + Timoshenko General form equations for a simply + supported beam with an applied Point Moment anywhere + along the beam span. + + Note unlike the Euler-Bernoulli beam formulas + the beam properties are needed as part of the + initial inputs. + + ** Maintain consistent units among the inputs ** + + M = moment + a = load location from left end of beam + L = beam span + E = beam modulus of elastacity + I = beam second moment of area about the axis of bending + G = beam shear modulus + kA = beam shear area, typically the beam web area for steel W shapes + + sign convention: + (+) positive moments are applied clockwise + (+) positive reactions are in the (+) positive y direction + + ''' + + self.M = M + self.a = a + self.L = L + self.E = E + self.I = I + self.G = G + self.kA = kA + + # b = L-a + self.b = self.L - self.a + + self.kind = 'Moment' + + self.error = '' + + if self.a > self.L: + self.error = 'Error a > l' + + # Simple End Reactions from statics + # Sum V = 0 and Sum M = 0 + + self.rl = -1.0*self.M/self.L + self.rr = self.M/self.L + + ''' + Integration constants + resulting from integration of the two formulas + M = -EI dtheta/dx + V = kAG (-theta + ddelta/dx) + + Initial conditions: + delta = 0 at x=0 and x = L + + Compatibility conditions: + theta = constant at x = a + delta = constant at x = a + ''' + + self.c1 = (((-1.0*self.M*self.a) / (self.E*self.I)) + + ((self.M*math.pow(self.a,2))/(2*self.E*self.I*self.L)) + + (self.M/(self.kA*self.G*self.L)) + + ((self.M*self.L)/(3*self.E*self.I))) + + self.c2 = 0 + + self.c3 = (((self.M*math.pow(self.a,2))/(2*self.E*self.I*self.L)) + + (self.M/(self.kA*self.G*self.L)) + + ((self.M*self.L)/(3*self.E*self.I))) + + self.c4 = (-1.0*self.M*math.pow(self.a,2))/(2*self.E*self.I) + + + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + ''' + function returns x and y coordinate data to facilitate + chart plotting + + y scaling is applied to the load value + x scaling only impacts the arrow head if arrows are + selected to be included + + arrows simply places two diagonal lines at the load intersection with + the beam line. + + ''' + + x=[] + y=[] + r = (self.M/2.0) + # set radius as M/2 so when centered on beam line the moment symbol + # total height mathces the moment value + + if arrows == 1: + arrow_height = r/6.0 + #30 degree arrow + arrow_minus= (arrow_height*math.tan(math.radians(30))) + + if self.ma <0: + x = [self.a,self.a,self.a] + y = [r,0,-r] + xi=0 + yi=0 + for a in range(-90, 181): + xi = (self.a)+((r*math.cos(math.radians(a)))) + yi = 0+((r*math.sin(math.radians(a)))) + x.append(xi) + y.append(yi) + + x.append(xi-arrow_minus) + y.append(yi+arrow_height) + x.append(xi) + y.append(yi) + x.append(xi+arrow_minus) + y.append(yi+arrow_height) + else: + x = [self.a-r,self.a,self.a+r, self.a+r-arrow_minus,self.a+r,self.a+r+arrow_minus,self.a+r] + y = [0,0,0,arrow_height,0,arrow_height,0] + + xi=0 + yi=0 + for a in range(0,271): + xi = self.a+(r*math.cos(math.radians(a))) + yi = 0+(r*math.sin(math.radians(a))) + x.append(xi) + y.append(yi) + else: + if self.ma <0: + x = [self.a,self.a,self.a] + y = [r,0,-r] + xi=0 + yi=0 + for a in range(-90, 181): + xi = self.a+(r*math.cos(math.radians(a))) + yi = 0+(r*math.sin(math.radians(a))) + x.append(xi) + y.append(yi) + else: + x = [self.a-r,self.a,self.a+r] + y = [0,r,0] + xi=0 + yi=0 + for a in range(0,271): + xi = self.a+(r*math.cos(math.radians(a))) + yi = 0+(r*math.sin(math.radians(a))) + x.append(xi) + y.append(yi) + + x = [i*x_scale for i in x] + y = [j*y_scale for j in y] + + return x,y + + def fef(self): + ''' + fixed end forces + g = 6EI / kAGL^2 + + Sign convention: + (+) positive moments are clock-wise + + ''' + + # redefine variables from self. to local to + # make formulas easier to read + M = self.M + a = self.a + b = self.b + L = self.L + + g = ((6*self.E*self.I) / (self.kA*self.G*self.L*self.L)) + + ML = 0 + MR = 0 + + # additional vertical reactions caused by fixed end moments + + MRL = -1.0*(ML+MR)/L + MRR = -1.0*MRL + + RL = self.rl + MRL + RR = self.rr + MRR + + return [RL, ML, RR, MR] + + def v(self,x): + ''' + function takes an array of x locations along the beam and + returns the associated internal beam shear + ''' + + iters = len(x) + v=zeros(iters) + + for i in range(0,iters): + v[i] = self.rl + + return v + + def m(self,x): + ''' + function takes an array of x locations along the beam and + returns the associated internal beam moment + ''' + + iters = len(x) + m=zeros(iters) + + for i in range(0,iters): + if x[i] <= self.a: + m[i] = self.rl * x[i] + else: + m[i] = self.rl * x[i] + self.M + return m + + def theta(self,x): + ''' + function takes an array of x locations along the beam and + returns the associated internal rotation of the cross-section vertical + axis + ''' + + iters = len(x) + theta = zeros(iters) + + for i in range(0,iters): + if x[i] <= self.a: + theta[i] = ((self.M*math.pow(x[i],2))/(2*self.E*self.I*self.L)) + self.c1 + else: + theta[i] = (((self.M*math.pow(x[i],2))/(2*self.E*self.I*self.L)) - + ((self.M*x[i])/(self.E*self.I)) + + self.c3) + + return theta + + def delta(self,x): + ''' + function takes an array of x locations along the beam and + returns the associated beam vertical deflection + ''' + + iters = len(x) + delta = zeros(iters) + + for i in range(0,iters): + if x[i] <= self.a: + delta[i] = (((-1.0*self.M*x[i])/(self.kA*self.G*self.L))+ + ((self.M*math.pow(x[i],3))/(6*self.E*self.I*self.L))+ + (self.c1*x[i])+ + self.c2) + + else: + delta[i] = (((-1.0*self.M*x[i])/(self.kA*self.G*self.L))+ + ((self.M*math.pow(x[i],3))/(6*self.E*self.I*self.L))- + ((self.M*math.pow(x[i],2))/(2*self.E*self.I))+ + (self.c3*x[i])+ + self.c4) + + return delta + + ''' + The below functions do the same as above with the exception that they only + accept a single x location and report a single result. + ''' + + def vx(self,x): + vx = self.rl + + return vx + + def mx(self,x): + if x <= self.a: + mx = self.rl * x + else: + mx = self.rl * x + self.M + return mx + + def thetax(self,x): + if x <= self.a: + thetax = ((self.M*math.pow(x,2))/(2*self.E*self.I*self.L)) + self.c1 + else: + thetax = (((self.M*math.pow(x,2))/(2*self.E*self.I*self.L)) - + ((self.M*x)/(self.E*self.I)) + + self.c3) + return thetax + + def deltax(self,x): + if x <= self.a: + deltax = (((-1.0*self.M*x)/(self.kA*self.G*self.L))+ + ((self.M*math.pow(x,3))/(6*self.E*self.I*self.L))+ + (self.c1*x)+ + self.c2) + + else: + deltax = (((-1.0*self.M*x)/(self.kA*self.G*self.L))+ + ((self.M*math.pow(x,3))/(6*self.E*self.I*self.L))- + ((self.M*math.pow(x,2))/(2*self.E*self.I))+ + (self.c3*x)+ + self.c4) + + return deltax + +class UniformLoad: + def __init__(self, w, a, b, L, E, I, G, kA): + ''' + Timoshenko derivation for uniform loading + pin-pin single span beam + + w - Load left end value + a - load start point from left end of beam + b - load end point from left end of beam + d - load width = b - a + L - beam span + E = beam modulus of elastacity + I = beam second moment of area about the axis of bending + G = beam shear modulus + kA = beam shear area, typically the beam web area for steel W shapes + + sign convention: + (+) positive moments are applied clockwise + (+) positive reactions are in the (+) positive y direction + ''' + self.w = w + self.a = a + self.b = b + self.L = L + self.E = E + self.I = I + self.G = G + self.kA = kA + + d= b - a + self.d = d + + ''' + Reactions: + W = w*d + sum Fy = 0 + --> RL + RR - W = 0 + xbar = (a + d/2) + sum Mx,rl,cw+ = 0 + --> -RR*L + W*(xbar) = 0 + --> RR = W*(xbar) / L + + RL = W - RR + ''' + + W = w*d + self.W = W + xbar = a + (d/2.0) + self.xbar = xbar + + RR = (W*xbar) / L + RL = W - RR + + self.RR = RR + self.RL = RL + + #Boundary and Compatibility equation + #Lists of coefficients and lists of associated equalities + ''' + Solve for Constants using boundary conditions and compatibility: + **Boundary @ x=0, V=RL:** + //c1 = RL + + **Boundary @ x=L, V=-RR:** + //c3 = -RR + + **Compatibility @ x=a, V=constant:** + c1 = -1*w*a + c2 + + //-c1 + c2 = w*a + + **Boundary @ x=0, M=0:** + //c4 = 0 + + **Boundary @ x=L, M=0:** + //c3*L + c6 = 0 + c6 = -c3*L + + **Compatibility @ x=a, M=constant:** + c1*a = (-1*w*a^2)/2 + c2*a + c5 + + //c1*a - c2*a - c5 = (-1*w*a^2)/2 + + **Boundary @ x=0, delta=0:** + //c10 = 0 + + **Boundary @ x=L, delta=0:** + //0 = c3*L/kAG + (-c3*L^3)/(6*EI) - c6*L^2/2*EI + c9*L + c12 + + **Compatibility @ x=a, delta=constant:** + c1*a/kAG + (-c1*a^3)/(6*EI) - c4*a^2/2*EI + c7*a = + -1*w*a^2/2*kAG + c2*a/kAG + (w*a^4)/(24*EI) - (c2*a^3)/6*EI - c5*a^2/2*EI + c8*a + c11 + + //c1*a/kAG + (-c1*a^3)/(6*EI) - c2*a/kAG + (c2*a^3)/6*EI - c4*a^2/2*EI + c5*a^2/2*EI + c7*a - c8*a - c11 = + -1*w*a^2/2*kAG + (w*a^4)/(24*EI) + + **Compatibility @ x=b, delta = constant:** + c3*b/kAG + (-c3*b^3)/(6*EI) - c6*b^2/2*EI + c9*b + c12 = + -1*w*b^2/2*kAG + c2*b/kAG + (w*b^4)/(24*EI) - (c2*b^3)/6*EI - c5*b^2/2*EI + c8*b + c11 + + //-c2*b/kAG + (c2*b^3)/6*EI + c3*b/kAG + (-c3*b^3)/(6*EI) + c5*b^2/2*EI - c6*b^2/2*EI - c8*b + c9*b - c11 + c12 = + -1*w1*b^2/2*kAG + (w1*b^4)/(24*EI) + + **Compatibility @ x=a, theta=constant:** + (-c1*a^2)/(2*EI) - c4*a/EI + c7 = (w*a^3)/(6*EI) - (c2*a^2)/2*EI - c5*a/EI + c8 + + //(-c1*a^2)/(2*EI) + (c2*a^2)/2*EI - c4*a/EI + c5*a/EI + c7 - c8 = (w*a^3)/(6*EI) + + **Compatibility @ x=b, theta = constant:** + (w*b^3)/(6*EI) - (c2*b^2)/2*EI - c5*b/EI + c8 = (-c3*b^2)/(2*EI) - c6*b/EI + c9 + + //(-c2*b^2)/2*EI + (c3*b^2)/(2*EI) - c5*b/EI + c6*b/EI + c8 - c9 = (-1*w*b^3)/(6*EI) + + ''' + bc1_coeff = [1,0,0,0,0,0,0,0,0,0,0,0] + bc1_eq = [RL] + + bc2_coeff = [-1,1,0,0,0,0,0,0,0,0,0,0] + bc2_eq = [w*a] + + bc3_coeff = [0,0,1,0,0,0,0,0,0,0,0,0] + bc3_eq = [-1*RR] + + bc4_coeff = [0,0,0,1,0,0,0,0,0,0,0,0] + bc4_eq = [0] + + bc5_coeff = [-1*a,a,0,0,1,0,0,0,0,0,0,0] + bc5_eq = [(w*math.pow(a,2))/2.0] + + bc6_coeff = [0,0,L,0,0,1,0,0,0,0,0,0] + bc6_eq = [0] + + bc7_coeff = [(-1*math.pow(a,2))/(2*E*I),(math.pow(a,2))/(2*E*I),0,0,a/(E*I),0,1,-1,0,0,0,0] + bc7_eq = [(w*math.pow(a,3))/(6*E*I)] + + bc8_coeff = [0, + (math.pow(b,2))/(2*E*I), + (-1*math.pow(b,2))/(2*E*I), + 0, + b/(E*I), + (-1*b)/(E*I), + 0, + -1, + 1, + 0, + 0, + 0] + + bc8_eq = [((w*math.pow(b,3))/(6*E*I))] + + bc9_coeff = [0,0,(L/(kA*G)) + ((-1*math.pow(L,3))/(6*E*I)),0,0,-1*math.pow(L,2)/(2*E*I),0,0,L,0,0,1] + bc9_eq = [0] + + bc10_coeff = [0,0,0,0,0,0,0,0,0,1,0,0] + bc10_eq = [0] + + bc11_coeff = [(a/(kA*G)) + ((-1*math.pow(a,3))/(6*E*I)), + (-1*a/(kA*G)) + ((math.pow(a,3))/(6*E*I)), + 0, + 0, + (math.pow(a,2)/(2*E*I)), + 0, + a, + -1*a, + 0, + 0, + -1, + 0] + + bc11_eq = [(-1*w*math.pow(a,2)/(2*kA*G)) + ((w*math.pow(a,4))/(24*E*I))] + + bc12_coeff = [0, + (-1*b/(kA*G)) + ((math.pow(b,3))/(6*E*I)), + (b/(kA*G)) + ((-1*math.pow(b,3))/(6*E*I)), + 0, + math.pow(b,2)/(2*E*I), + -1*math.pow(b,2)/(2*E*I), + 0, + -1*b, + b, + 0, + -1, + 1] + + bc12_eq = [((-1*w*math.pow(b,2))/(2*kA*G)) + ((w*math.pow(b,4))/(24*E*I))] + + + bceq = [bc1_coeff,bc2_coeff,bc3_coeff,bc4_coeff,bc5_coeff,bc6_coeff,bc7_coeff,bc8_coeff,bc9_coeff,bc10_coeff,bc11_coeff,bc12_coeff] + bcs = [bc1_eq,bc2_eq,bc3_eq,bc4_eq,bc5_eq,bc6_eq,bc7_eq,bc8_eq,bc9_eq,bc10_eq,bc11_eq,bc12_eq] + + bceq = np.array(bceq) + bcs = np.array(bcs) + + c = np.linalg.solve(bceq,bcs) + self.c = c + + ''' + Load Formulas: + 0 < x < a: + w = 0 + + a < x < b: + w = -1*w + + b < x < L: + w = 0 + + Shear Formulas: + w = dV/dx, therefore V = integral w dx + + 0 < x < a: + V = c1 + + a < x < b: + V = -1*w*x + c2 + + c < x < L: + V = c3 + ''' + def vx(self,x): + + # redefine variables from self. to local to + # make formulas easier to read + w = self.w + a = self.a + c = self.c + b = self.b + L = self.L + + if 0 <= x <= a: + v = c[0][0] + elif a < x <= b: + v = (-1*w*x) + c[1][0] + elif b < x <= L: + v = c[2][0] + else: + v = 0 + + return v + + ''' + Moment Formulas: + V = dM/dx, therefore M = integral V dx + + 0 < x < a: + M = c1*x + c4 + + a < x < b: + M = (-1*w*x^2)/2 + c2*x + c5 + + b < x < L: + M = c3*x + c6 + ''' + def mx(self,x): + # redefine variables from self. to local to + # make formulas easier to read + w = self.w + a = self.a + c = self.c + b = self.b + L = self.L + + if 0 <= x <= a: + m = c[0][0]*x + c[3][0] + elif a < x <= b: + m = (((-1*w*math.pow(x,2))/2.0) + + c[1][0]*x + + c[4][0]) + elif b < x <= L: + m = c[2][0]*x + c[5][0] + else: + m = 0 + return m + + ''' + Timoshenko Relationship for Rotation, theta, and Deflection, delta + M = -E*I d theta/dx + V = kAG (-theta + d delta/dx) + + Rotation Formulas: + theta = integral M/-EI dx + + 0 < x < a: + theta = (-c1*x^2)/(2*EI) - c4*x/EI + c7 + + a < x < b: + theta = (w1*x^3)/(6*EI) - (c2*x^2)/2*EI - c5*x/EI + c8 + + b < x < L: + theta = (-c3*x^2)/(2*EI) - c6*x/EI + c9 + ''' + + def thetax(self,x): + + # redefine variables from self. to local to + # make formulas easier to read + w = self.w + a = self.a + c = self.c + b = self.b + L = self.L + E = self.E + I = self.I + + if 0 <= x <= a: + theta = (((-1*c[0][0]*math.pow(x,2))/(2.0*E*I)) - + ((c[3][0]*x)/(E*I)) + + c[6][0]) + elif a < x <= b: + theta = (((w*math.pow(x,3))/(6.0*E*I)) - + ((c[1][0]*math.pow(x,2))/(2.0*E*I)) - + ((c[4][0]*x)/(E*I)) + + c[7][0]) + elif b < x <= L: + theta = (((-1*c[2][0]*math.pow(x,2))/(2.0*E*I)) - + ((c[5][0]*x)/(E*I)) + + c[8][0]) + else: + theta = 0 + + return theta + + ''' + Delta Formulas: + delta = integral V/kAG + theta dx + + 0 < x < a: + delta = c1*x/kAG + (-c1*x^3)/(6*EI) - c4*x^2/2*EI + c7*x + c10 + + a < x < b: + delta = -1*w1*x^2/2*kAG + c2*x/kAG + (w1*x^4)/(24*EI) - (c2*x^3)/6*EI - c5*x^2/2*EI + c8*x + c11 + + b < x < L: + delta = c3*x/kAG + (-c3*x^3)/(6*EI) - c6*x^2/2*EI + c9*x + c12 + ''' + def deltax(self,x): + # redefine variables from self. to local to + # make formulas easier to read + w = self.w + a = self.a + c = self.c + b = self.b + L = self.L + E = self.E + I = self.I + G = self.G + kA = self.kA + + if 0 <= x <= a: + delta = (((c[0][0]*x)/(kA*G)) + + ((-1*c[0][0]*math.pow(x,3))/(6.0*E*I)) - + ((c[3][0]*math.pow(x,2))/(2.0*E*I)) + + (c[6][0]*x) + + c[9][0]) + elif a < x <= b: + delta = (((-1*w*math.pow(x,2))/(2.0*kA*G)) + + ((c[1][0]*x)/(kA*G)) + + ((w*math.pow(x,4))/(24.0*E*I)) - + ((c[1][0]*math.pow(x,3))/(6.0*E*I)) - + ((c[4][0]*math.pow(x,2))/(2.0*E*I)) + + (c[7][0]*x) + + c[10][0]) + elif b < x <= L: + delta = (((c[2][0]*x)/(kA*G)) + + ((-1*c[2][0]*math.pow(x,3))/(6.0*E*I)) - + ((c[5][0]*math.pow(x,2))/(2*E*I)) + + (c[8][0]*x) + + c[11][0]) + else: + delta = 0 + + return delta + + def fef(self): + L = self.L + E = self.E + I = self.I + G = self.G + kA = self.kA + + fem = fixedendmomentsTimoshenko(self.thetax(0), self.thetax(L), L, E, I, G, kA, [1,1]) + + ML = fem[0][0] + MR = fem[1][0] + + mo = timoforms.PointMoment(ML,0,L,E,I,G,kA) + ml = timoforms.PointMoment(MR,L,L,E,I,G,kA) + + RL = self.RL + mo.rl + ml.rl + RR = self.RR + mo.rr + ml.rr + + return [RL,ML,RR,MR] + +class VariableLoad: + def __init__(self, w1, w2, a, b, L, E, I, G, kA): + ''' + Timoshenko derivation for trapezoidal/variable loading + pin-pin single span beam + + w1 - Load left end value + w2 - load right end value + a - load start point from left end of beam + b - load end point from left end of beam + d - load width = b - a + s - slope of load = (w2 - w1) / d + L - beam span + E = beam modulus of elastacity + I = beam second moment of area about the axis of bending + G = beam shear modulus + kA = beam shear area, typically the beam web area for steel W shapes + + sign convention: + (+) positive moments are applied clockwise + (+) positive reactions are in the (+) positive y direction + ''' + self.w1 = w1 + self.w2 = w2 + self.a = a + self.b = b + self.L = L + self.E = E + self.I = I + self.G = G + self.kA = kA + + d= b - a + self.d = d + s= (w2 - w1) / d + self.s = s + + + ''' + Reactions: + W = (w1 + w2)*d*0.5 + sum Fy = 0 + --> RL + RR - W = 0 + xbar = (d * ((2 * w2) + w1)) / (3 * (w2 + w1)) + sum Mx,rl,cw+ = 0 + --> -RR*L + W*(a+xbar) = 0 + --> RR = W*(a+xbar) / L + + RL = W - RR + ''' + + W = (w1 + w2)*d*0.5 + self.W = W + xbar = (d * ((2 * w2) + w1)) / (3 * (w2 + w1)) + self.xbar = xbar + + RR = W*(a+xbar) / L + RL = W - RR + + self.RR = RR + self.RL = RL + + #Boundary and Compatibility equation + #Lists of coefficients and lists of associated equalities + ''' + Solve for Constants using boundary conditions and compatibility: + **Boundary @ x=0, V=RL:** + //c1 = RL + + **Boundary @ x=L, V=-RR:** + //c3 = -RR + + **Compatibility @ x=a, V=constant:** + c1 = -1*w1*a - (s(a-a)^2)/2 + c2 + + //-c1 + c2 = w1*a + + **Boundary @ x=0, M=0:** + //c4 = 0 + + **Boundary @ x=L, M=0:** + //c3*L + c6 = 0 + c6 = -c3*L + + **Compatibility @ x=a, M=constant:** + c1*a = (-1*w1*a^2)/2 - (s(a-a)^3)/6 + c2*a + c5 + + //-c1*a + c2*a + c5 = (w1*a^2)/2 + (s(a-a)^3)/6 + + **Boundary @ x=0, delta=0:** + //c10 = 0 + + **Boundary @ x=L, delta=0:** + //0 = c3*L/kAG + (-c3*L^3)/(6*EI) - c6*L^2/2*EI + c9*L + c12 + + **Compatibility @ x=a, delta=constant:** + c1*a/kAG + (-c1*a^3)/(6*EI) - c4*a^2/2*EI + c7*a = + -1*w1*a^2/2*kAG - (s(a-a)^3)/6*kAG + c2*a/kAG + (w1*a^4)/(24*EI) + (s(a-a)^5)/(120*EI) - (c2*a^3)/6*EI - c5*a^2/2*EI + c8*a + c11 + + //c1*a/kAG + (-c1*a^3)/(6*EI) - c2*a/kAG + (c2*a^3)/6*EI - c4*a^2/2*EI + c5*a^2/2*EI + c7*a - c8*a - c11 = + -1*w1*a^2/2*kAG + (w1*a^4)/(24*EI) + + **Compatibility @ x=a, theta=constant:** + (-c1*a^2)/(2*EI) - c4*a/EI + c7 = (w1*a^3)/(6*EI) + (s(a-a)^4)/(24*EI) - (c2*a^2)/2*EI - c5*a/EI + c8 + + //(-c1*a^2)/(2*EI) + (c2*a^2)/2*EI - c4*a/EI + c5*a/EI + c7 - c8 = (w1*a^3)/(6*EI) + + **Compatibility @ x=b, theta = constant:** + (w1*b^3)/(6*EI) + (s(b-a)^4)/(24*EI) - (c2*b^2)/2*EI - c5*b/EI + c8 = (-c3*b^2)/(2*EI) - c6*b/EI + c9 + + //(-c2*b^2)/2*EI + (c3*b^2)/(2*EI) - c5*b/EI + c6*b/EI + c8 - c9 = (-1*w1*b^3)/(6*EI) - (s(b-a)^4)/(24*EI) + + + **Compatibility @ x=b, delta = constant:** + c3*b/kAG + (-c3*b^3)/(6*EI) - c6*b^2/2*EI + c9*b + c12 = + -1*w1*b^2/2*kAG - (s(b-a)^3)/6*kAG + c2*b/kAG + (w1*b^4)/(24*EI) + (s(b-a)^5)/(120*EI) - (c2*b^3)/6*EI - c5*b^2/2*EI + c8*b + c11 + + //-c2*b/kAG + (c2*b^3)/6*EI + c3*b/kAG + (-c3*b^3)/(6*EI) + c5*b^2/2*EI - c6*b^2/2*EI - c8*b + c9*b - c11 + c12 = -1*w1*b^2/2*kAG - (s(b-a)^3)/6*kAG + (w1*b^4)/(24*EI) + (s(b-a)^5)/(120*EI) + + Matrix formulation for constants: + // above indicates formula in matrix + c1 [1,0,0,0,0,0,0,0,0,0,0,0] [RL] + c2 [-1,1,0,0,0,0,0,0,0,0,0,0] [w1*a] + c3 [0,0,1,0,0,0,0,0,0,0,0,0] [-RR] + c4 [0,0,0,1,0,0,0,0,0,0,0,0] [0] + c5 [-a,a,0,0,1,0,0,0,0,0,0,0] [(w1*a^2)/2] + c6 [0,0,L,0,0,1,0,0,0,0,0,0] [0] + c7 [(-1*a^2)/(2*EI),(a^2)/2*EI,0,-1*a/EI,a/EI,0,1,-1,0,0,0,0] [(w1*a^3)/(6*EI)] + c8 [0,(-1*b^2)/2*EI,(b^2)/(2*EI),0,-1*b/EI,b/EI,0,1,-1,0,0,0] [(-1*w1*b^3)/(6*EI) - (s(b-a)^4)/(24*EI)] + c9 [0,0,L/kAG + (-1*L^3)/(6*EI),0,0,-1*L^2/2*EI,0,0,L,0,0,1] [0] + c10 [0,0,0,0,0,0,0,0,0,1,0,0] [0] + c11 [a/kAG + (-1*a^3)/(6*EI),-1*a/kAG + (a^3)/6*EI,0,-1*a^2/2*EI,a^2/2*EI,0,a,-a,0,0,-1,0] [-1*w1*a^2/2*kAG + (w1*a^4)/(24*EI)] + c12 [0,-1*b/kAG + (b^3)/6*EI,d/kAG + (-1*b^3)/(6*EI),0,b^2/2*EI,-1*b^2/2*EI,0,-1*b,b,0,-1,1] [-1*w1*b^2/2*kAG - (s(b-a)^3)/6*kAG + (w1*b^4)/(24*EI) + (s(b-a)^5)/(120*EI)] + ''' + bc1_coeff = [1,0,0,0,0,0,0,0,0,0,0,0] + bc1_eq = [RL] + + bc2_coeff = [-1,1,0,0,0,0,0,0,0,0,0,0] + bc2_eq = [w1*a] + + bc3_coeff = [0,0,1,0,0,0,0,0,0,0,0,0] + bc3_eq = [-1*RR] + + bc4_coeff = [0,0,0,1,0,0,0,0,0,0,0,0] + bc4_eq = [0] + + bc5_coeff = [-1*a,a,0,0,1,0,0,0,0,0,0,0] + bc5_eq = [(w1*math.pow(a,2))/2.0] + + bc6_coeff = [0,0,L,0,0,1,0,0,0,0,0,0] + bc6_eq = [0] + + bc7_coeff = [(-1*math.pow(a,2))/(2*E*I),(math.pow(a,2))/(2*E*I),0,-1*a/(E*I),a/(E*I),0,1,-1,0,0,0,0] + bc7_eq = [(w1*math.pow(a,3))/(6*E*I)] + + bc8_coeff = [0, + (-1*math.pow(b,2))/(2*E*I), + (math.pow(b,2))/(2*E*I), + 0, + -1*b/(E*I), + b/(E*I), + 0, + 1, + -1, + 0, + 0, + 0] + + bc8_eq = [((-1*w1*math.pow(b,3))/(6*E*I)) - ((s*math.pow((b-a),4))/(24*E*I))] + + bc9_coeff = [0,0,(L/(kA*G)) + ((-1*math.pow(L,3))/(6*E*I)),0,0,-1*math.pow(L,2)/(2*E*I),0,0,L,0,0,1] + bc9_eq = [0] + + bc10_coeff = [0,0,0,0,0,0,0,0,0,1,0,0] + bc10_eq = [0] + + bc11_coeff = [(a/(kA*G)) + ((-1*math.pow(a,3))/(6*E*I)), + (-1*a/(kA*G)) + ((math.pow(a,3))/(6*E*I)), + 0, + ((-1*math.pow(a,2))/(2*E*I)), + (math.pow(a,2)/(2*E*I)), + 0, + a, + -1*a, + 0, + 0, + -1, + 0] + + bc11_eq = [(-1*w1*math.pow(a,2)/(2*kA*G)) + ((w1*math.pow(a,4))/(24*E*I))] + + bc12_coeff = [0, + (-1*b/(kA*G)) + ((math.pow(b,3))/(6*E*I)), + (b/(kA*G)) + ((-1*math.pow(b,3))/(6*E*I)), + 0, + math.pow(b,2)/(2*E*I), + -1*math.pow(b,2)/(2*E*I), + 0, + -1*b, + b, + 0, + -1, + 1] + + bc12_eq = [((-1*w1*math.pow(b,2))/(2*kA*G)) - ((s*math.pow((b-a),3))/(6*kA*G)) + ((w1*math.pow(b,4))/(24*E*I)) + ((s*math.pow((b-a),5))/(120*E*I))] + + + bceq = [bc1_coeff,bc2_coeff,bc3_coeff,bc4_coeff,bc5_coeff,bc6_coeff,bc7_coeff,bc8_coeff,bc9_coeff,bc10_coeff,bc11_coeff,bc12_coeff] + bcs = [bc1_eq,bc2_eq,bc3_eq,bc4_eq,bc5_eq,bc6_eq,bc7_eq,bc8_eq,bc9_eq,bc10_eq,bc11_eq,bc12_eq] + + bceq = np.array(bceq) + bcs = np.array(bcs) + + c = np.linalg.solve(bceq,bcs) + self.c = c + + ''' + Load Formulas: + 0 < x < a: + w = 0 + + a < x < b: + w = -1*w1 - s(x-a) + + b < x < L: + w = 0 + + Shear Formulas: + w = dV/dx, therefore V = integral w dx + + 0 < x < a: + V = c1 + + a < x < b: + V = -1*w1*x - (s(x-a)^2)/2 + c2 + + c < x < L: + V = c3 + ''' + + def vx(self,x): + + # redefine variables from self. to local to + # make formulas easier to read + w1 = self.w1 + a = self.a + s = self.s + c = self.c + b = self.b + L = self.L + + if 0 <= x <= a: + v = c[0][0] + elif a < x <= b: + v = (-1*w1*x) - ((s*math.pow((x-a),2))/2.0) + c[1][0] + elif b < x <= L: + v = c[2][0] + else: + v = 0 + + return v + + ''' + Moment Formulas: + V = dM/dx, therefore M = integral V dx + + 0 < x < a: + M = c1*x + c4 + + a < x < b: + M = (-1*w1*x^2)/2 - (s(x-a)^3)/6 + c2*x + c5 + + b < x < L: + M = c3*x + c6 + ''' + def mx(self,x): + # redefine variables from self. to local to + # make formulas easier to read + w1 = self.w1 + a = self.a + s = self.s + c = self.c + b = self.b + L = self.L + + if 0 <= x <= a: + m = c[0][0]*x + c[3][0] + elif a < x <= b: + m = (((-1*w1*math.pow(x,2))/2.0) - + ((s*math.pow((x-a),3))/6.0) + + c[1][0]*x + + c[4][0]) + elif b < x <= L: + m = c[2][0]*x + c[5][0] + else: + m = 0 + return m + + ''' + Timoshenko Relationship for Rotation, theta, and Deflection, delta + M = -E*I d theta/dx + V = kAG (-theta + d delta/dx) + + Rotation Formulas: + theta = integral M/-EI dx + + 0 < x < a: + theta = (-c1*x^2)/(2*EI) - c4*x/EI + c7 + + a < x < b: + theta = (w1*x^3)/(6*EI) + (s(x-a)^4)/(24*EI) - (c2*x^2)/2*EI - c5*x/EI + c8 + + b < x < L: + theta = (-c3*x^2)/(2*EI) - c6*x/EI + c9 + ''' + + def thetax(self,x): + + # redefine variables from self. to local to + # make formulas easier to read + w1 = self.w1 + a = self.a + s = self.s + c = self.c + b = self.b + L = self.L + E = self.E + I = self.I + + if 0 <= x <= a: + theta = (((-1*c[0][0]*math.pow(x,2))/(2.0*E*I)) - + ((c[3][0]*x)/(E*I)) + + c[6][0]) + elif a < x <= b: + theta = (((w1*math.pow(x,3))/(6.0*E*I)) + + ((s*math.pow((x-a),4))/(24.0*E*I)) - + ((c[1][0]*math.pow(x,2))/(2.0*E*I)) - + ((c[4][0]*x)/(E*I)) + + c[7][0]) + elif b < x <= L: + theta = (((-1*c[2][0]*math.pow(x,2))/(2.0*E*I)) - + ((c[5][0]*x)/(E*I)) + + c[8][0]) + else: + theta = 0 + + return theta + + ''' + Delta Formulas: + delta = integral V/kAG + theta dx + + 0 < x < a: + delta = c1*x/kAG + (-c1*x^3)/(6*EI) - c4*x^2/2*EI + c7*x + c10 + + a < x < b: + delta = -1*w1*x^2/2*kAG - (s(x-a)^3)/6*kAG + c2*x/kAG + (w1*x^4)/(24*EI) + (s(x-a)^5)/(120*EI) - (c2*x^3)/6*EI - c5*x^2/2*EI + c8*x + c11 + + b < x < L: + delta = c3*x/kAG + (-c3*x^3)/(6*EI) - c6*x^2/2*EI + c9*x + c12 + ''' + def deltax(self,x): + # redefine variables from self. to local to + # make formulas easier to read + w1 = self.w1 + a = self.a + s = self.s + c = self.c + b = self.b + L = self.L + E = self.E + I = self.I + G = self.G + kA = self.kA + + if 0 <= x <= a: + delta = (((c[0][0]*x)/(kA*G)) + + (-1*c[0][0]*math.pow(x,3))/(6.0*E*I)) + - ((c[3][0]*math.pow(x,2))/(2.0*E*I)) + + (c[6][0]*x) + + c[9][0]) + elif a < x <= b: + delta = (((-1*w1*math.pow(x,2))/(2.0*kA*G)) + - ((s*math.pow((x-a),3))/(6.0*kA*G)) + + ((c[1][0]*x)/(kA*G)) + + ((w1*math.pow(x,4))/(24.0*E*I)) + + ((s*math.pow((x-a),5))/(120.0*E*I)) + - ((c[1][0]*math.pow(x,3))/(6.0*E*I)) + - ((c[4][0]*math.pow(x,2))/(2.0*E*I)) + + (c[7][0]*x) + + c[10][0]) + elif b < x <= L: + delta = (((c[2][0]*x)/(kA*G)) + + ((-1*c[2][0]*math.pow(x,3))/(6.0*E*I)) + - ((c[5][0]*math.pow(x,2))/(2*E*I)) + + (c[8][0]*x) + + c[11][0]) + else: + delta = 0 + + return delta + + def fef(self): + L = self.L + E = self.E + I = self.I + G = self.G + kA = self.kA + + fem = fixedendmomentsTimoshenko(self.thetax(0), self.thetax(L), L, E, I, G, kA, [1,1]) + + ML = fem[0][0] + MR = fem[1][0] + + mo = timoforms.PointMoment(ML,0,L,E,I,G,kA) + ml = timoforms.PointMoment(MR,L,L,E,I,G,kA) + + RL = self.RL + mo.rl + ml.rl + RR = self.RR + mo.rr + ml.rr + + return [RL,ML,RR,MR] \ No newline at end of file diff --git a/Analysis/beam_patterning.py b/Analysis/beam_patterning.py index 1d1c9d2..cf17b79 100644 --- a/Analysis/beam_patterning.py +++ b/Analysis/beam_patterning.py @@ -1,4 +1,28 @@ -#!/usr/bin/env python +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import matplotlib @@ -1918,20 +1942,20 @@ def __init__(self, master): self.license_display() def license_display(self, *event): - license_string = ("This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n\n" - - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n\n" - - "You should have received a copy of the GNU General Public License along" - "with this program; if not, write to the Free Software Foundation, Inc.," - "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" - "\nA copy of the License can be viewed at:\n https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE") + license_string = ("Copyright (c) 2019, Donald N. Bockoven III\n" + "All rights reserved.\n\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" + " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" + " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" + " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" + " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" + " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" + " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," + " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" + "https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE" + ) tkMessageBox.showerror("License Information",license_string) self.master.focus_force() diff --git a/Analysis/eng_tips_maybe.py b/Analysis/eng_tips_maybe.py new file mode 100644 index 0000000..37dc2ba --- /dev/null +++ b/Analysis/eng_tips_maybe.py @@ -0,0 +1,224 @@ +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' + +from __future__ import division +import math +import matplotlib.pyplot as plt +import section_props as secprop + +def coord_trans(x,y, xo, yo, angle): + ''' + given an angle in degrees + and coordinate to translate about + return the transformed values of + the x and y lists + ''' + theta = math.radians(angle) + + x_t = [(i-xo)*math.cos(theta)+(j-yo)*math.sin(theta) for i,j in zip(x, y)] + y_t = [-1.0*(i-xo)*math.sin(theta)+(j-yo)*math.cos(theta) for i,j in zip(x, y)] + + x_t = [i+xo for i in x_t] + y_t = [j+yo for j in y_t] + + + return x_t, y_t + +# KootK +x1 = [0,60,60,120,120,60,60,0,0] +y1 = [0,0,60,60,120,120,180,180,0] + +x2 = [8,52,52,8,8] +y2 = [8,8,172,172,8] + +x3 = [60,112,112,60,60] +y3 = [68,68,112,112,68] + +shape1 = secprop.Section(x1,y1) +shape2 = secprop.Section(x2,y2, False, 1) +shape3 = secprop.Section(x3,y3, False, 1) + +# Bar coordinates and As's +xb = [4,17,30,43,56,56,56,56,56,69,82,95,108,116,116,116,116,103,90,77,64,56,56,56,56,43,30,17,4,4,4,4,4,4,4,4,4,4,4,4,4,4] +yb = [4,4,4,4,4,17,30,43,56,64,64,64,64,77,90,103,116,116,116,116,116,129,142,155,168,176,176,176,176,163,150,137,124,111,98,85,72,59,46,33,20,7] +ab = [0.31]*len(xb) + +# Es and Ec -- consistent units -- +Es = 29000000 #psi +Ec = math.pow(150,1.5)*33*math.sqrt(4500) #psi + +ncrack = Es/Ec +nplastic = 60000/4500.0 + +n = nplastic + +# Desired neutral axis rotation and elevation +# positive = clockwise +# set elevation = 0 to automate PNA elevation +na_angle = -45 +na_y = 0 + +# tranform the sections and the bars so the NA +# lies on the horiztonal about the centroid of major +# solid shape + +shape1.transformed_vertices(shape1.cx,shape1.cy,na_angle) +shape2.transformed_vertices(shape1.cx,shape1.cy,na_angle) +shape3.transformed_vertices(shape1.cx,shape1.cy,na_angle) + +xb_t, yb_t = coord_trans(xb,yb,shape1.cx,shape1.cy,na_angle) + +# translate everything to the +x,+y quadrant +xtrans = -1.0*min(shape1.x) +ytrans = -1.0*min(shape1.y) + +shape1.translate_vertices(xtrans,ytrans) +shape2.translate_vertices(xtrans,ytrans) +shape3.translate_vertices(xtrans,ytrans) + +#translate the bars +xb_t = [i+xtrans for i in xb_t] +yb_t = [j+ytrans for j in yb_t] + +as_yb_t = [[ast,j] for ast,j in zip(ab,yb_t)] + +# if na_y = 0 assumes you want the Icr for +# the plastic neutral axis + +if na_y == 0: + # using the bisection method step the NA + # down until Marea above = Marea below + + a=max(shape1.y) + b=min(shape1.y) + c=0 + mna=0 + + max_iter = 10000 + tol = 1e-12 + loop = 0 + + while loop < max_iter: + c = (a+b)/2.0 + + # conrete area above the cut line + cut1 = secprop.split_shape_above_horizontal_line(shape1, c) + asolid = [] + dysolid = [] + for sol_shape in cut1: + asolid.append(sol_shape.area) + dysolid.append(sol_shape.cy - c) + + msolid = sum([ac*d for ac,d in zip(asolid,dysolid)]) + + # void area above the cut line + avoid = [] + dyvoid = [] + cut2 = secprop.split_shape_above_horizontal_line(shape2, c, False, 1) + cut3 = secprop.split_shape_above_horizontal_line(shape3, c, False, 1) + for void1_shape in cut2: + avoid.append(void1_shape.area) + dyvoid.append(void1_shape.cy - c) + for void2_shape in cut3: + avoid.append(void2_shape.area) + dyvoid.append(void2_shape.cy - c) + + mvoid = sum([av*d for av,d in zip(avoid,dyvoid)]) + + mconc = msolid + mvoid + + ms_above = sum([(n-1)*i[0]*abs((i[1]-c)) for i in as_yb_t if i[1]>c]) + ms_below = sum([n*i[0]*abs((i[1]-c)) for i in as_yb_t if i[1]=na_y]) +Ibars_below = sum([n*i[0]*math.pow(i[1]-na_y,2) for i in as_yb_t if i[1]{1}'.format(c,i) + elif c < 0: + line = line + ' - {0:0.4f}*x{1}'.format(abs(c),i) + else: + line = line + ' + {0:0.4f}*x{1}'.format(c,i) + i+=1 + + output = output + '\n{0:0.4f} < x <= {1:0.4f}:\n\n\n{2}\n\n'.format(func[1][0],func[1][1],line) + output = output + '\n' + return output + +def poly_eval(c_list,x): + + i = 0 + res=0 + if all(c == 0 for c in c_list): + pass + else: + for c in c_list: + res = res + c*math.pow(x,i) + i+=1 + + return res + class no_load: - def __init__(self): + def __init__(self, L, case='D'): self.p = 0 self.rl = 0 self.rr = 0 - + self.L = L + self.case =case + self.kind = 'NL' - - def v(self,x): + + self.x_graph = [0] + self.y_graph = [0] + + def chart_load(self,x_scale=0, y_scale=0, arrows=0): + x = [0] + y = [0] + return x,y + + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + v = [[[0],[0,self.L]]] + m = [[[0],[0,self.L]]] + eis = [[[0],[0,self.L]]] + eid = [[[0],[0,self.L]]] + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + + def fef(self,loadfactor=1): + # Fixed End Forces + RL = 0*loadfactor + RR = 0*loadfactor + ML = 0*loadfactor + MR = 0*loadfactor + + return [RL,ML,RR,MR] + + def v(self,x,loadfactor=1): iters = len(x) v=zeros(iters) return v - def m(self,x): + def m(self,x,loadfactor=1): iters = len(x) m=zeros(iters) return m - def eis(self,x): + def eis(self,x,loadfactor=1): iters = len(x) eis=zeros(iters) return eis - def eid(self,x): + def eid(self,x,loadfactor=1): iters = len(x) eid=zeros(iters) return eid - def vx(self,x): + def vx(self,x,loadfactor=1): v = 0 return v - def mx(self,x): + def mx(self,x,loadfactor=1): m = 0 return m - def eisx(self,x): + def eisx(self,x,loadfactor=1): eisx = 0 return eisx - def eidx(self,x): + def eidx(self,x,loadfactor=1): eid = 0 return eid @@ -69,11 +232,11 @@ def __init__(self, p, a, L): self.a = float(a) self.L = float(L) self.b = self.L - self.a - + self.kind = 'Point' - + self.error = '' - + if self.a > self.L: self.error = 'Error a > l' self.error = 'Error a > l' @@ -86,12 +249,71 @@ def __init__(self, p, a, L): arrow_height = self.p/6.0 #30 degree arrow - arrow_plus= self.a+(arrow_height*math.tan(math.radians(30))) - arrow_minus= self.a-(arrow_height*math.tan(math.radians(30))) + arrow_plus= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus= self.a-(arrow_height*math.tan(math.radians(15))) self.x_graph=[arrow_minus,self.a,arrow_plus,self.a,self.a] self.y_graph=[arrow_height,0,arrow_height,0,self.p] + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + if arrows == 1: + arrow_height = (self.p/6.0) + #30 degree arrow + arrow_plus= (self.a+(arrow_height*math.tan(math.radians(15)))) + arrow_minus= (self.a-(arrow_height*math.tan(math.radians(15)))) + + x=[arrow_minus,self.a,arrow_plus,self.a,self.a] + x = [i*x_scale for i in x] + y=[arrow_height,0,arrow_height,0,self.p] + y = [j*y_scale for j in y] + else: + x = [self.a*x_scale, self.a*x_scale] + y = [0,self.p*y_scale] + + return x,y + + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + if self.a == 0 or self.a == self.L: + v = [[[0],[0,self.L]]] + m = [[[0],[0,self.L]]] + eis = [[[0],[0,self.L]]] + eid = [[[0],[0,self.L]]] + else: + v = [[[self.rl],[0,self.a]],[[-1*self.rr],[self.a,self.L]]] + + m = [[[0,self.rl],[0,self.a]],[[(self.rr * self.L),(-1 * self.rr)],[self.a,self.L]]] + + eis = [[[self.c1,0,self.rl/2.0],[0,self.a]],[[self.c2,(self.rr * self.L),-1.0*self.rr/2.0],[self.a,self.L]]] + + eid = [[[0,self.c1,0,self.rl/6.0],[0,self.a]],[[self.c4, self.c2, self.rr*self.L*0.5,-1*self.rr/6.0],[self.a,self.L]]] + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + + def fef(self): + # Fixed End Forces + RL = ((self.p*self.b*self.b) / (self.L*self.L*self.L))*((3*self.a)+self.b) + RR = ((self.p*self.a*self.a) / (self.L*self.L*self.L))*(self.a+(3*self.b)) + ML = -1*(self.p*self.a*self.b*self.b) / (self.L*self.L) + MR = (self.p*self.a*self.a*self.b) / (self.L*self.L) + + return [RL,ML,RR,MR] + def v(self,x): iters = len(x) v=zeros(iters) @@ -179,14 +401,14 @@ def __init__(self, ma, a, L): self.ma = float(ma) self.a = float(a) self.L = float(L) - + self.kind = 'Moment' - + self.error = '' - + if a > self.L: self.error = 'Error a > L' - + self.rr = self.ma/self.L self.rl = -1.0*self.rr @@ -195,10 +417,10 @@ def __init__(self, ma, a, L): self.c3 = 0 self.c4 = ((-1.0*self.rl*self.L**3)/6.0) - (0.5*self.ma*self.L**2) - (self.c2*self.L) - r = (self.ma/8.0) + r = (self.ma/2.0) arrow_height = r/6.0 #30 degree arrow - arrow_minus= (arrow_height*math.tan(math.radians(30))) + arrow_minus= (arrow_height*math.tan(math.radians(15))) if self.ma <0: self.x_graph = [self.a,self.a,self.a] @@ -228,6 +450,110 @@ def __init__(self, ma, a, L): self.x_graph.append(x) self.y_graph.append(y) + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + x=[] + y=[] + r = (self.ma/2.0) + + if arrows == 1: + arrow_height = r/6.0 + #30 degree arrow + arrow_minus= (arrow_height*math.tan(math.radians(15))) + + if self.ma <0: + x = [self.a,self.a,self.a] + y = [r,0,-r] + xi=0 + yi=0 + for a in range(-90, 181): + xi = (self.a)+((r*math.cos(math.radians(a)))) + yi = 0+((r*math.sin(math.radians(a)))) + x.append(xi) + y.append(yi) + + x.append(xi-arrow_minus) + y.append(yi+arrow_height) + x.append(xi) + y.append(yi) + x.append(xi+arrow_minus) + y.append(yi+arrow_height) + else: + x = [self.a-r,self.a,self.a+r, self.a+r-arrow_minus,self.a+r,self.a+r+arrow_minus,self.a+r] + y = [0,0,0,arrow_height,0,arrow_height,0] + + xi=0 + yi=0 + for a in range(0,271): + xi = self.a+(r*math.cos(math.radians(a))) + yi = 0+(r*math.sin(math.radians(a))) + x.append(xi) + y.append(yi) + else: + if self.ma <0: + x = [self.a,self.a,self.a] + y = [r,0,-r] + xi=0 + yi=0 + for a in range(-90, 181): + xi = self.a+(r*math.cos(math.radians(a))) + yi = 0+(r*math.sin(math.radians(a))) + x.append(xi) + y.append(yi) + else: + x = [self.a-r,self.a,self.a+r] + y = [0,r,0] + xi=0 + yi=0 + for a in range(0,271): + xi = self.a+(r*math.cos(math.radians(a))) + yi = 0+(r*math.sin(math.radians(a))) + x.append(xi) + y.append(yi) + + x = [i*x_scale for i in x] + y = [j*y_scale for j in y] + return x,y + + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + v = [[[self.rl],[0,self.L]]] + + if self.a == 0: + m = [[[self.ma,self.rl],[0,self.L]]] + elif self.a == self.L: + m = [[[0,self.rl],[0,self.L]]] + else: + m = [[[0,self.rl],[0,self.a]],[[self.ma,self.rl],[self.a,self.L]]] + + eis = [[[self.c1,0,0.5*self.rl],[0,self.a]],[[self.c2,self.ma,0.5*self.rl],[self.a,self.L]]] + + eid = [[[self.c3, self.c1,0,((1/6.0)*self.rl)],[0,self.a]],[[self.c4,self.c2,0.5*self.ma,(1/6.0)*self.rl],[self.a,self.L]]] + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + + def fef(self): + # Fixed End Forces + RL = ((-6.0*self.ma*self.a) / (self.L*self.L*self.L)) * (self.L-self.a) + RR = -1.0*RL + ML = ((-1.0*self.ma) / (self.L*self.L))*((self.L*self.L)-(4*self.L*self.a)+(3*self.a*self.a)) + MR = -1.0*(self.ma / (self.L*self.L))*((3*self.a*self.a)-(2*self.a*self.L)) + + return [RL,ML,RR,MR] def v(self,x): iters = len(x) @@ -319,11 +645,11 @@ def __init__(self, w1, a, b, L): self.L = float(L) self.b = float(b) self.c = b-a - + self.kind = 'UDL' - + self.error = '' - + if self.a > self.b: self.error = 'Error a > b' self.error = 'Error a > b' @@ -335,7 +661,7 @@ def __init__(self, w1, a, b, L): self.error = 'Error b > l' else: pass - + self.rl = (self.w1 * self.c) - (((self.w1 * self.c) * (self.a + (self.c / 2))) / self.L) self.rr = (((self.w1 * self.c) * (self.a + (self.c / 2))) / self.L) self.c1 = 0 @@ -350,14 +676,63 @@ def __init__(self, w1, a, b, L): arrow_height = self.w1/12.0 #30 degree arrow - arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(30))) - arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(30))) - arrow_plus_end= self.b+(arrow_height*math.tan(math.radians(30))) - arrow_minus_end= self.b-(arrow_height*math.tan(math.radians(30))) + arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(15))) + arrow_plus_end= self.b+(arrow_height*math.tan(math.radians(15))) + arrow_minus_end= self.b-(arrow_height*math.tan(math.radians(15))) self.x_graph=[arrow_minus_start,self.a,arrow_plus_start,self.a,self.a,self.b,self.b,arrow_minus_end,self.b,arrow_plus_end] self.y_graph=[arrow_height,0,arrow_height,0,self.w1,self.w1,0,arrow_height,0,arrow_height] + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + x=[] + y=[] + if arrows == 1: + arrow_height = self.w1/6.0 + #30 degree arrow + arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(15))) + arrow_plus_end= self.b+(arrow_height*math.tan(math.radians(15))) + arrow_minus_end= self.b-(arrow_height*math.tan(math.radians(15))) + + x=[arrow_minus_start,self.a,arrow_plus_start,self.a,self.a,self.b,self.b,arrow_minus_end,self.b,arrow_plus_end] + x = [i*x_scale for i in x] + y=[arrow_height,0,arrow_height,0,self.w1,self.w1,0,arrow_height,0,arrow_height] + y = [j*y_scale for j in y] + else: + x=[self.a,self.a,self.b,self.b] + x = [i*x_scale for i in x] + y=[0,self.w1,self.w1,0] + y = [j*y_scale for j in y] + + return x,y + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + v = [[[self.rl],[0,self.a]],[[(self.rl+self.w1*self.a),-1.0*self.w1],[self.a,self.b]],[[-1*self.rr],[self.b,self.L]]] + + m = [[[self.c1,self.rl],[0,self.a]],[[self.c2,self.rl+(self.w1*self.a),-0.5*self.w1],[self.a,self.b]],[[self.c3,-1.0*self.rr],[self.b,self.L]]] + + eis = [[[self.c4,self.c1,0.5*self.rl],[0,self.a]],[[self.c5,self.c2,0.5*(self.rl+(self.w1*self.a)),(-1/6.0)*self.w1],[self.a,self.b]],[[self.c6,self.c3,-0.5*self.rr],[self.b,self.L]]] + + eid = [[[self.c7,self.c4,0.5*self.c1,1/6.0*self.rl],[0,self.a]],[[self.c8, self.c5, 0.5*self.c2,(1/6.0)*(self.rl+(self.w1*self.a)),-1.0*(self.w1 / 24.0)],[self.a,self.b]],[[self.c9,self.c6,0.5*self.c3,((-1.0 * self.rr) / 6.0)],[self.b,self.L]]] + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + def v(self,x): iters = len(x) v=zeros(iters) @@ -450,6 +825,26 @@ def eidx(self,x): eid = ((-1 * self.rr * x ** 3) / 6) + ((self.c3 * x ** 2) / 2) + (self.c6 * x) + self.c9 return eid + def fef(self): + eis0 = self.eisx(0) + eisL = self.eisx(self.L) + + s = np.array([[-1.0*eis0],[-1.0*eisL]]) + + ems = np.array([[-1.0*self.L/3.0 , self.L/6.0],[self.L/6.0 , -1.0*self.L/3.0]]) + + fem = np.linalg.solve(ems,s) + + mo = point_moment(fem[0][0],0,self.L) + ml = point_moment(fem[1][0],self.L,self.L) + + RL = self.rl+mo.rl+ml.rl + RR = self.rr+mo.rr+ml.rr + ML = fem[0][0] + MR = fem[1][0] + + return [RL,ML,RR,MR] + class trap: def __init__(self, w1, w2, a, b, L): @@ -459,12 +854,12 @@ def __init__(self, w1, w2, a, b, L): self.L = float(L) self.b = float(b) self.c = self.b-self.a - + self.kind = 'TRAP' - - + + self.error = '' - + if self.a > self.b: self.error = 'Error a > b' self.error = 'Error a > b' @@ -479,7 +874,7 @@ def __init__(self, w1, w2, a, b, L): self.error = 'Error w1 and w2 change direction' else: pass - + self.s = (self.w2 -self.w1)/self.c self.xbar = (self.c * ((2 * self.w2) + self.w1)) / (3 * (self.w2 + self.w1)) self.W = self.c * ((self.w1 + self.w2) / 2) @@ -498,14 +893,66 @@ def __init__(self, w1, w2, a, b, L): arrow_height = self.w1/6.0 arrow_height2 = self.w2/6.0 #30 degree arrow - arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(30))) - arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(30))) - arrow_plus_end= self.b+(arrow_height2*math.tan(math.radians(30))) - arrow_minus_end= self.b-(arrow_height2*math.tan(math.radians(30))) + arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(15))) + arrow_plus_end= self.b+(arrow_height2*math.tan(math.radians(15))) + arrow_minus_end= self.b-(arrow_height2*math.tan(math.radians(15))) self.x_graph=[arrow_minus_start,self.a,arrow_plus_start,self.a,self.a,self.b,self.b,arrow_minus_end,self.b,arrow_plus_end] self.y_graph=[arrow_height,0,arrow_height,0,self.w1,self.w2,0,arrow_height2,0,arrow_height2] + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + x=[] + y=[] + if arrows == 1: + arrow_height = self.w1/6.0 + arrow_height2 = self.w2/6.0 + #30 degree arrow + arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(15))) + arrow_plus_end= self.b+(arrow_height2*math.tan(math.radians(15))) + arrow_minus_end= self.b-(arrow_height2*math.tan(math.radians(15))) + + x=[arrow_minus_start,self.a,arrow_plus_start,self.a,self.a,self.b,self.b,arrow_minus_end,self.b,arrow_plus_end] + x = [i*x_scale for i in x] + y=[arrow_height,0,arrow_height,0,self.w1,self.w2,0,arrow_height2,0,arrow_height2] + y = [j*y_scale for j in y] + + else: + x=[self.a,self.a,self.b,self.b] + x = [i*x_scale for i in x] + y=[0,self.w1,self.w2,0] + y = [j*y_scale for j in y] + + return x,y + + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + v = [[[self.rl],[0,self.a]],[[self.rl- ((((self.s * self.a) - (2 * self.w1)) * self.a) / 2),-1.0*((self.w1 - (self.s * self.a))),-1.0*(self.s/ 2)],[self.a,self.b]],[[-1.0*self.rr],[self.b,self.L]]] + + m = [[[self.c1,self.rl],[0,self.a]],[[self.c2,self.rl - ((((self.s * self.a) - (2 * self.w1)) * self.a) / 2.0),-1.0*((self.w1 - (self.s * self.a)) / 2.0),-1.0*((self.s) / 6.0)],[self.a,self.b]],[[self.c3,-1.0*self.rr],[self.b,self.L]]] + + eis = [[[self.c4,self.c1,(self.rl / 2.0)],[0,self.a]],[[self.c5,self.c2,(self.rl/ 2.0) - ((((self.s * self.a) - (2 * self.w1)) * self.a) / 4.0), -1.0*((self.w1 - (self.s * self.a)) / 6.0),-1.0*(self.s / 24.0)],[self.a,self.b]],[[self.c6,self.c3,((-1.0* self.rr) / 2)],[self.b,self.L]]] + + eid = [[[self.c7,self.c4,(self.c1 / 2.0),(self.rl/ 6.0)],[0,self.a]],[[self.c8,self.c5,self.c2 / 2.0,(self.rl / 6.0) - ((((self.s * self.a) - (2 * self.w1)) * self.a) / 12.0), -1.0*((self.w1 - (self.s * self.a)) / 24),-1.0*(self.s / 120.0)],[self.a,self.b]],[[self.c9,self.c6,(self.c3 / 2.0),((-1.0 * self.rr) / 6.0)],[self.b,self.L]]] + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + def v(self,x): iters = len(x) v=zeros(iters) @@ -598,15 +1045,192 @@ def eidx(self,x): eid = ((-1 * self.rr * x ** 3) / 6) + ((self.c3 * x ** 2) / 2) + (self.c6 * x) + self.c9 return eid + def fef(self): + eis0 = self.eisx(0) + eisL = self.eisx(self.L) + + s = np.array([[-1.0*eis0],[-1.0*eisL]]) + + ems = np.array([[-1.0*self.L/3.0 , self.L/6.0],[self.L/6.0 , -1.0*self.L/3.0]]) + + fem = np.linalg.solve(ems,s) + + mo = point_moment(fem[0][0],0,self.L) + ml = point_moment(fem[1][0],self.L,self.L) + + RL = self.rl+mo.rl+ml.rl + RR = self.rr+mo.rr+ml.rr + ML = fem[0][0] + MR = fem[1][0] + + return [RL,ML,RR,MR] + +class end_delta: + def __init__(self, delta_i, delta_j, L): + ''' + Important note it is assumed that delta_i and delta_j + have been divided by E and I. If this is being used + in combination with other loads make sure consistent + units are being used + ''' + + self.rl = 0 + self.rr = 0 + self.deltai = delta_i + self.deltaj = delta_j + self.L = L + + self.slope = (delta_j - delta_i)/self.L + + self.kind = 'END_DELTA' + + self.x_graph = [0] + self.y_graph = [0] + + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + x=[0] + y=[0] + + return x,y + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + v = [[[0],[0,self.L]]] + m = [[[0],[0,self.L]]] + eis = [[[self.slope],[0,self.L]]] + eid = [[[self.deltai,self.slope],[0,self.L]]] + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + + def v(self,x): + iters = len(x) + v=zeros(iters) + return v + + def m(self,x): + iters = len(x) + m=zeros(iters) + return m + + def eis(self,x): + iters = len(x) + eis=zeros(iters) + for i in range(0,iters): + eis[i] = self.slope + return eis + + def eid(self,x): + iters = len(x) + eid=zeros(iters) + for i in range(0,iters): + eid[i] = self.slope*x[i] + self.deltai + return eid + + def vx(self,x): + v = 0 + return v + + def mx(self,x): + m = 0 + return m + + def eisx(self,x): + eisx = self.slope + return eisx + + def eidx(self,x): + eid = self.slope*x + self.deltai + return eid + + def fef(self): + eis0 = self.eisx(0) + eisL = self.eisx(self.L) + + s = np.array([[-1.0*eis0],[-1.0*eisL]]) + + ems = np.array([[-1.0*self.L/3.0 , self.L/6.0],[self.L/6.0 , -1.0*self.L/3.0]]) + + fem = np.linalg.solve(ems,s) + + mo = point_moment(fem[0][0],0,self.L) + ml = point_moment(fem[1][0],self.L,self.L) + + RL = self.rl+mo.rl+ml.rl + RR = self.rr+mo.rr+ml.rr + ML = fem[0][0] + MR = fem[1][0] + + return [RL,ML,RR,MR] + class cant_right_nl: - def __init__(self, slope): + def __init__(self, slope,L): self.slope = slope - + self.L = L self.rl = 0 + self.rr = 0 self.ml = 0 - + self.kind = 'NL' + self.x_graph = [0] + self.y_graph = [0] + + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + x=[0] + y=[0] + + return x,y + + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + v = [[[0],[0,self.L]]] + + m = [[[0],[0,self.L]]] + + eis = [[[self.slope],[0,self.L]]] + + eid = [[[0, self.slope],[0,self.L]]] + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + + def fef(self): + # Fixed End Forces + RL = 0 + RR = 0 + ML = 0 + MR = 0 + + return [RL,ML,RR,MR] + def v(self,x): iters = len(x) v=zeros(iters) @@ -663,21 +1287,22 @@ def __init__(self, p, a, L, Lb): self.L = float(L) self.Lb = float(Lb) self.b = self.L - self.a - + self.kind = 'Point' - + self.error = '' - + if self.a > self.L: self.error = 'Error a > l' self.error = 'Error a > l' self.rl = self.p + self.rr = 0 self.ml = -1.0*self.p*self.a # 0 length backspan indicates fixed-free beam initialize slope to 0 if Lb == 0: - self.backspan = no_load() + self.backspan = no_load(0) self.c1 = 0 else: self.backspan = point_moment(-1.0*self.ml,self.Lb,self.Lb) @@ -689,12 +1314,74 @@ def __init__(self, p, a, L, Lb): arrow_height = self.p/6.0 #30 degree arrow - arrow_plus= self.a+(arrow_height*math.tan(math.radians(30))) - arrow_minus= self.a-(arrow_height*math.tan(math.radians(30))) + arrow_plus= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus= self.a-(arrow_height*math.tan(math.radians(15))) self.x_graph=[arrow_minus,self.a,arrow_plus,self.a,self.a] self.y_graph=[arrow_height,0,arrow_height,0,self.p] + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + + if arrows == 1: + arrow_height = self.p/6.0 + #30 degree arrow + arrow_plus= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus= self.a-(arrow_height*math.tan(math.radians(15))) + + x=[arrow_minus,self.a,arrow_plus,self.a,self.a] + x = [i*x_scale for i in x] + y=[arrow_height,0,arrow_height,0,self.p] + y = [j*y_scale for j in y] + else: + x=[self.a,self.a] + x = [i*x_scale for i in x] + y=[0,self.p] + y = [j*y_scale for j in y] + + return x,y + + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + if self.a == 0: + v = [[[0],[0,self.L]]] + m = [[[0],[0,self.L]]] + eis = [[[0],[0,self.L]]] + eid = [[[0],[0,self.L]]] + else: + v = [[[self.p],[0,self.a]],[[0],[self.a,self.L]]] + + m = [[[self.ml,self.rl],[0,self.a]],[[0],[self.a,self.L]]] + + eis = [[[self.c1,self.ml,0.5*self.rl],[0,self.a]],[[self.c3],[self.a,self.L]]] + + eid = [[[self.c2,self.c1,0.5*self.ml,(1.0/6.0)*self.rl],[0,self.a]],[[self.c4, self.c3],[self.a,self.L]]] + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + + def fef(self): + # Fixed End Forces + RL = self.rl + RR = 0 + ML = self.ml + MR = 0 + + return [RL,ML,RR,MR] + def v(self,x): iters = len(x) v=zeros(iters) @@ -781,21 +1468,22 @@ def __init__(self, ma, a, L, Lb): self.L = float(L) self.Lb = float(Lb) self.b = self.L - self.a - + self.kind = 'Moment' self.error = '' - + if self.a > self.L: self.error = 'Error a > l' self.error = 'Error a > l' self.rl = 0 + self.rr = 0 self.ml = -1.0*self.ma # 0 length backspan indicates fixed-free beam initialize slope to 0 if Lb == 0: - self.backspan = no_load() + self.backspan = no_load(0) self.c1 = 0 else: self.backspan = point_moment(-1.0*self.ml,self.Lb,self.Lb) @@ -805,10 +1493,10 @@ def __init__(self, ma, a, L, Lb): self.c3 = self.ml*self.a + self.c1 self.c4 = 0.5*self.ml*self.a**2 + self.c1 * self.a + self.c2 - self.c3 * self.a - r = (self.ma/8.0) + r = (self.ma/2.0) arrow_height = r/6.0 #30 degree arrow - arrow_minus= (arrow_height*math.tan(math.radians(30))) + arrow_minus= (arrow_height*math.tan(math.radians(15))) if self.ma <0: self.x_graph = [self.a,self.a,self.a] @@ -838,6 +1526,83 @@ def __init__(self, ma, a, L, Lb): self.x_graph.append(x) self.y_graph.append(y) + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + r = (self.ma/2.0) + + if arrows == 1: + arrow_height = r/6.0 + #30 degree arrow + arrow_minus= (arrow_height*math.tan(math.radians(15))) + + if self.ma <0: + x= [self.a,self.a,self.a] + y = [r,0,-r] + xi=0 + yi=0 + for a in range(-90, 181): + xi = self.a+(r*math.cos(math.radians(a))) + yi = 0+(r*math.sin(math.radians(a))) + x.append(xi) + y.append(yi) + + x.append(xi-arrow_minus) + y.append(yi+arrow_height) + x.append(xi) + y.append(yi) + x.append(xi+arrow_minus) + y.append(yi+arrow_height) + else: + x= [self.a-r,self.a,self.a+r, self.a+r-arrow_minus,self.a+r,self.a+r+arrow_minus,self.a+r] + y = [0,0,0,arrow_height,0,arrow_height,0] + xi=0 + yi=0 + for a in range(0,271): + xi = self.a+(r*math.cos(math.radians(a))) + yi = 0+(r*math.sin(math.radians(a))) + x.append(xi) + y.append(yi) + + x = [i*x_scale for i in x] + y = [j*y_scale for j in y] + + return x,y + + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + v = [[[0],[0,self.L]]] + + m = [[[self.ml],[0,self.a]],[[0],[self.a,self.L]]] + + eis = [[[self.c1,self.ml],[0,self.a]],[[self.c3],[self.a,self.L]]] + + eid = [[[self.c2, self.c1,0.5*self.ml],[0,self.a]],[[self.c4,self.c3],[self.a,self.L]]] + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + + def fef(self): + # Fixed End Forces + RL = self.rl + RR = 0 + ML = self.ml + MR = 0 + + return [RL,ML,RR,MR] + def v(self,x): iters = len(x) v=zeros(iters) @@ -920,11 +1685,11 @@ def __init__(self, w1, a, b, L, Lb): self.c = self.b - self.a self.w_tot = self.w1*self.c self.Lb = float(Lb) - + self.kind = 'UDL' - + self.error = '' - + if self.a > self.b: self.error = 'Error a > b' self.error = 'Error a > b' @@ -936,36 +1701,118 @@ def __init__(self, w1, a, b, L, Lb): self.error = 'Error b > l' else: pass - + self.rl = self.w_tot + self.rr = 0 self.ml = -1.0*self.w_tot*(self.b-(self.c/2)) # 0 length backspan indicates fixed-free beam initialize slope to 0 if Lb == 0: - self.backspan = no_load() + self.backspan = no_load(0) self.c1 = 0 else: self.backspan = point_moment(-1.0*self.ml,self.Lb,self.Lb) self.c1 = self.backspan.eisx(self.Lb) self.c2 = 0 - self.c3 = self.c1 self.c4 = self.c1*self.a + self.c2 - self.c3*a - self.c5 = 0.5*self.w_tot*self.b**2 + self.ml*self.b - (1.0/6.0)*self.w1*(self.b-self.a)**3 + self.c3 self.c6 = (1.0/6.0)*self.w_tot*self.b**3 + 0.5*self.ml*self.b**2 - (1.0/24.0)*self.w1*(self.b-self.a)**4 + self.c3*self.b + self.c4 - self.c5*self.b arrow_height = self.w1/12.0 #30 degree arrow - arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(30))) - arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(30))) - arrow_plus_end= self.b+(arrow_height*math.tan(math.radians(30))) - arrow_minus_end= self.b-(arrow_height*math.tan(math.radians(30))) + arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(15))) + arrow_plus_end= self.b+(arrow_height*math.tan(math.radians(15))) + arrow_minus_end= self.b-(arrow_height*math.tan(math.radians(15))) self.x_graph=[arrow_minus_start,self.a,arrow_plus_start,self.a,self.a,self.b,self.b,arrow_minus_end,self.b,arrow_plus_end] self.y_graph=[arrow_height,0,arrow_height,0,self.w1,self.w1,0,arrow_height,0,arrow_height] + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + if arrows == 1: + arrow_height = self.w1/12.0 + #30 degree arrow + arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(15))) + arrow_plus_end= self.b+(arrow_height*math.tan(math.radians(15))) + arrow_minus_end= self.b-(arrow_height*math.tan(math.radians(15))) + + x=[arrow_minus_start,self.a,arrow_plus_start,self.a,self.a,self.b,self.b,arrow_minus_end,self.b,arrow_plus_end] + x = [i*x_scale for i in x] + y=[arrow_height,0,arrow_height,0,self.w1,self.w1,0,arrow_height,0,arrow_height] + y = [j*y_scale for j in y] + else: + x=[self.a,self.a,self.b,self.b] + x = [i*x_scale for i in x] + y=[0,self.w1,self.w1,0] + y = [j*y_scale for j in y] + + return x,y + + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + v = ([ + [[self.rl],[0,self.a]], + [[self.rl+(self.w1*self.a),-self.w1],[self.a,self.b]], + [[0],[self.b,self.L]] + ]) + + m = ([ + [[self.ml, self.rl],[0,self.a]], + [[self.ml-(0.5*self.a*self.a*self.w1),self.rl+(self.a*self.w1),-0.5*self.w1],[self.a,self.b]], + [[0],[self.b,self.L]] + ]) + + eis = ([ + [[self.c1,self.ml,0.5*self.rl],[0,self.a]], + [[self.c3+((1.0/6.0)*self.a*self.a*self.a*self.w1), + self.ml-(0.5*self.a*self.a*self.w1), + (0.5*self.rl)+(0.5*self.a*self.w1), + ((-1.0/6.0)*self.w1)],[self.a,self.b]], + [[self.c5],[self.b,self.L]] + ]) + + eid = ([ + # Range 0 to a + [[self.c2,self.c1,0.5*self.ml,(1.0/6.0)*self.rl],[0,self.a]], + # Range a to b + [[self.c4-((1.0/24.0)*math.pow(self.a,4)*self.w1), #x^0 + ((1.0/6.0)*math.pow(self.a,3)*self.w1)+self.c3, #x^1 + ((-0.25)*math.pow(self.a,2)*self.w1)+ (0.5*self.ml), #x^2 + ((1.0/6.0)*self.a*self.w1)+ ((1.0/6.0)*self.rl), #x^3 + ((-1.0/24.0)*self.w1)],[self.a,self.b]], #x^4 + # Range b to L + [[self.c6,self.c5],[self.b,self.L]] + ]) + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + + def fef(self): + # Fixed End Forces + RL = self.rl + RR = 0 + ML = self.ml + MR = 0 + + return [RL,ML,RR,MR] + def v(self,x): iters = len(x) v=zeros(iters) @@ -1011,9 +1858,16 @@ def eid(self,x): for i in range(0,iters): if x[i] <= self.a: - eid[i] = (1.0/6.0)*self.rl*x[i]**2 + 0.5*self.ml*x[i]**2 + self.c1 * x[i] + self.c2 + eid[i] = ((1.0/6.0)*self.rl*x[i]*x[i]*x[i]+ + 0.5*self.ml*x[i]*x[i] + + self.c1 * x[i] + + self.c2) elif x[i] <= self.b: - eid[i] = (1.0/6.0)*self.rl*x[i]**3 + 0.5*self.ml*x[i]**2 - (1.0/24.0)*self.w1*(x[i]-self.a)**4 + self.c3*x[i] + self.c4 + eid[i] = ((1.0/6.0)*self.rl*x[i]*x[i]*x[i] + + 0.5*self.ml*x[i]*x[i] - + ((1.0/24.0)*self.w1*(x[i]-self.a)**4) + + self.c3*x[i] + + self.c4) else: eid[i] = self.c5*x[i] + self.c6 return eid @@ -1066,11 +1920,11 @@ def __init__(self, w1, w2, a, b, L, Lb): self.b = float(b) self.Lb = float(Lb) self.c = self.b-self.a - + self.kind = 'TRAP' self.error = '' - + if self.a > self.b: self.error = 'Error a > b' self.error = 'Error a > b' @@ -1085,16 +1939,17 @@ def __init__(self, w1, w2, a, b, L, Lb): self.error = 'Error w1 and w2 change direction' else: pass - + self.w = 0.5*(self.w1+self.w2)*self.c self.d = self.a+(((self.w1+(2*self.w2))/(3*(self.w2+self.w1)))*self.c) self.s = (self.w1-self.w2)/self.c self.rl = self.w + self.rr = 0 self.ml = -1*self.w*self.d # 0 length backspan indicates fixed-free beam initialize slope to 0 if Lb == 0: - self.backspan = no_load() + self.backspan = no_load(0) self.c1 = 0 else: self.backspan = point_moment(-1.0*self.ml,self.Lb,self.Lb) @@ -1113,14 +1968,124 @@ def __init__(self, w1, w2, a, b, L, Lb): arrow_height = self.w1/6.0 arrow_height2 = self.w2/6.0 #30 degree arrow - arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(30))) - arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(30))) - arrow_plus_end= self.b+(arrow_height2*math.tan(math.radians(30))) - arrow_minus_end= self.b-(arrow_height2*math.tan(math.radians(30))) + arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(15))) + arrow_plus_end= self.b+(arrow_height2*math.tan(math.radians(15))) + arrow_minus_end= self.b-(arrow_height2*math.tan(math.radians(15))) self.x_graph=[arrow_minus_start,self.a,arrow_plus_start,self.a,self.a,self.b,self.b,arrow_minus_end,self.b,arrow_plus_end] self.y_graph=[arrow_height,0,arrow_height,0,self.w1,self.w2,0,arrow_height2,0,arrow_height2] + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + if arrows == 1: + arrow_height = self.w1/6.0 + arrow_height2 = self.w2/6.0 + #30 degree arrow + arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(15))) + arrow_plus_end= self.b+(arrow_height2*math.tan(math.radians(15))) + arrow_minus_end= self.b-(arrow_height2*math.tan(math.radians(15))) + + x=[arrow_minus_start,self.a,arrow_plus_start,self.a,self.a,self.b,self.b,arrow_minus_end,self.b,arrow_plus_end] + x = [i*x_scale for i in x] + y=[arrow_height,0,arrow_height,0,self.w1,self.w2,0,arrow_height2,0,arrow_height2] + y = [j*y_scale for j in y] + else: + x=[self.a,self.a,self.b,self.b] + x = [i*x_scale for i in x] + y=[0,self.w1,self.w2,0] + y = [j*y_scale for j in y] + + return x,y + + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + v = ([ + # Range 0 to a + [[self.rl],[0,self.a]], + # Range a to b + [[(0.5*math.pow(self.a,2)*self.s) + (self.a*self.w1) + self.rl, #x^0 + (-1.0*self.w1) - (self.a*self.s), #x^1 + 0.5*self.s], #x^2 + [self.a,self.b]], + # Range b to L + [[0],[self.b,self.L]] + ]) + + m = ([ + # Range 0 to a + [[self.ml, self.rl],[0,self.a]], + # Range a to b + [[self.c3, #x^0 + (0.5*math.pow(self.a,2)*self.s)+ (self.a*self.w1) + self.rl, #x^1 + (-0.5*self.a*self.s)-(0.5*self.w1), #x^2 + (1/6.0)*self.s], #x^3 + [self.a,self.b]], + # Range b to L + [[0],[self.b,self.L]] + ]) + + eis = ([ + # Range 0 to a + [[self.c1,self.ml,0.5*self.rl],[0,self.a]], + # Range a to b + [[self.c4,#x^0 + self.c3,#x^1 + (0.25*math.pow(self.a,2)*self.s)+(0.5*self.a*self.w1)+(0.5*self.rl),#x^2 + ((-1/6.0)*self.a*self.s) - ((1/6.0)*self.w1),#x^3 + (1/24.0)*self.s],#x^4 + [self.a,self.b]], + # Range b to L + [[self.c6],[self.b,self.L]] + ]) + + eid = ([ + # Range 0 to a + [[self.c2,#x^0 + self.c1,#x^1 + 0.5*self.ml,#x^2 + ((1.0/6.0)*self.rl),#x^3 + ], + [0,self.a]], + # Range a to b + [[self.c5,#x^0 + self.c4,#x^1 + 0.5*self.c3,#x^2 + ((1/12.0)*math.pow(self.a,2)*self.s)+ + ((1/6.0)*self.a*self.w1) + ((1/6.0)*self.rl),#x^3 + ((-1/24.0)*self.a*self.s) - ((1/24.0)*self.w1),#x^4 + (1/120.0)*self.s],#x^5 + [self.a,self.b]], + # Range b to L + [[self.c7,self.c6],[self.b,self.L]] + ]) + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + + def fef(self): + # Fixed End Forces + RL = self.rl + RR = 0 + ML = self.ml + MR = 0 + + return [RL,ML,RR,MR] + def v(self,x): iters = len(x) v=zeros(iters) @@ -1131,7 +2096,7 @@ def v(self,x): elif x[i]<=self.b: v[i] = self.rl + 0.5*self.s*x[i]**2 - x[i]*((self.s*self.a)+self.w1) + 0.5*self.a*((self.s*self.a)+(2*self.w1)) else: - v[i] =0 + v[i] = 0 return v def m(self,x): @@ -1215,12 +2180,58 @@ def __init__(self, slope, L): self.slope = float(slope) self.c1 = self.slope self.c2 = -1.0*self.c1*self.L - + self.kind = 'NL' self.rr = 0 + self.rl = 0 self.mr = 0 + self.x_graph = [0] + self.y_graph = [0] + + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + x = [0] + y = [0] + + return x,y + + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + v = [[[0],[0,self.L]]] + + m = [[[0],[0,self.L]]] + + eis = [[[self.c1],[0,self.L]]] + + eid = [[[self.c2, self.c1],[0,self.L]]] + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + + def fef(self): + # Fixed End Forces + RL = 0 + RR = 0 + ML = 0 + MR = 0 + + return [RL,ML,RR,MR] + def v(self,x): iters = len(x) v=zeros(iters) @@ -1280,17 +2291,18 @@ def __init__(self, p, a, L,Lb): self.kind = 'Point' self.error = '' - + if self.a > self.L: self.error = 'Error a > l' self.error = 'Error a > l' self.rr = self.p + self.rl = 0 self.mr = -1*self.p*(self.L-self.a) # 0 length backspan indicates fixed-free beam initialize slope to 0 if self.Lb == 0: - self.backspan = no_load() + self.backspan = no_load(0) self.c3 = 0 + (0.5*self.p * (self.L-self.a)**2) else: self.backspan = point_moment(self.mr,0,self.Lb) @@ -1302,12 +2314,68 @@ def __init__(self, p, a, L,Lb): arrow_height = self.p/6.0 #30 degree arrow - arrow_plus= self.a+(arrow_height*math.tan(math.radians(30))) - arrow_minus= self.a-(arrow_height*math.tan(math.radians(30))) + arrow_plus= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus= self.a-(arrow_height*math.tan(math.radians(15))) self.x_graph=[arrow_minus,self.a,arrow_plus,self.a,self.a] self.y_graph=[arrow_height,0,arrow_height,0,self.p] + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + if arrows == 1: + arrow_height = self.p/6.0 + #30 degree arrow + arrow_plus= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus= self.a-(arrow_height*math.tan(math.radians(15))) + + x=[arrow_minus,self.a,arrow_plus,self.a,self.a] + x = [i*x_scale for i in x] + y=[arrow_height,0,arrow_height,0,self.p] + y = [j*y_scale for j in y] + else: + x=[self.a,self.a] + x = [i*x_scale for i in x] + y=[0,self.p] + y = [j*y_scale for j in y] + + return x,y + + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + + v = [[[0],[0,self.a]],[[-1.0*self.p],[self.a,self.L]]] + + m = [[[0],[0,self.a]],[[self.p*self.a,-1.0*self.p],[self.a,self.L]]] + + eis = [[[self.c1],[0,self.a]],[[-0.5*self.a*self.a*self.p+self.c3,self.a*self.p, -0.5*self.p],[self.a,self.L]]] + + eid = [[[self.c2,self.c1],[0,self.a]],[[self.c4+((self.a*self.a*self.a*self.p)*(1/6.0)), self.c3-(0.5*self.a*self.a*self.p),0.5*self.a*self.p,(-1/6.0)*self.p],[self.a,self.L]]] + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + + def fef(self): + # Fixed End Forces + RL = 0 + RR = self.rr + ML = 0 + MR = self.mr + + return [RL,ML,RR,MR] + def v(self,x): iters = len(x) v=zeros(iters) @@ -1390,19 +2458,20 @@ def __init__(self, ma, a, L,Lb): self.Lb = float(Lb) self.kind = 'Moment' - + self.error = '' - + if self.a > self.L: self.error = 'Error a > l' self.error = 'Error a > l' self.rr = 0 + self.rl = 0 self.mr = self.ma # 0 length backspan indicates fixed-free beam initialize slope to 0 if Lb == 0: - self.backspan = no_load() + self.backspan = no_load(0) self.c3 = 0 - (self.ma*self.L) else: self.backspan = point_moment(self.mr,0,Lb) @@ -1412,10 +2481,10 @@ def __init__(self, ma, a, L,Lb): self.c1 = (1.0*self.ma*self.a) + self.c3 self.c2 = 0.5*self.ma*self.a**2 + self.c3*self.a + self.c4 - self.c1*self.a - r = (self.ma/8.0) + r = (self.ma/2.0) arrow_height = r/6.0 #30 degree arrow - arrow_minus= (arrow_height*math.tan(math.radians(30))) + arrow_minus= (arrow_height*math.tan(math.radians(15))) if self.ma <0: self.x_graph = [self.a,self.a,self.a] @@ -1445,6 +2514,83 @@ def __init__(self, ma, a, L,Lb): self.x_graph.append(x) self.y_graph.append(y) + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + r = (self.ma/2.0) + + if arrows == 1: + arrow_height = r/6.0 + #30 degree arrow + arrow_minus= (arrow_height*math.tan(math.radians(15))) + + if self.ma <0: + x= [self.a,self.a,self.a] + y = [r,0,-r] + xi=0 + yi=0 + for a in range(-90, 181): + xi = self.a+(r*math.cos(math.radians(a))) + yi = 0+(r*math.sin(math.radians(a))) + x.append(xi) + y.append(yi) + + x.append(xi-arrow_minus) + y.append(yi+arrow_height) + x.append(xi) + y.append(yi) + x.append(xi+arrow_minus) + y.append(yi+arrow_height) + else: + x= [self.a-r,self.a,self.a+r, self.a+r-arrow_minus,self.a+r,self.a+r+arrow_minus,self.a+r] + y = [0,0,0,arrow_height,0,arrow_height,0] + xi=0 + yi=0 + for a in range(0,271): + xi = self.a+(r*math.cos(math.radians(a))) + yi = 0+(r*math.sin(math.radians(a))) + x.append(xi) + y.append(yi) + + x = [i*x_scale for i in x] + y = [j*y_scale for j in y] + + return x,y + + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + v = [[[0],[0,self.L]]] + + m = [[[0],[0,self.a]],[[self.ma],[self.a,self.L]]] + + eis = [[[self.c1],[0,self.a]],[[self.c3,self.ma],[self.a,self.L]]] + + eid = [[[self.c2, self.c1],[0,self.a]],[[self.c4,self.c3,0.5*self.ma],[self.a,self.L]]] + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + + def fef(self): + # Fixed End Forces + RL = 0 + RR = self.rr + ML = 0 + MR = self.mr + + return [RL,ML,RR,MR] + def v(self,x): iters = len(x) v=zeros(iters) @@ -1527,11 +2673,11 @@ def __init__(self, w1, a, b, L, Lb): self.b = float(b) self.c = self.b-self.a self.w_tot = self.w1*self.c - + self.kind = 'UDL' self.error = '' - + if self.a > self.b: self.error = 'Error a > b' self.error = 'Error a > b' @@ -1543,13 +2689,14 @@ def __init__(self, w1, a, b, L, Lb): self.error = 'Error b > l' else: pass - + self.rr = self.w_tot + self.rl = 0 self.mr = -1.0*self.w_tot*(self.L-(a+(self.c/2.0))) # 0 length backspan indicates fixed-free beam initialize slope to 0 if Lb == 0: - self.backspan = no_load() + self.backspan = no_load(0) self.c5 = 0 + (0.5 * self.w_tot * (self.L - (self.a + (0.5*self.c)))**2) else: self.backspan = point_moment(self.mr,0,Lb) @@ -1563,14 +2710,125 @@ def __init__(self, w1, a, b, L, Lb): arrow_height = self.w1/12.0 #30 degree arrow - arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(30))) - arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(30))) - arrow_plus_end= self.b+(arrow_height*math.tan(math.radians(30))) - arrow_minus_end= self.b-(arrow_height*math.tan(math.radians(30))) + arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(15))) + arrow_plus_end= self.b+(arrow_height*math.tan(math.radians(15))) + arrow_minus_end= self.b-(arrow_height*math.tan(math.radians(15))) self.x_graph=[arrow_minus_start,self.a,arrow_plus_start,self.a,self.a,self.b,self.b,arrow_minus_end,self.b,arrow_plus_end] self.y_graph=[arrow_height,0,arrow_height,0,self.w1,self.w1,0,arrow_height,0,arrow_height] + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + if arrows == 1: + arrow_height = self.w1/12.0 + #30 degree arrow + arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(15))) + arrow_plus_end= self.b+(arrow_height*math.tan(math.radians(15))) + arrow_minus_end= self.b-(arrow_height*math.tan(math.radians(15))) + + x=[arrow_minus_start,self.a,arrow_plus_start,self.a,self.a,self.b,self.b,arrow_minus_end,self.b,arrow_plus_end] + x = [i*x_scale for i in x] + y=[arrow_height,0,arrow_height,0,self.w1,self.w1,0,arrow_height,0,arrow_height] + y = [j*y_scale for j in y] + else: + x=[self.a,self.a,self.b,self.b] + x = [i*x_scale for i in x] + y=[0,self.w1,self.w1,0] + y = [j*y_scale for j in y] + + return x,y + + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + v = ([ + [[0],[0,self.a]], + [[self.w1*self.a, + -1.0*self.w1], + [self.a,self.b]], + [[-1.0*self.w_tot],[self.b,self.L]] + ]) + + m = ([ + # Range 0 to a + [[0],[0,self.a]], + # Range a to b + [[-0.5*math.pow(self.a,2)*self.w1, + self.a*self.w1, + -0.5*self.w1], + [self.a,self.b]], + # Range b to L + [[self.a*self.w_tot + 0.5*self.c*self.w_tot, + -1.0*self.w_tot], + [self.b,self.L]] + ]) + + eis = ([ + # Range 0 to a + [[self.c1],[0,self.a]], + # Range a to b + [[(1/6.0)*math.pow(self.a,3)*self.w1 + self.c3,#x^0 + -0.5*math.pow(self.a,2)*self.w1,#x^1 + 0.5*self.a*self.w1,#x^2 + (-1/6.0)*self.w1],#x^3 + [self.a,self.b]], + # Range b to L + [[self.c5-(0.5*math.pow(self.a,2)*self.w_tot)- + (0.5*self.a*self.c*self.w_tot) - ((1/8.0)*math.pow(self.c,2)*self.w_tot),#x^0 + (self.a*self.w_tot)+(0.5*self.c*self.w_tot),#x^1 + -0.5*self.w_tot],#x^2 + [self.b,self.L]] + ]) + + eid = ([ + # Range 0 to a + [[self.c2,self.c1],[0,self.a]], + # Range a to b + [[self.c4-((1/24.0)*math.pow(self.a,4)*self.w1),#x^0 + (1/6.0)*math.pow(self.a,3)*self.w1+self.c3,#x^1 + -0.25*math.pow(self.a,2)*self.w1,#x^2 + (1/6.0)*self.a*self.w1,#x^3 + (-1/24.0)*self.w1],#x^4 + [self.a,self.b]], + # Range b to L + [[((1/6.0)*math.pow(self.a,3)*self.w_tot)+ + (0.25*math.pow(self.a,2)*self.c*self.w_tot)+ + (0.125*self.a*math.pow(self.c,2)*self.w_tot)+ + ((1/48.0)*math.pow(self.c,3)*self.w_tot)+self.c6,#x^0 + (-0.5*math.pow(self.a,2)*self.w_tot)- + (0.5*self.a*self.c*self.w_tot)- + (0.125*math.pow(self.c,2)*self.w_tot)+self.c5,#x^1 + (0.5*self.a*self.w_tot) + (0.25*self.c*self.w_tot),#x^2 + (-1/6.0)*self.w_tot],#x^3 + [self.b,self.L]] + ]) + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + + def fef(self): + # Fixed End Forces + RL = 0 + RR = self.rr + ML = 0 + MR = self.mr + + return [RL,ML,RR,MR] + def v(self,x): iters = len(x) v=zeros(iters) @@ -1670,11 +2928,11 @@ def __init__(self, w1, w2, a, b, L, Lb): self.b = float(b) self.Lb = float(Lb) self.c = self.b-self.a - + self.kind = 'TRAP' - + self.error = '' - + if self.a > self.b: self.error = 'Error a > b' self.error = 'Error a > b' @@ -1689,18 +2947,19 @@ def __init__(self, w1, w2, a, b, L, Lb): self.error = 'Error w1 and w2 change direction' else: pass - + self.w = 0.5*(self.w1+self.w2)*self.c self.dl = self.a+(((self.w1+(2*self.w2))/(3*(self.w2+self.w1)))*self.c) self.dr = self.L-self.dl self.s = (self.w1-self.w2)/self.c self.cc = (((self.w1+(2*self.w2))/(3*(self.w2+self.w1)))*self.c) + self.a self.rr = self.w + self.rl=0 self.mr = -1*self.rr*(self.L-self.cc) # 0 length backspan indicates fixed-free beam initialize slope to 0 if Lb == 0: - self.backspan = no_load() + self.backspan = no_load(0) self.c6 = 0 + (0.5*self.w*(self.L-self.cc)**2) else: self.backspan = point_moment(self.mr,0,Lb) @@ -1716,14 +2975,130 @@ def __init__(self, w1, w2, a, b, L, Lb): arrow_height = self.w1/6.0 arrow_height2 = self.w2/6.0 #30 degree arrow - arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(30))) - arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(30))) - arrow_plus_end= self.b+(arrow_height2*math.tan(math.radians(30))) - arrow_minus_end= self.b-(arrow_height2*math.tan(math.radians(30))) + arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(15))) + arrow_plus_end= self.b+(arrow_height2*math.tan(math.radians(15))) + arrow_minus_end= self.b-(arrow_height2*math.tan(math.radians(15))) self.x_graph=[arrow_minus_start,self.a,arrow_plus_start,self.a,self.a,self.b,self.b,arrow_minus_end,self.b,arrow_plus_end] self.y_graph=[arrow_height,0,arrow_height,0,self.w1,self.w2,0,arrow_height2,0,arrow_height2] + def chart_load(self, x_scale=0, y_scale=0, arrows=0): + if arrows == 1: + arrow_height = self.w1/6.0 + arrow_height2 = self.w2/6.0 + #30 degree arrow + arrow_plus_start= self.a+(arrow_height*math.tan(math.radians(15))) + arrow_minus_start= self.a-(arrow_height*math.tan(math.radians(15))) + arrow_plus_end= self.b+(arrow_height2*math.tan(math.radians(15))) + arrow_minus_end= self.b-(arrow_height2*math.tan(math.radians(15))) + + x=[arrow_minus_start,self.a,arrow_plus_start,self.a,self.a,self.b,self.b,arrow_minus_end,self.b,arrow_plus_end] + x = [i*x_scale for i in x] + y=[arrow_height,0,arrow_height,0,self.w1,self.w2,0,arrow_height2,0,arrow_height2] + y = [j*y_scale for j in y] + else: + x=[self.a,self.a,self.b,self.b] + x = [i*x_scale for i in x] + y=[0,self.w1,self.w2,0] + y = [j*y_scale for j in y] + + return x,y + + def piece_functions(self): + ''' + Returns the general piecwise function in the form of two lists + # list1 is the polynomial coeficients of order [c0,c1x,c2x^2,...,cnx^n] + # where the list values will only by the cn's* + # list 2 will be the range over which the function piece applies + # 0 <= a would be [0,a] **note it will be assumed the the eqality is <= not < + # rerturned lists will be [[[list11],[list21]],....,[[list1n],[list2n]] + # where n is the total number of functions to capture the range from + # 0 to the full span, L of the beam + ''' + + v = ([ + [[0], + [0,self.a]], + [[(0.5*math.pow(self.a,2)*self.s)+(self.a*self.w1), #x^0 + (-1.0*self.a*self.s) - self.w1, #x^1 + 0.5*self.s], #x^2 + [self.a,self.b]], + [[-1.0*self.rr], + [self.b,self.L]] + ]) + + m = ([ + # Range 0 to a + [[0], + [0,self.a]], + # Range a to b + [[self.c3, #x^0 + (0.5*math.pow(self.a,2)*self.s)+(self.a*self.w1), #x^1 + (-0.5*self.a*self.s) - (0.5*self.w1), #x^2 + (1/6.0)*self.s], #x^3 + [self.a,self.b]], + # Range b to L + [[self.w*self.cc, #x^0 + -1.0*self.w], #x^1 + [self.b,self.L]] + ]) + + eis = ([ + # Range 0 to a + [[self.c1], + [0,self.a]], + # Range a to b + [[self.c4,#x^0 + self.c3,#x^1 + (0.25*math.pow(self.a,2)*self.s)+(0.5*self.a*self.w1),#x^2 + ((-1/6.0)*self.a*self.s)-((1/6.0)*self.w1),#x^3 + (1/24.0)*self.s],#x^4 + [self.a,self.b]], + # Range b to L + [[self.c6-(0.5*math.pow(self.cc,2)*self.w),#x^0 + self.cc*self.w,#x^1 + -0.5*self.w],#x^2 + [self.b,self.L]] + ]) + + eid = ([ + # Range 0 to a + [[self.c2,self.c1], + [0,self.a]], + # Range a to b + [[self.c5,#x^0 + self.c4,#x^1 + 0.5*self.c3,#x^2 + ((1/12.0)*math.pow(self.a,2)*self.s)+((1/6.0)*self.a*self.w1),#x^3 + ((-1/24.0)*self.a*self.s)-((1/24.0)*self.w1),#x^4 + (1/120.0)*self.s],#x^5 + + [self.a,self.b]], + # Range b to L + [[self.c7+((1/6.0)*math.pow(self.cc,3)*self.w),#x^0 + self.c6-(0.5*math.pow(self.cc,2)*self.w),#x^1 + 0.5*self.cc*self.w,#x^2 + (-1/6.0)*self.w],#x^3 + [self.b,self.L]] + ]) + + vs = PieceFunctionString(v) + ms = PieceFunctionString(m) + eiss = PieceFunctionString(eis) + eids = PieceFunctionString(eid) + + return [v,m,eis,eid],[vs,ms,eiss,eids] + + def fef(self): + # Fixed End Forces + RL = 0 + RR = self.rr + ML = 0 + MR = self.mr + + return [RL,ML,RR,MR] + def v(self,x): iters = len(x) v=zeros(iters) @@ -1813,8 +3188,8 @@ def eidx(self,x): return eid def fixed_free_left_by_stations(loads, number_of_stations): - - # Take a list of loads and integer ammount of stations and return + + # Take a list of loads and integer ammount of stations and return # lists of stations, shears, moments,E*I*Slopes, and E*I*Deflections # # loads should already be defined using the classes in this file @@ -1824,16 +3199,16 @@ def fixed_free_left_by_stations(loads, number_of_stations): # defined. Validation of this will be added at a later date. # # -Consistent unit definitions across load values and lengths - + L = loads[0].L - + iters = int(number_of_stations) - + # Review loads and add additional stations to capture load start # and end points. For Point/Point Moments add station directly before # and directly after load. extra_stations = np.array([0]) - + for load in loads: if load.kind == 'Point': a = load.a @@ -1849,44 +3224,44 @@ def fixed_free_left_by_stations(loads, number_of_stations): elif load.kind == 'UDL': extra_stations = np.append(extra_stations, [load.a,load.b]) - + elif load.kind == 'TRAP': extra_stations = np.append(extra_stations, [load.a,load.b]) - + else: pass - + extra_stations = np.unique(extra_stations) - + # Generate station coordinates based on a step size of l / number of stations - + step = L / (number_of_stations * 1.00) # multply by 1.00 to force Float division - + xs = zeros(iters+1) - + xs[0] = 0 - + for i in range(1,(iters+1)): if xs[i-1] + step > L: xs[i] = L else: xs[i] = xs[i-1] + step - + xs = np.append(xs, extra_stations) - + xs = np.sort(xs) - + xs = np.unique(xs) - + i = xs.shape[0] - + r = 0 mr = 0 v = zeros(i) m = zeros(i) eis = zeros(i) eid = zeros(i) - + for load in loads: r = r + load.rr mr = mr + load.mr @@ -1894,14 +3269,14 @@ def fixed_free_left_by_stations(loads, number_of_stations): m = m + load.m(xs) eis = eis + load.eis(xs) eid = eid + load.eid(xs) - + result_list = [xs,r,mr,v,m,eis,eid] - + return result_list - + def fixed_free_right_by_stations(loads, number_of_stations): - - # Take a list of loads and integer ammount of stations and return + + # Take a list of loads and integer ammount of stations and return # lists of stations, shears, moments,E*I*Slopes, and E*I*Deflections # # loads should already be defined using the classes in this file @@ -1911,16 +3286,16 @@ def fixed_free_right_by_stations(loads, number_of_stations): # defined. Validation of this will be added at a later date. # # -Consistent unit definitions across load values and lengths - + L = loads[0].L - + iters = int(number_of_stations) - + # Review loads and add additional stations to capture load start # and end points. For Point/Point Moments add station directly before # and directly after load. extra_stations = np.array([0]) - + for load in loads: if load.kind == 'Point': a = load.a @@ -1936,45 +3311,45 @@ def fixed_free_right_by_stations(loads, number_of_stations): elif load.kind == 'UDL': extra_stations = np.append(extra_stations, [load.a,load.b]) - + elif load.kind == 'TRAP': extra_stations = np.append(extra_stations, [load.a,load.b]) - + else: pass - + extra_stations = np.unique(extra_stations) - + # Generate station coordinates based on a step size of l / number of stations - + step = L / (number_of_stations * 1.00) # multply by 1.00 to force Float division - + xs = zeros(iters+1) - + xs[0] = 0 - + for i in range(1,(iters+1)): if xs[i-1] + step > L: xs[i] = L else: xs[i] = xs[i-1] + step - + xs = np.append(xs, extra_stations) - + xs = np.sort(xs) - + xs = np.unique(xs) - + i = xs.shape[0] - + r = 0 ml = 0 v = zeros(i) m = zeros(i) eis = zeros(i) eid = zeros(i) - - + + for load in loads: r = r + load.rl ml = ml + load.ml @@ -1982,13 +3357,13 @@ def fixed_free_right_by_stations(loads, number_of_stations): m = m + load.m(xs) eis = eis + load.eis(xs) eid = eid + load.eid(xs) - + result_list = [xs,r,ml,v,m,eis,eid] - + return result_list def fixed_free_at_x(loads, x): - # Take a list of loads and x location in span and return + # Take a list of loads and x location in span and return # shear, moment,E*I*Slope, and E*I*Deflection # # loads should already be defined using the classes in this file @@ -1998,24 +3373,24 @@ def fixed_free_at_x(loads, x): # defined. Validation of this will be added at a later date. # # -Consistent unit definitions across load values and lengths - + v = 0 m = 0 eis = 0 eid = 0 - + for load in loads: v = v + load.vx(x) m = m + load.mx(x) eis = eis + load.eisx(x) eid = eid + load.eidx(x) - + result_list = [v,m,eis,eid] - + return result_list def pin_pin_single_span_at_x(loads, x): - # Take a list of loads and x locatoin in span and return + # Take a list of loads and x locatoin in span and return # shear, moment,E*I*Slope, and E*I*Deflection # # loads should already be defined using the classes in this file @@ -2025,25 +3400,25 @@ def pin_pin_single_span_at_x(loads, x): # defined. Validation of this will be added at a later date. # # -Consistent unit definitions across load values and lengths - + v = 0 m = 0 eis = 0 eid = 0 - + for load in loads: v = v + load.vx(x) m = m + load.mx(x) eis = eis + load.eisx(x) eid = eid + load.eidx(x) - + result_list = [v,m,eis,eid] - + return result_list - + def pin_pin_single_span_by_stations(loads, number_of_stations): - - # Take a list of loads and integer ammount of stations and return + + # Take a list of loads and integer ammount of stations and return # lists of stations, shears, moments,E*I*Slopes, and E*I*Deflections # # loads should already be defined using the classes in this file @@ -2053,16 +3428,16 @@ def pin_pin_single_span_by_stations(loads, number_of_stations): # defined. Validation of this will be added at a later date. # # -Consistent unit definitions across load values and lengths - + L = loads[0].L - + iters = int(number_of_stations) - + # Review loads and add additional stations to capture load start # and end points. For Point/Point Moments add station directly before # and directly after load. extra_stations = np.array([0]) - + for load in loads: if load.kind == 'Point': a = load.a @@ -2078,45 +3453,45 @@ def pin_pin_single_span_by_stations(loads, number_of_stations): elif load.kind == 'UDL': extra_stations = np.append(extra_stations, [load.a,load.b]) - + elif load.kind == 'TRAP': extra_stations = np.append(extra_stations, [load.a,load.b]) - + else: pass - + extra_stations = np.unique(extra_stations) - + # Generate station coordinates based on a step size of l / number of stations - + step = L / (number_of_stations * 1.00) # multply by 1.00 to force Float division - + xs = zeros(iters+1) - + xs[0] = 0 - + for i in range(1,(iters+1)): if xs[i-1] + step > L: xs[i] = L else: xs[i] = xs[i-1] + step - + xs = np.append(xs, extra_stations) - + xs = np.sort(xs) - + xs = np.unique(xs) - + i = xs.shape[0] - + rl = 0 rr = 0 v = zeros(i) m = zeros(i) eis = zeros(i) eid = zeros(i) - - + + for load in loads: rl = rl + load.rl rr = rr + load.rr @@ -2124,15 +3499,15 @@ def pin_pin_single_span_by_stations(loads, number_of_stations): m = m + load.m(xs) eis = eis + load.eis(xs) eid = eid + load.eid(xs) - + result_list = [xs,rl,rr,v,m,eis,eid] - + return result_list def fixed_end_moments_from_end_slopes(eis0, eisL, fed, L): ####################################################################################################### # - # Solve Simultaneous equation for fixed end moments knowing + # Solve Simultaneous equation for fixed end moments knowing # end slopes of simple beam at support points: # # By compatibility for fixed ends initial and final slope should be 0. @@ -2161,40 +3536,40 @@ def fixed_end_moments_from_end_slopes(eis0, eisL, fed, L): # eis0 = E*I*Slope @ 0 ft or beam left end # eisL = E*I*Slope @ L ft or beam right end # fed = [1,1], where a 1 signifies the location is fixed - # L = span length + # L = span length # # Assumptions: # 1. consistent units are used for the inputs - # 2. the slopes entered are the actual slope not + # 2. the slopes entered are the actual slope not # the inverse ie not the restoring slope # ####################################################################################################### - + if fed[0] == 1 and fed[1] == 1: s = np.array([[-1.0*eis0],[-1.0*eisL]]) - + ems = np.array([[-1.0*L/3.0 , L/6.0],[L/6.0 , -1.0*L/3.0]]) - + fem = np.linalg.solve(ems,s) - + elif fed[0] == 1 and fed[1] == 0: fel= ((-1.0*eis0 * -3.0) / L) fem = np.array([[fel],[0]]) - + elif fed[0] == 0 and fed[1] == 1: fer = ((-1.0*eisL * -3.0) / L) fem = np.array([[0],[fer]]) - + else: fem = np.array([[0],[0]]) - + return fem def single_span_solve_fixed_ends_and_redundant_interiors(delta, reaction_points, L, fem): - + ####################################################################################################### # - # Solve Simultaneous equation for internal reactions and fixed end moments knowing + # Solve Simultaneous equation for internal reactions and fixed end moments knowing # deflection and end slopes of simple beam at support points: # # By compatibility for fixed ends initial and final slope should be 0, and deflection @@ -2250,77 +3625,77 @@ def single_span_solve_fixed_ends_and_redundant_interiors(delta, reaction_points, # # Assumptions: # 1. consistent units are used for the inputs - # 2. the deformations entered are the actual deformations not + # 2. the deformations entered are the actual deformations not # the inverse ie not the restoring deformation. # ####################################################################################################### - + #build the coefficient matrix rows and the deflection values coeff_matrix = [] - + delta = [-1.0*x for x in delta] - + #Start Moment Component mo = point_moment(1,0,L) ml = point_moment(1,L,L) - + coeff_matrix.append([mo.eisx(0)*fem[0],ml.eisx(0)*fem[1]]) coeff_matrix.append([mo.eisx(L)*fem[0],ml.eisx(L)*fem[1]]) - + for support in reaction_points: a = support - + point_load = pl(1,a,L) - + coeff_row = [] - + coeff_row.append(mo.eidx(a)*fem[0]) coeff_row.append(ml.eidx(a)*fem[1]) - + for point in reaction_points: - + x = point new_pl = pl(1,x,L) eid_p = new_pl.eidx(a) - + coeff_row.append(eid_p) - + coeff_matrix[0].append(point_load.eisx(0)) coeff_matrix[1].append(point_load.eisx(L)) - - + + coeff_matrix.append(coeff_row) - + d = np.array(delta) coeff = np.array(coeff_matrix) - + if fem == [0,1]: d = np.delete(d, (0), axis=0) coeff = np.delete(coeff, (0), axis=0) coeff = np.delete(coeff, (0), axis=1) - + reaction_points = [0] + reaction_points - + elif fem == [1,0]: d = np.delete(d, (1), axis=0) coeff = np.delete(coeff, (1), axis=0) coeff = np.delete(coeff, (1), axis=1) - + reaction_points = [0] + reaction_points - + elif fem == [0,0]: d = np.delete(d, (0), axis=0) coeff = np.delete(coeff, (0), axis=0) coeff = np.delete(coeff, (0), axis=1) - + d = np.delete(d, (0), axis=0) coeff = np.delete(coeff, (0), axis=0) coeff = np.delete(coeff, (0), axis=1) else: reaction_points = [0,0] + reaction_points - + R = np.linalg.solve(coeff,d) - + #List of reactions defined as loads from class types above reactions_as_loads = [] @@ -2329,21 +3704,210 @@ def single_span_solve_fixed_ends_and_redundant_interiors(delta, reaction_points, if (fem == [1,0] or fem == [1,1]) and i == 0: m = reaction reactions_as_loads.append(point_moment(m,0,L)) - + elif fem == [0,1] and i == 0: m = reaction reactions_as_loads.append(point_moment(m,L,L)) - + elif fem == [1,1] and i == 1: m = reaction reactions_as_loads.append(point_moment(m,L,L)) - + else: p = reaction a = reaction_points[i] reactions_as_loads.append(pl(p,a,L)) - + i+=1 return R, reactions_as_loads +def center_span_piecewise_function(loads): + ''' + Build the full piecewise fucntion set for a single span + Input: lists of loads as defined above + output: lists of piecewise functions and list of piecewise functions as text strings + + It is assumed all loads have the same span length defined + ''' + + # Gather load start and end locations these define how the fucntions will be split + ab = [] + ab.append(loads[0].L) + for load in loads: + if load.kind == "Point" or load.kind == "Moment": + ab.append(load.a) + elif load.kind == "NL" or load.kind == "END_DELTA": + pass + else: + ab.append(load.a) + ab.append(load.b) + ab = list(set(ab)) + ab.sort() + + v_out = [] + m_out = [] + eis_out = [] + eid_out = [] + + count=0 + for i in ab: + if count == 0: + piece_range = [0,i] + else: + piece_range = [ab[count-1],i] + + if piece_range == [0,0]: + pass + else: + v = [] + m = [] + eis = [] + eid = [] + for load in loads: + func, func_strings = load.piece_functions() + + #Shear + for piece in func[0]: + if piece[1][0] < piece_range[1] and piece[1][1] >= piece_range[1]: + eq_len_delta = len(piece[0]) - len(v) # difference in number of coefficients + + if eq_len_delta > 0: + v.extend([0]*eq_len_delta) + elif eq_len_delta<0: + piece[0].extend([0]*abs(eq_len_delta)) + else: + pass + + v = [sum(x) for x in zip(piece[0],v)] + else: + pass + #Moment + for piece in func[1]: + if piece[1][0] < piece_range[1] and piece[1][1] >= piece_range[1]: + eq_len_delta = len(piece[0]) - len(m) # difference in number of coefficients + + if eq_len_delta > 0: + m.extend([0]*eq_len_delta) + elif eq_len_delta<0: + piece[0].extend([0]*abs(eq_len_delta)) + else: + pass + + m = [sum(x) for x in zip(piece[0],m)] + else: + pass + #EIS + for piece in func[2]: + if piece[1][0] < piece_range[1] and piece[1][1] >= piece_range[1]: + eq_len_delta = len(piece[0]) - len(eis) # difference in number of coefficients + + if eq_len_delta > 0: + eis.extend([0]*eq_len_delta) + elif eq_len_delta<0: + piece[0].extend([0]*abs(eq_len_delta)) + else: + pass + + eis = [sum(x) for x in zip(piece[0],eis)] + else: + pass + #EID + for piece in func[3]: + if piece[1][0] < piece_range[1] and piece[1][1] >= piece_range[1]: + eq_len_delta = len(piece[0]) - len(eid) # difference in number of coefficients + + if eq_len_delta > 0: + eid.extend([0]*eq_len_delta) + elif eq_len_delta<0: + piece[0].extend([0]*abs(eq_len_delta)) + else: + pass + + eid = [sum(x) for x in zip(piece[0],eid)] + else: + pass + v_out.append([v,piece_range]) + m_out.append([m,piece_range]) + eis_out.append([eis,piece_range]) + eid_out.append([eid,piece_range]) + count +=1 + + vs = PieceFunctionString(v_out) + ms = PieceFunctionString(m_out) + eiss = PieceFunctionString(eis_out) + eids = PieceFunctionString(eid_out) + + return [v_out, m_out, eis_out, eid_out],[vs, ms, eiss, eids] + +def eval_beam_piece_function(piece_function,x): + ''' + Given the peicewise beam functions and a location evaluate the results + + return a list of [V,M,EIS,EID] + ''' + + res = [] + + for func in piece_function: + for line in func: + if line[1][0] == 0 and x ==0: + res.append(poly_eval(line[0],x)) + if line[1][0] < x <= line[1][1]: + res.append(poly_eval(line[0],x)) + else: + pass + + return res + +def points_of_zero_shear(shear_piece_function): + ''' + Given the piecewise shear function for the beam return a list + of the location of zero shear or where shear jumps from + to - ie + at point loads + ''' + + zero_loc = [] + i=0 + for line in shear_piece_function: + + if len(line[0]) == 1 and i==0: + pass # If function is a value then there is no chance for a sign change + + else: + a = poly_eval(line[0], line[1][0]+0.0001) # value at start of bounds + b = poly_eval(line[0], line[1][1]-0.0001) # value at end of bounds + + if a==0: + zero_loc.append(line[1][0]) + + elif b==0: + zero_loc.append(line[1][1]) + + else: + # if signs are the the same a/b will result in a positive value + coeff = line[0][::-1] + c = np.roots(coeff) + c = c.real[abs(c.imag)<1e-5] + for root in c: + if line[1][0] < root <= line[1][1]: + zero_loc.append(root) + else: + pass + + if i==0: + pass + else: + d = poly_eval(shear_piece_function[i-1][0], line[1][0]-0.0001) # value at end of previous bounds + + if d == 0: + pass + elif a/d < 0: + zero_loc.append(line[1][0]) + else: + pass + i+=1 + + zero_loc = sorted(set(zero_loc)) + + return zero_loc diff --git a/Analysis/pin_pin_point_moment.py b/Analysis/pin_pin_point_moment.py deleted file mode 100644 index 1c01b8d..0000000 --- a/Analysis/pin_pin_point_moment.py +++ /dev/null @@ -1,83 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Mon Mar 26 15:00:06 2018 - -@author: DonB -""" - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -import scipy as sci -import scipy.integrate - -#pin pin beam with point moment -E_ksi = 29000.0 -E_ksf = E_ksi * (144.0) -I_in4 = 30.8 -I_ft4 = I_in4/(12.0**4) - -m_ftkips = 2.0 -a_ft = 3 -l_ft = 10.0 - -rr_kips = m_ftkips/l_ft -rl_kips = -1.0*rr_kips - -c2 = (-1.0/l_ft) * ((m_ftkips*a_ft**2) - (0.5*m_ftkips*a_ft**2) + (rl_kips * (l_ft**3/6.0)) + (0.5*m_ftkips*l_ft**2)) -c1 = m_ftkips*a_ft + c2 -c3 = 0 -c4 = ((-1.0*rl_kips*l_ft**3)/6.0) - (0.5*m_ftkips*l_ft**2) - (c2*l_ft) - -step = l_ft/1000 -station = [] -v = [] -m = [] -eis = [] -eid = [] -x=0 -xs=[0] -for i in range(0,1001): - if i==0: - x = 0 - else: - x = x + step - xs.append(x) - v.append(rl_kips) - - if x <= a_ft: - mx = rl_kips * x - eisx = (0.5*rl_kips*x**2) + c1 - eidx = ((1/6.0)*rl_kips*x**3) + (c1*x) + c3 - - else: - mx = (rl_kips * x) + m_ftkips - eisx = (0.5*rl_kips*x**2) + (m_ftkips*x) + c2 - eidx = (1/6.0)*rl_kips*x**3 + (0.5*m_ftkips*x**2) + (c2*x) + c4 - - m.append(mx) - eis.append(eisx) - eid.append(eidx) - station.append(x) - -m_xx=[] -A = sci.integrate.simps(m, xs) -for i in range(len(xs)): - m_xx.append(m[i]*xs[i]) - -xl = (1/A)*sci.integrate.simps(m_xx, xs) -xr = l_ft - xl - -Aal = (6.0*A*xl / l_ft) -Aar = (6.0*A*xr / l_ft) \ No newline at end of file diff --git a/Analysis/section_props.py b/Analysis/section_props.py new file mode 100644 index 0000000..73cac63 --- /dev/null +++ b/Analysis/section_props.py @@ -0,0 +1,1289 @@ +''' +BSD 3-Clause License +Copyright (c) 2019-2022, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' + +from __future__ import division +import math + + +def coordinate_rotation(x, y, xo, yo, angle): + + theta = math.radians(angle) + + x_t = (x-xo)*math.cos(theta)-(y-yo)*math.sin(theta) + y_t = (x-xo)*math.sin(theta)+(y-yo)*math.cos(theta) + + x_t = x_t+xo + y_t = y_t+yo + + return [x_t, y_t] + + +class Section: + + def __init__(self, x, y, solid=True, n=1, E=1, Fy=1): + ''' + A section defined by (x,y) vertices + + the vertices should for a closed polygon. + initialization will check is first and last coordinate are equal + and if not will add an additional vertex equal to the first + + Inputs: + + x = a list of x coordinate values + y = a list of y coordinate values + + Assumptions: + + x and y are of consistent units + x and y form a closed polygon with no segment overlaps + + If solid = 1 then the coordinates will be ordered so the signed area + is positive + + n = property multiplier + ''' + + self.output = [] + self.output_strings = [] + + self.E = E + self.Fy = Fy + self.solid = solid + + # check if a closed polygon is formed from the coordinates + # if not add another x and y coordinate equal to the firts + # coordinate x and y + + self.warnings = '' + if x[0] == x[-1] and y[0] == y[-1]: + pass + else: + x.append(x[0]) + y.append(y[0]) + + self.warnings = self.warnings + '**User Verify** Shape was not closed, program attempted to close it.\p' + + # check the signed area of the coordinates, should be positive + # for a solid shape. If not reverse the coordinate order + + self.area = sum([(x[i]*y[i+1])-(x[i+1]*y[i]) for i in range(len(x[:-1]))])/2.0 + self.area = self.area*n + + if self.area < 0 and solid == True: + x.reverse() + y.reverse() + self.warnings = self.warnings + '**User Verify** Coordinate order reversed to make signed area positive for a solid.\n' + + self.area = sum([(x[i]*y[i+1])-(x[i+1]*y[i]) for i in range(len(x[:-1]))])/2.0 + self.area = self.area*n + + elif self.area > 0 and solid is False: + x.reverse() + y.reverse() + self.warnings = self.warnings + '**User Verify** Coordinate order reversed to make signed area negative for a void.\n' + + self.area = sum([(x[i]*y[i+1])-(x[i+1]*y[i]) for i in range(len(x[:-1]))])/2.0 + self.area = self.area*n + + elif self.area == 0: + self.warnings = self.warnings + '**User Verify** Area = 0 - verify defined shape has no overlapping segments.\n' + + else: + pass + + self.x = [i for i in x] + self.y = [j for j in y] + self.n = n + + if self.area == 0: + pass + else: + self.calc_props() + + def compute_n(self, other): + n = self.E / other.E + self.n = n + self.calc_props() + + def change_n(self, n): + self.n = n + self.calc_props() + + def segments(self): + ''' + return ordered coordinate pairs defining the line segments + of each side of the section. + ''' + segments = [[[self.x[i[0]],self.y[j[0]]],[self.x[i[0]+1],self.y[j[0]+1]]] for i,j in zip(enumerate(self.x[1:]),enumerate(self.y[1:]))] + + self.segments = segments + + return segments + + def transformed_segments(self, xo, yo, angle_degrees): + ''' + given an angle in degrees + and coordinate to translate about + return the transformed vertices segment pairs + ''' + theta = math.radians(angle_degrees) + + x_tr = [(x-xo)*math.cos(theta)+(y-yo)*math.sin(theta) for x,y in zip(self.x, self.y)] + y_tr = [-1.0*(x-xo)*math.sin(theta)+(y-yo)*math.cos(theta) for x,y in zip(self.x, self.y)] + + segments = [[[x_tr[i[0]],y_tr[j[0]]],[x_tr[i[0]+1],y_tr[j[0]+1]]] for i,j in zip(enumerate(x_tr[1:]),enumerate(y_tr[1:]))] + + return segments + + def calc_props(self): + x = self.x + y = self.y + n = self.n + + self.area = sum([(x[i]*y[i+1])-(x[i+1]*y[i]) for i in range(len(x[:-1]))])/2.0 + self.narea = self.area*n + + self.output.append(self.area) + self.output_strings.append('Area') + + # properties about the global x and y axis + + self.cx = sum([(x[i]+x[i+1])*((x[i]*y[i+1])-(x[i+1]*y[i])) for i in range(len(x[:-1]))])/(6*self.area) + self.cx = self.cx + self.output.append(self.cx) + self.output_strings.append('Cx') + self.cy = sum([(y[i]+y[i+1])*((x[i]*y[i+1])-(x[i+1]*y[i])) for i in range(len(x[:-1]))])/(6*self.area) + self.cy = self.cy + self.output.append(self.cy) + self.output_strings.append('Cy') + self.output.append('---') + self.output_strings.append('Global Axis:') + self.Ix = sum([((y[i]*y[i])+(y[i]*y[i+1])+(y[i+1]*y[i+1]))*((x[i]*y[i+1])-(x[i+1]*y[i])) for i in range(len(x[:-1]))])/(12.0) + self.nIx = self.Ix*n + self.output.append(self.Ix) + self.output_strings.append('Ix') + self.Iy = sum([((x[i]*x[i])+(x[i]*x[i+1])+(x[i+1]*x[i+1]))*((x[i]*y[i+1])-(x[i+1]*y[i])) for i in range(len(x[:-1]))])/(12.0) + self.nIy = self.Iy*n + self.output.append(self.Iy) + self.output_strings.append('Iy') + self.Ixy = sum([((x[i]*y[i+1])+(2*x[i]*y[i])+(2*x[i+1]*y[i+1])+(x[i+1]*y[i]))*(x[i]*y[i+1]-x[i+1]*y[i]) for i in range(len(x[:-1]))])/(24.0) + self.nIxy = self.Ixy*n + self.output.append(self.Ixy) + self.output_strings.append('Ixy') + self.Jz = self.Ix + self.Iy + self.nJz = self.Jz*n + self.output.append(self.Jz) + self.output_strings.append('Jz') + self.sx_top = self.Ix / abs(max(y) - self.cy) + self.output.append(self.sx_top) + self.output_strings.append('Sx,top') + self.sx_bottom = self.Ix / abs(min(y) - self.cy) + self.output.append(self.sx_bottom) + self.output_strings.append('Sx,botom') + self.sy_right = self.Iy / abs(max(x) - self.cx) + self.output.append(self.sy_right) + self.output_strings.append('Sy,right') + self.sy_left = self.Iy / abs(min(x) - self.cx) + self.output.append(self.sy_left) + self.output_strings.append('Sy,left') + + self.rx = math.sqrt(self.Ix/self.area) + self.output.append(self.rx) + self.output_strings.append('rx') + self.ry = math.sqrt(self.Iy/self.area) + self.output.append(self.ry) + self.output_strings.append('ry') + self.rz = math.sqrt(self.Jz/self.area) + self.output.append(self.rz) + self.output_strings.append('rz') + + # properties about the cross section centroidal x and y axis + # parallel axis theorem Ix = Ixx + A*d^2 + # therefore to go from the global axis to the local + # Ixx = Ix - A*d^2 + self.output.append('--') + self.output_strings.append('Shape Centroidal Axis:') + self.Ixx = self.Ix - (self.area*self.cy*self.cy) + self.nIxx = self.Ixx*n + self.output.append(self.Ixx) + self.output_strings.append('Ixx') + self.Iyy = self.Iy - (self.area*self.cx*self.cx) + self.nIyy = self.Iyy*n + self.output.append(self.Iyy) + self.output_strings.append('Iyy') + self.Ixxyy = self.Ixy - (self.area*self.cx*self.cy) + self.nIxxyy = self.Ixxyy*n + self.output.append(self.Ixxyy) + self.output_strings.append('Ixxyy') + self.Jzz = self.Ixx + self.Iyy + self.nJzz = self.Jzz*n + self.output.append(self.Jzz) + self.output_strings.append('Jzz') + self.sxx_top = self.Ixx / abs(max(y) - self.cy) + self.output.append(self.sxx_top) + self.output_strings.append('Sxx,top') + self.sxx_bottom = self.Ixx / abs(min(y) - self.cy) + self.output.append(self.sxx_bottom) + self.output_strings.append('Sxx,bottom') + self.syy_right = self.Iyy / abs(max(x) - self.cx) + self.output.append(self.syy_right) + self.output_strings.append('Syy,right') + self.syy_left = self.Iyy / abs(min(x) - self.cx) + self.output.append(self.syy_left) + self.output_strings.append('Syy,left') + + self.rxx = math.sqrt(self.Ixx/self.area) + self.output.append(self.rxx) + self.output_strings.append('rxx') + self.ryy = math.sqrt(self.Iyy/self.area) + self.output.append(self.ryy) + self.output_strings.append('ryy') + self.rzz = math.sqrt(self.Jzz/self.area) + self.output.append(self.rzz) + self.output_strings.append('rzz') + + # Cross section principal Axis + + two_theta = math.atan2((-1*2.0*self.Ixxyy),(1E-16+(self.Ixx - self.Iyy))) + A = (self.Ixx+self.Iyy)/2.0 + B = (self.Ixx-self.Iyy)/2.0 + I1 = A+math.sqrt((B*B)+(self.Ixxyy*self.Ixxyy)) + I2 = A-math.sqrt((B*B)+(self.Ixxyy*self.Ixxyy)) + + self.output.append('--') + self.output_strings.append('Shape Principal Axis:') + self.Iuu = A+(B*math.cos(two_theta))-(self.Ixxyy*math.sin(two_theta)) + self.output.append(self.Iuu) + self.output_strings.append('Iuu') + self.Ivv = A-(B*math.cos(two_theta))+(self.Ixxyy*math.sin(two_theta)) + self.output.append(self.Ivv) + self.output_strings.append('Ivv') + self.Iuuvv = (B*math.sin(two_theta))+(self.Ixxyy*math.cos(two_theta)) + self.output.append(self.Iuuvv) + self.output_strings.append('Iuuvv') + + if (I1-1E-10)<=self.Iuu and (I1+1E-10)>=self.Iuu: + self.theta1 = math.degrees(two_theta/2.0) + self.theta2 = self.theta1 + 90.0 + else: + self.theta2 = math.degrees(two_theta/2.0) + self.theta1 = self.theta2 + 90.0 + + self.output.append(self.theta1) + self.output_strings.append('Theta1,u') + self.output.append(self.theta2) + self.output_strings.append('Theta2,v') + + # Create coordinates for the XX,YY,UU,VV axis lines + + self.xx_axis=[min(x)-1,self.cy,max(x)+1,self.cy] + self.yy_axis=[self.cx,min(y)-1,self.cx,max(y)+1] + + # UU axis coordinates + + u1 = coordinate_rotation(self.xx_axis[0],self.xx_axis[1],self.cx,self.cy,self.theta1) + u2 = coordinate_rotation(self.xx_axis[2],self.xx_axis[3],self.cx,self.cy,self.theta1) + + self.uu_axis = [u1[0],u1[1],u2[0],u2[1]] + + # VV axis coordinates + v1 = coordinate_rotation(self.xx_axis[0],self.xx_axis[1],self.cx,self.cy,self.theta2) + v2 = coordinate_rotation(self.xx_axis[2],self.xx_axis[3],self.cx,self.cy,self.theta2) + + self.vv_axis = [v1[0],v1[1],v2[0],v2[1]] + + def calc_s_at_vertices(self): + sx = [] + sy = [] + + for y in shape.y: + if y == 0: + y=0.00000000000001 + else: + pass + + sx.append(self.Ixx / abs(y - self.cy)) + + for x in shape.x: + if x == 0: + x = 0.00000000000001 + else: + pass + + sy.append(self.Iyy / abs(x - self.cx)) + + return sx, sy + + def parallel_axis_theorem(self, x, y, transformed=False): + ''' + given a new global x,y coordinate for a new + set of x, y axis return the associated Ix, Iy, and Ixy + ''' + if self.area == 0: + return [0,0,0] + else: + dx = self.cx - x + dy = self.cy - y + + if transformed: + Ix = (self.Ixx + (self.area*dy*dy))*self.n + Iy = (self.Iyy + (self.area*dx*dx))*self.n + Ixy = (self.Ixxyy + (self.area*dx*dy))*self.n + else: + Ix = self.Ixx + (self.area*dy*dy) + Iy = self.Iyy + (self.area*dx*dx) + Ixy = self.Ixxyy + (self.area*dx*dy) + + return [Ix, Iy, Ixy] + + def transformed_vertices_degrees(self, xo, yo, angle, commit=0): + ''' + given an angle in degrees + and coordinate to translate about + return the transformed values of the shape vertices + ''' + theta = math.radians(angle) + + x_tr = [(x-xo)*math.cos(theta)+(y-yo)*math.sin(theta) for x,y in zip(self.x, self.y)] + y_tr = [-1.0*(x-xo)*math.sin(theta)+(y-yo)*math.cos(theta) for x,y in zip(self.x, self.y)] + + # Commit transformation to Section + if commit == 1: + self.x = x_tr + self.y = y_tr + + self.calc_props() + else: + pass + + return [x_tr, y_tr] + + def translate_vertices(self, xo, yo, commit=0): + ''' + give an x and y translation + shift or return the shifted + shape vertices by the x and y amount + ''' + x_t = [x+xo for x in self.x] + y_t = [y+yo for y in self.y] + + # Commit the translation to the shape + if commit == 1: + self.x = x_t + self.y = y_t + + self.calc_props() + else: + pass + + return [x_t, y_t] + + def transformed_properties(self, x, y, angle): + ''' + given a new global x,y coordinate for a new + set of x, y axis and the axis angle. Return full set of transformed properties + at the new axis + + input angle as degrees + ''' + if self.area == 0: + return [0,0,0,0,0,0,0] + + else: + Ix, Iy, Ixy = self.parallel_axis_theorem(x,y) + + two_theta = 2*math.radians(angle) + # I on principal Axis + + temp = (Ix+Iy)/2.0 + temp2 = (Ix-Iy)/2.0 + + Iu = temp + temp2*math.cos(two_theta) - Ixy*math.sin(two_theta) + Iv = temp - temp2*math.cos(two_theta) + Ixy*math.sin(two_theta) + Iuv = temp2*math.sin(two_theta) + Ixy*math.cos(two_theta) + + Jw = Iu + Iv + + ru = math.sqrt(Iu/self.area) + rv = math.sqrt(Iv/self.area) + rw = math.sqrt(Jw/self.area) + + trans_coords = self.transformed_vertices(angle) + + return [Iu,Iv,Iuv,Jw,ru,rv,rw,trans_coords] + +class Composite_Section: + + def __init__(self): + + self.sections = [] + + def add_section(self, section): + + self.sections.append(section) + + def remove_section(self, section_index): + + self.sections.pop(section_index) + + def calculate_properties(self): + + # determine the global centroid location and total composite area + # cx = sum A*dx / sum A + # cy = sum A*dy / sum A + # dx = section cx + # dy = section cy + # A = section area + + self.output = [] + self.output_strings = [] + + self.area = sum([section.area for section in self.sections]) + self.transformedarea = sum([section.narea for section in self.sections]) + + self.output.append(self.area) + self.output_strings.append('Area') + + sum_A_dx = sum([section.narea*section.cx for section in self.sections]) + sum_A_dy = sum([section.narea*section.cy for section in self.sections]) + + self.cx = sum_A_dx / self.transformedarea + + self.output.append(self.cx) + self.output_strings.append('cx') + + self.cy = sum_A_dy / self.transformedarea + + self.output.append(self.cy) + self.output_strings.append('cy') + + self.output.append('--') + self.output_strings.append('Shape Centroidal Axis:') + + # determine moment of inertias about the centroid coordinates + + self.Ixx = sum([section.parallel_axis_theorem(self.cx, self.cy, transformed=True)[0] for section in self.sections]) + + self.output.append(self.Ixx) + self.output_strings.append('Ixx') + + self.Iyy = sum([section.parallel_axis_theorem(self.cx, self.cy, transformed=True)[1] for section in self.sections]) + + self.output.append(self.Iyy) + self.output_strings.append('Iyy') + + self.Ixxyy = sum([section.parallel_axis_theorem(self.cx, self.cy, transformed=True)[2] for section in self.sections]) + + self.output.append(self.Ixxyy) + self.output_strings.append('Ixxyy') + + self.Jzz = self.Ixx + self.Iyy + + self.output.append(self.Jzz) + self.output_strings.append('Jzz') + + # radii of gyration - centroidal axis + self.rxx = math.sqrt(self.Ixx/self.transformedarea) + self.output.append(self.rxx) + self.output_strings.append('rxx') + self.ryy = math.sqrt(self.Iyy/self.transformedarea) + self.output.append(self.ryy) + self.output_strings.append('ryy') + self.rzz = math.sqrt(self.Jzz/self.transformedarea) + self.output.append(self.rzz) + self.output_strings.append('rzz') + + # composite section principal Axis + + two_theta = math.atan2((-1*2.0*self.Ixxyy),(1E-16+(self.Ixx - self.Iyy))) + A = (self.Ixx+self.Iyy)/2.0 + B = (self.Ixx-self.Iyy)/2.0 + I1 = A+math.sqrt((B*B)+(self.Ixxyy*self.Ixxyy)) + I2 = A-math.sqrt((B*B)+(self.Ixxyy*self.Ixxyy)) + + self.output.append('--') + self.output_strings.append('Shape Principal Axis:') + self.Iuu = A+(B*math.cos(two_theta))-(self.Ixxyy*math.sin(two_theta)) + self.output.append(self.Iuu) + self.output_strings.append('Iuu') + self.Ivv = A-(B*math.cos(two_theta))+(self.Ixxyy*math.sin(two_theta)) + self.output.append(self.Ivv) + self.output_strings.append('Ivv') + self.Iuuvv = (B*math.sin(two_theta))+(self.Ixxyy*math.cos(two_theta)) + self.output.append(self.Iuuvv) + self.output_strings.append('Iuuvv') + + if (I1-1E-10)<=self.Iuu and (I1+1E-10)>=self.Iuu: + self.theta1 = math.degrees(two_theta/2.0) + self.theta2 = self.theta1 + 90.0 + else: + self.theta2 = math.degrees(two_theta/2.0) + self.theta1 = self.theta2 + 90.0 + + self.output.append(self.theta1) + self.output_strings.append('Theta1,u') + self.output.append(self.theta2) + self.output_strings.append('Theta2,v') + + # Create coordinates for the XX,YY,UU,VV axis lines + x = [] + y = [] + + for section in self.sections: + x.extend(section.x) + y.extend(section.y) + + # Section Moduli + self.sxx_top = self.Ixx / abs(max(y) - self.cy) + self.output.append(self.sxx_top) + self.output_strings.append('Sxx,top') + self.sxx_bottom = self.Ixx / abs(min(y) - self.cy) + self.output.append(self.sxx_bottom) + self.output_strings.append('Sxx,bottom') + self.syy_right = self.Iyy / abs(max(x) - self.cx) + self.output.append(self.syy_right) + self.output_strings.append('Syy,right') + self.syy_left = self.Iyy / abs(min(x) - self.cx) + self.output.append(self.syy_left) + self.output_strings.append('Syy,left') + + self.xx_axis=[min(x)-1,self.cy,max(x)+1,self.cy] + self.yy_axis=[self.cx,min(y)-1,self.cx,max(y)+1] + + # UU axis coordinates + + u1 = coordinate_rotation(self.xx_axis[0],self.xx_axis[1],self.cx,self.cy,self.theta1) + u2 = coordinate_rotation(self.xx_axis[2],self.xx_axis[3],self.cx,self.cy,self.theta1) + + self.uu_axis = [u1[0],u1[1],u2[0],u2[1]] + + # VV axis coordinates + v1 = coordinate_rotation(self.xx_axis[0],self.xx_axis[1],self.cx,self.cy,self.theta2) + v2 = coordinate_rotation(self.xx_axis[2],self.xx_axis[3],self.cx,self.cy,self.theta2) + + self.vv_axis = [v1[0],v1[1],v2[0],v2[1]] + + def bounding_box(self, angle): + x = [] + y = [] + + for section in self.sections: + x.extend(section.x) + y.extend(section.y) + + theta = math.radians(angle) + xo = self.cx + yo = self.cy + + xt = [(i-xo)*math.cos(theta)-(j-yo)*math.sin(theta) for i,j in zip(x,y)] + yt = [(i-xo)*math.sin(theta)+(j-yo)*math.cos(theta) for i,j in zip(x,y)] + + height = max(yt)-min(yt) + width = max(xt)-min(xt) + + return {"MinX":min(xt),"MaxX":max(xt),"MinY":min(yt),"MaxY":max(yt),"Height":height,"Width":width} + + def plastic_Zx(self, tol=1E-8, max_iters=100, baseFy = 36): + + bbox = self.bounding_box(0) + a = bbox["Height"] + b = 0 + c = b + + plastic_a = plastic_forceandmoment(self.sections,a, 0, (self.cx,self.cy)) + fa = plastic_a["C"]+plastic_a["T"] + + plastic_b = plastic_forceandmoment(self.sections,b, 0, (self.cx,self.cy)) + fb = plastic_b["C"]+plastic_b["T"] + fc = fb + i = 0 + + while (abs(fc) > tol and i <= max_iters): + c = (a+b)/2 + + plastic_c = plastic_forceandmoment(self.sections,c, 0, (self.cx,self.cy)) + fc = plastic_c["C"]+plastic_c["T"] + if fc < 0: + b = c + else: + a = c + + i += 1 + + Zx = plastic_c["M"]/baseFy + err = plastic_c["C"]+plastic_c["T"] + axis = c + + self.Zxx = {"AxisY":axis,"Zx":Zx,"C":plastic_c["C"],"T":plastic_c["T"],"Error":err,"Iterations":i,"Fy": baseFy} + + return {"AxisY":axis,"Zx":Zx,"C":plastic_c["C"],"T":plastic_c["T"],"Error":err,"Iterations":i} + + def plastic_Zy(self, tol=1E-8, max_iters=100, baseFy = 36): + + bbox = self.bounding_box(90) + a = bbox["Height"] + b = 0 + c = b + + plastic_a = plastic_forceandmoment(self.sections,a, 90, (self.cx,self.cy)) + fa = plastic_a["C"]+plastic_a["T"] + + plastic_b = plastic_forceandmoment(self.sections,b, 90, (self.cx,self.cy)) + plastic_c = plastic_b + fb = plastic_b["C"]+plastic_b["T"] + fc = fb + + i = 0 + + while (abs(fc) > tol and i <= max_iters): + c = (a+b)/2 + + plastic_c = plastic_forceandmoment(self.sections,c, 90, (self.cx,self.cy)) + fc = plastic_c["C"]+plastic_c["T"] + + if fc < 0: + b = c + else: + a = c + + i += 1 + + Zy = plastic_c["M"]/baseFy + err = plastic_c["C"]+plastic_c["T"] + axis = c + + self.Zyy = {"AxisX":axis,"Zy":Zy,"C":plastic_c["C"],"T":plastic_c["T"],"Error":err,"Iterations":i} + return {"AxisX":axis,"Zy":Zy,"C":plastic_c["C"],"T":plastic_c["T"],"Error":err,"Iterations":i} + + def plastic_Zu(self, tol=1E-8, max_iters=100, baseFy = 36): + + bbox = self.bounding_box(self.theta1) + a = bbox["Height"] + b = 0 + c = b + + plastic_a = plastic_forceandmoment(self.sections,a, self.theta1, (self.cx,self.cy)) + fa = plastic_a["C"]+plastic_a["T"] + + plastic_b = plastic_forceandmoment(self.sections,b, self.theta1, (self.cx,self.cy)) + plastic_c = plastic_b + fb = plastic_b["C"]+plastic_b["T"] + + fc = fb + + i = 0 + + while (abs(fc) > tol and i <= max_iters): + c = (a+b)/2 + + plastic_c = plastic_forceandmoment(self.sections,c, self.theta1, (self.cx,self.cy)) + fc = plastic_c["C"]+plastic_c["T"] + + if fc < 0: + b = c + else: + a = c + + i += 1 + + Zu = plastic_c["M"]/baseFy + err = plastic_c["C"]+plastic_c["T"] + axis = c + + self.Zuu = {"AxisV":axis,"Zu":Zu,"C":plastic_c["C"],"T":plastic_c["T"],"Error":err,"Iterations":i} + return {"AxisV":axis,"Zu":Zu,"C":plastic_c["C"],"T":plastic_c["T"],"Error":err,"Iterations":i} + + def plastic_Zv(self, tol=1E-8, max_iters=100, baseFy = 36): + + bbox = self.bounding_box(self.theta2) + a = bbox["Height"] + b = 0 + c = b + + plastic_a = plastic_forceandmoment(self.sections,a, self.theta2, (self.cx,self.cy)) + fa = plastic_a["C"]+plastic_a["T"] + + plastic_b = plastic_forceandmoment(self.sections,b, self.theta2, (self.cx,self.cy)) + plastic_c = plastic_b + fb = plastic_b["C"]+plastic_b["T"] + fc = fb + + i = 0 + + while (abs(fc) > tol and i <= max_iters): + c = (a+b)/2 + + plastic_c = plastic_forceandmoment(self.sections,c, self.theta2, (self.cx,self.cy)) + fc = plastic_c["C"]+plastic_c["T"] + + if fc < 0: + b = c + else: + a = c + + i += 1 + + Zv = plastic_c["M"]/baseFy + err = plastic_c["C"]+plastic_c["T"] + axis = c + + self.Zvv = {"AxisU":axis,"Zv":Zv,"C":plastic_c["C"],"T":plastic_c["T"],"Error":err,"Iterations":i} + return {"AxisU":axis,"Zv":Zv,"C":plastic_c["C"],"T":plastic_c["T"],"Error":err,"Iterations":i} + +def circle_coordinates(x,y,r,start,end): + ''' + given a center point x,y + and a radius + return the x,y coordinate list for a circle + ''' + + x_out = [] + y_out = [] + + for a in range(start,end+1): + x0 = r*math.cos(math.radians(a)) + y0 = r*math.sin(math.radians(a)) + + x_out.append(x0+x) + y_out.append(y0+y) + + return [x_out,y_out] + +def line_x_at_y(x1,y1,x2,y2,at_y): + ''' + given two points and a y coordinate + return the corresponding x coordinate + ''' + if x2 == x1: + x_out = x1 + + else: + m = (y2-y1) / (x2-x1) + + # y = mx + b + # b = y - mx + b = y1 - (m*x1) + + # y = mx+b + # x = y-b / m + if m == 0: + x_out = 0 + else: + x_out = (at_y - b) / m + + return x_out + +def dist_btwn_point_and_plane(point, xy, plane='H'): + ''' + given a point as a list = [x,y] + a plane elevation/location + a plane orientation + H = horizontal + V = vertical + + return if the the point is in front, behind, or on + the plane + ''' + + # General tolerance + tol = 1E-16 + if plane=='H': + dist = point[1] - xy + + if dist > tol: + return 'over' + elif dist < tol: + return 'under' + else: + return 'on' + + elif plane == 'V': + dist = point[0] - xy + + if dist > tol: + return 'left' + elif dist < tol: + return 'right' + else: + return 'on' + +def split_shape_above_horizontal_line(shape, line_y, solid=True, n=1): + + ''' + given a shape and horizontal line y value + return all the sub shapes above the line + + assumption: + shape has been rotated to align with the horizontal + ''' + # new shapes above + sub_shapes = [] + + if max(shape.y) < line_y: + pass + + elif min(shape.y) > line_y: + x = [i for i in shape.x] + y = [j for j in shape.y] + sub = Section(x,y,solid,n) + + sub_shapes.append(sub) + else: + + xy = [[x,y] for x,y in zip(shape.x,shape.y)] + + list_above = [] + list_below = [] + + i=0 + for point in xy: + if i == len(xy)-1: + pass + else: + p1 = point + p2 = xy[i+1] + + p1_test = dist_btwn_point_and_plane(p1, line_y,'H') + p2_test = dist_btwn_point_and_plane(p2, line_y,'H') + + if p1_test=='over' and p2_test=='over': + list_above.append(p2) + + elif p1_test=='on' and p2_test=='over': + list_above.append(p2) + + elif p1_test=='under' and p2_test=='over': + x_int = line_x_at_y(p1[0],p1[1],p2[0],p2[1],line_y) + list_above.append([x_int,line_y]) + list_above.append(p2) + list_below.append(p1) + list_below.append([x_int,line_y]) + + elif p1_test=='over' and p2_test=='on': + list_above.append(p2) + + elif p1_test=='on' and p2_test=='on': + list_above.append(p2) + + elif p1_test=='under' and p2_test=='on': + list_above.append(p2) + list_below.append(p2) + + elif p1_test=='over' and p2_test=='under': + x_int = line_x_at_y(p1[0],p1[1],p2[0],p2[1],line_y) + list_above.append([x_int,line_y]) + list_below.append([x_int,line_y]) + list_below.append(p2) + + elif p1_test=='on' and p2_test=='under': + list_below.append(p1) + list_below.append(p2) + + elif p1_test=='uder' and p2_test=='under': + list_below.append(p2) + i+=1 + + xover = [p[0] for p in list_above] + yover = [p[1] for p in list_above] + + xunder = [p[0] for p in list_below] + yunder = [p[1] for p in list_below] + + #plt.plot(xover,yover,'co') + #plt.plot(xunder, yunder,'ko') + + if solid==False: + list_above.reverse() + + int_count = 0 + xsub = [] + ysub = [] + xsub2 = [] + ysub2 = [] + + if len(list_above) >=3: + if list_above[0][1] == list_above[1][1] and list_above[0][1]==line_y: + + xsub = [p[0] for p in list_above] + ysub = [p[1] for p in list_above] + sub = Section(xsub,ysub,solid,n) + sub_shapes.append(sub) + + elif list_above[0][1] != line_y and len([1 for p in list_above if p[1]==line_y])>=2: + xsub = [p[0] for p in list_above] + ysub = [p[1] for p in list_above] + sub = Section(xsub,ysub,solid,n) + sub_shapes.append(sub) + + else: + xsub = [] + ysub = [] + xsub2 = [] + ysub2 = [] + i=0 + for point in list_above: + if list_above[0][1]!=line_y and int_count<1: + xsub2.append(point[0]) + ysub2.append(point[1]) + + else: + if int_count > 2: + xsub2.append(point[0]) + ysub2.append(point[1]) + else: + xsub.append(point[0]) + ysub.append(point[1]) + + + if point != list_above[-1]: + next_point = list_above[i+1] + prev_point = list_above[i-1] + next_point_check = next_point[1] == line_y and point[1] == line_y and next_point[0]> point[0] + prev_point_check = prev_point[1] == line_y and point[1] >= prev_point[1] and next_point[1] > point[1] + if prev_point_check == True: + int_count = 0 + else: + next_point_check = False + prev_point_check = False + + if point[1] == line_y: + int_count +=1 + + if int_count >= 2 and len(xsub)>2 and list_above[0][1]==line_y and next_point_check==False: + sub = Section(xsub,ysub,solid,n) + int_count = 0 + xsub = [] + ysub = [] + + sub_shapes.append(sub) + + elif point == list_above[-1] and len(xsub)>2: + sub = Section(xsub,ysub,solid,n) + int_count = 0 + xsub = [] + ysub = [] + + sub_shapes.append(sub) + + i+=1 + + if len(xsub2)>2: + sub = Section(xsub2,ysub2,solid,n) + int_count = 0 + xsub = [] + ysub = [] + + sub_shapes.append(sub) + + + return sub_shapes + +def stl_wf(d,bf,tf,tw,k, Fy=50, E=29000): + ''' + given the defining geometric + properties for a Wide Flange from + AISC + + return a Shape with appropriate + coordinates + 0,0 point will be the bottom left of the section + ''' + + # Bottom flange + x = [0,bf,bf] + y = [0,0,tf] + + # points in bottom right radius angle range is 270,180 + cr1x = (bf/2.0)+(tw/2.0)+(k-tf) + cr1y = k + + # draw circle for radius in clockwise order then reverse it + # for the first radius + r=k-tf + x_r1, y_r1 = circle_coordinates(cr1x,cr1y,r,180,270) + + x_r1.reverse() + y_r1.reverse() + + x.extend(x_r1) + y.extend(y_r1) + + # points in top right radius angle range is 180,90 + cr2x = cr1x + cr2y = d-k + + # draw circle for radius in clockwise order then reverse it + # for the first radius + x_r2, y_r2 = circle_coordinates(cr2x,cr2y,r,90,180) + + x_r2.reverse() + y_r2.reverse() + + x.extend(x_r2) + y.extend(y_r2) + + # top flange + x.extend([bf,bf,0,0]) + y.extend([d-tf,d,d,d-tf]) + + # points in top left radius angle range is 90,0 + cr3x = (bf/2.0)-(tw/2.0)-(k-tf) + cr3y = d-k + + # draw circle for radius in clockwise order then reverse it + # for the first radius + x_r3, y_r3 = circle_coordinates(cr3x,cr3y,r,0,90) + + x_r3.reverse() + y_r3.reverse() + + x.extend(x_r3) + y.extend(y_r3) + + # points in bottom left radius angle range is 360,270 + cr4x = cr3x + cr4y = k + + # draw circle for radius in clockwise order then reverse it + # for the first radius + x_r4, y_r4 = circle_coordinates(cr4x,cr4y,r,270,360) + + x_r4.reverse() + y_r4.reverse() + + x.extend(x_r4) + y.extend(y_r4) + + # Last points to close the bottom flange + x.extend([0,0]) + y.extend([tf,0]) + + WF = Section(x,y, Fy=Fy, E=E) + + return WF + +def stl_angle(vleg, hleg, thickness, k): + ''' + given the defining geometric + properties for an Angle from + AISC + + return a Shape with appropriate + coordinates + 0,0 point will be the bottom left of the section + ''' + r1 = k - thickness # leg-to-leg Fillet + r2 = r1/2.0 # toe fillet 1/2*Fillet per ISO 657-1: 1989 (E) + + # Bottom horizontal leg + x = [0,hleg,hleg] + y = [0,0,thickness - r2] + + # outisde horizontal leg fillet + # for the first radius + r=r2 + x_r1, y_r1 = circle_coordinates(hleg-(r2),thickness - r2,r,1,90) + + x.extend(x_r1) + y.extend(y_r1) + + # horizontal top flat + x.append(k) + y.append(thickness) + + #interior corner radii + r = r1 + x_r1, y_r1 = circle_coordinates(k,k,r,180,269) + + x_r1.reverse() + y_r1.reverse() + + x.extend(x_r1) + y.extend(y_r1) + + # vertical inside flat + x.append(thickness) + y.append(vleg - r2) + + # outside vertical leg fillet + r=r2 + x_r1, y_r1 = circle_coordinates(thickness - r2,vleg-(r2),r,1,90) + + x.extend(x_r1) + y.extend(y_r1) + + x.append(0) + y.append(vleg) + + x.append(0) + y.append(0) + + Angle = Section(x,y) + + return Angle + +def plastic_forceandmoment(shapes, axis_depth, rotation, rotation_point, log=False): + ''' + shapes = list of cross sections, list + axis_depth = depth of plastic axis from maximum y coordinate of shapes, float + rotation = counterclockwise rotation to the axis considered, float + rotation_point = center point of the rotation, typically the centroid, tuple + ''' + # Log + loglist = [] + + #if rotation == 0: + # log = True + + # Generate Segments + segments = [] + fy = [] + T = 0 + C = 0 + Maxis = 0 + + x0 = rotation_point[0] + y0 = rotation_point[1] + + for shape in shapes: + shape_segments = shape.transformed_segments(x0,y0,rotation) + shape_fy = [shape.Fy]*len(shape_segments) + segments.extend(shape_segments) + fy.extend(shape_fy) + + # Agregate Y coordinates + y = [] + + for segment in segments: + y.extend([segment[0][1],segment[1][1]]) + + axis = max(y) - axis_depth + + for i,segment in enumerate(segments): + + x1 = segment[0][0] + y1 = segment[0][1] + x2 = segment[1][0] + y2 = segment[1][1] + f = fy[i] + + if y1 < axis and y2< axis: + # segment is below the axis + # Opposite sign for Axial and Moment + axial = -1*0.5*f*(x1+x2)*(y1-y2) + T += (-1*axial) + + moment = (1/6.0)*f*(y2-y1)*((x1*((2*y1)+y2))+(x2*(y1+(2*y2)))) + Maxis += (-1*moment) + + if log: + loglist.append(['below axis -- T',f'Axial:{axial}',f'Moment:{moment}',f'({x1},{y1}) ({x2},{y2})',f'C:{C}',f'T:{T}']) + + elif y1 >= axis and y2 >= axis: + # Segment is entirely above the axis + # Standard sign for Axial and Moment + axial = -1*0.5*f*(x1+x2)*(y1-y2) + C += axial + + moment = (1/6.0)*f*(y2-y1)*((x1*((2*y1)+y2))+(x2*(y1+(2*y2)))) + Maxis += moment + + if log: + loglist.append(['above or on axis -- C',f'Axial:{axial}',f'Moment:{moment}',f'({x1},{y1}) ({x2},{y2})',f'C:{C}',f'T:{T}']) + + else: + # Axis bisects the segment + # Using parametric formula generate two new segments + + # y(t) = y1 + t (y2 - y1) + # t = (axis - y1) / (y2-y1) + + t = (axis - y1)/(y2-y1) + + x3 = x1 + (t*(x2-x1)) + y3 = axis + + if y1 < axis: + # First Segment is below axis + axialt = -1*0.5*f*(x1+x3)*(y1-y3) + T += (-1*axialt) + + momentt = (1/6.0)*f*(y3-y1)*((x1*((2*y1)+y3))+(x3*(y1+(2*y3)))) + Maxis += (-1*momentt) + + # Second Segment is above axis + axialc = -1*0.5*f*(x3+x2)*(y3-y2) + C += axialc + + momentc = (1/6.0)*f*(y2-y3)*((x3*((2*y3)+y2))+(x2*(y3+(2*y2)))) + Maxis += momentc + + if log: + loglist.append(['axis bisected -- y1 below axis' + ,f'Axial-T:{axialt}' + ,f'Moment-T:{momentt}' + ,f'Axial-C:{axialc}' + ,f'Moment-C:{momentc}' + ,f't:{t}' + ,f'({x1},{y1}) ({x2},{y2})' + ,f'point at t: ({x3},{y3})' + ,f'C:{C}',f'T:{T}']) + else: + # First Segment is above axis + axialc = -1*0.5*f*(x1+x3)*(y1-y3) + C += axialc + + momentt = (1/6.0)*f*(y3-y1)*((x1*((2*y1)+y3))+(x3*(y1+(2*y3)))) + Maxis += momentt + + # Second Segment is below axis + axialt = -1*0.5*f*(x3+x2)*(y3-y2) + T += (-1*axialt) + + momentc = (1/6.0)*f*(y2-y3)*((x3*((2*y3)+y2))+(x2*(y3+(2*y2)))) + Maxis += (-1*momentc) + + if log: + loglist.append(['axis bisected -- y1 above or on axis' + ,f'Axial-T:{axialt}' + ,f'Moment-T:{momentt}' + ,f'Axial-C:{axialc}' + ,f'Moment-C:{momentc}' + ,f't:{t}' + ,f'({x1},{y1}) ({x2},{y2})' + ,f'point at t: ({x3},{y3})' + ,f'C:{C}',f'T:{T}']) + + if log: + print(loglist) + + return {"C":C,"T":T,"M":Maxis} + +### TEST AREA ### + + + diff --git a/Analysis/shear_deflection_testing.py b/Analysis/shear_deflection_testing.py new file mode 100644 index 0000000..43777cc --- /dev/null +++ b/Analysis/shear_deflection_testing.py @@ -0,0 +1,104 @@ +from __future__ import division +import math +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation + +import TimoshenkoFormulas as timobm +import pin_pin_beam_equations_classes as ebbm + +# Properties for a W36x135 +E_ksi = 29000 +G_ksi = 11200 +kA_in2 = 21.36 +I_in4 = 7800 + +# Span Info +L_ft = 25 +a_ft = 12.5 +M_ftkips = 1000.0 + +#convert G and E to ksf +G_ksf = G_ksi*144.0 +E_ksf = E_ksi*144.0 + +#convert kA to ft^2 +kA_ft2 = kA_in2 * (1/144.0) + +#convert I to ft^4 +I_ft4 = I_in4 / math.pow(12,4) + +step = L_ft/20.0 + +x = [0+(i*step) for i in range(21)] +bm = [0 for i in x] + +M_timo = timobm.PointLoad(M_ftkips,a_ft,L_ft,E_ksf,I_ft4,G_ksf,kA_ft2) + +M_ebb = ebbm.pl(M_ftkips,a_ft,L_ft) + +theta_timo = [-1.0*M_timo.thetax(i) for i in x] + +theta_ebb = [M_ebb.eisx(i)/(E_ksf*I_ft4) for i in x] + +tol = 1e-15 + +theta_dif = [i-y if abs(i-y) > abs(tol) else 0 for i,y in zip(theta_timo,theta_ebb)] + +delta_timo = [-12.0*M_timo.deltax(i) for i in x] + +delta_ebb = [12.0*M_ebb.eidx(i)/(E_ksf*I_ft4) for i in x] + +delta_dif = [i-y if abs(i-y) > abs(tol) else 0 for i,y in zip(delta_timo,delta_ebb)] + +c1 = M_timo.c1 +c2 = M_timo.c2 +c3 = M_timo.c3 +c4 = M_timo.c4 + +ax1 = plt.subplot2grid((3,3),(1,0)) +ax2 = plt.subplot2grid((3,3),(2,0)) +ax3 = plt.subplot2grid((3,3),(1,1)) +ax4 = plt.subplot2grid((3,3),(2,1)) +ax5 = plt.subplot2grid((3,3),(1,2)) +ax6 = plt.subplot2grid((3,3),(2,2)) +ax7 = plt.subplot2grid((3,3),(0,0)) +ax8 = plt.subplot2grid((3,3),(0,1)) +ax9 = plt.subplot2grid((3,3),(0,2)) + +ax1.plot(x,theta_ebb) +ax2.plot(x,delta_ebb) +ax3.plot(x,theta_timo) +ax4.plot(x,delta_timo) +ax5.plot(x,theta_dif) +ax6.plot(x,delta_dif) +ax7.plot(x,bm) +ax8.plot(x,bm) +ax9.plot(x,bm) + +theta_timo_norm = [(i)/max((max(theta_timo), abs(min(theta_timo))))*1.25 if max((max(theta_timo), abs(min(theta_timo)))) != 0 else 0 for i in theta_timo] +theta_ebb_norm = [(i)/max((max(theta_ebb), abs(min(theta_ebb))))*1.25 if max((max(theta_ebb), abs(min(theta_ebb)))) != 0 else 0 for i in theta_ebb] +theta_dif_norm = [(i)/max((max(theta_dif), abs(min(theta_dif))))*1.25 if max((max(theta_dif), abs(min(theta_dif)))) !=0 else 0 for i in theta_dif] + +for i,y in enumerate(x): + + h = 0.5 + + xs_timo = [y+(theta_timo_norm[i]*h), y-(theta_timo_norm[i]*h)] + xs_ebb = [y+(theta_ebb_norm[i]*h), y-(theta_ebb_norm[i]*h)] + xs_dif = [y+(theta_dif_norm[i]*h), y-(theta_dif_norm[i]*h)] + + ys = [-h,h] + + ax7.plot(xs_ebb,[-h,h],'r') + ax8.plot(xs_timo,[-h,h],'r') + ax9.plot(xs_dif,[-h,h],'r') + + +ax7.set_ylim([-1,1]) +ax8.set_ylim([-1,1]) +ax9.set_ylim([-1,1]) + +plt.tight_layout() + +plt.show() \ No newline at end of file diff --git a/Analysis/shear_delta_eng-tips.py b/Analysis/shear_delta_eng-tips.py new file mode 100644 index 0000000..c6e0069 --- /dev/null +++ b/Analysis/shear_delta_eng-tips.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +""" +Created on Mon May 13 16:43:13 2019 + +@author: DonB +""" + +from __future__ import division +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation + + +def point_shear_delta(P_kips,a_ft,L_ft,x_ft,G_ksi,kA_in2): + + #Reaction + RL_kips = P_kips*(L_ft-a_ft)*(1/L_ft) + RR_kips = P_kips - RL_kips + #convert G to ksf + G_ksf = G_ksi*144.0 + + #convert kA to ft^2 + kA_ft2 = kA_in2 * (1/144.0) + + C4 = P_kips*a_ft / (kA_ft2*G_ksf) + + if x_ft <= a_ft: + delta_ft = (RL_kips*x_ft) / (kA_ft2*G_ksf) + + else: + delta_ft = ((-1.0*RR_kips*x_ft) / (kA_ft2*G_ksf)) + C4 + + delta_in = 12.0*delta_ft + + return delta_in + +def animation_step(frame,p,L,x,x_rev,g,ka, ret): + + a_front = x[frame] + + a_back = x_rev[frame] + + delta_front = [point_shear_delta(p,a_front,L,i,g,ka) for i in x] + delta_back = [point_shear_delta(-p,a_back,L,i,g,ka) for i in x] + + delta = [i+y for i,y in zip(delta_front, delta_back)] + + l1.set_data(x, delta) + l2.set_data([a_front,a_front],[0,-0.9]) + l3.set_data([a_back,a_back],[0,0.9]) + +def animation_step_amp(frame,p,L,x,x_rev,g,ka, ret): + + if x_rev[frame] == x[frame]: + multi=1 + else: + L_prime = x_rev[frame] - x[frame] + multi = L/L_prime + + a_front = x[frame] + a_back = x_rev[frame] + + delta_front = [point_shear_delta(p*multi,a_front,L,i,g,ka) for i in x] + delta_back = [point_shear_delta(-p*multi,a_back,L,i,g,ka) for i in x] + + delta = [i+y for i,y in zip(delta_front, delta_back)] + + l1.set_data(x, delta) + l2.set_data([a_front,a_front],[0,-0.9]) + l3.set_data([a_back,a_back],[0,0.9]) + +G_ksi = 11200 +kA_in2 = 21.36 +L_ft = 5 +a_ft = 2.5 +P_kips = 1000.0 +x_ft = 2.5 + +step = L_ft/100.0 + +x = [0+(i*step) for i in range(101)] +x_rev = x[::-1] + +bm = [0]*len(x) + +fig, ax = plt.subplots() + +ax.set_xlim(-1,6) +ax.set_ylim(-0.12,0.12) +ax.plot(x,bm) + +l1, = ax.plot([],[],'g') +l2, = ax.plot([],[],'r') +l3, = ax.plot([],[],'b') + +ani = animation.FuncAnimation(fig, animation_step_amp, frames = np.arange(0,100), fargs=(P_kips,L_ft,x,x_rev,G_ksi,kA_in2,0), interval=100) + +plt.rcParams["animation.convert_path"] = "C:\Program Files\ImageMagick-7.0.7-Q16\magick.exe" + +ani.save("eng-tips_collapsing_point_loads_amped.gif",writer="imagemagick", extra_args="convert") + +plt.show() + + + diff --git a/Analysis/simple_beam.py b/Analysis/simple_beam.py index 05e5cb0..e896f4d 100644 --- a/Analysis/simple_beam.py +++ b/Analysis/simple_beam.py @@ -1,18 +1,28 @@ -# -*- coding: utf-8 -*- - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import Tkinter as tk @@ -26,57 +36,64 @@ import os import webbrowser import tkMessageBox -# import matplotlib.pyplot as plt +import tkFileDialog class Master_window: def __init__(self, master): - + self.master = master - + + self.inputs = [] + self.loads_scale = [0.0001] self.load_last_add = [] - + self.extra_reactions = [] + self.end_moments = [] + self.reaction_left = 0 self.reaction_right = 0 - + self.shearl = zeros(501) self.shearc = zeros(501) self.shearr = zeros(501) - + self.momentl = zeros(501) self.momentc = zeros(501) self.momentr = zeros(501) - + self.slopel = zeros(501) self.slopec = zeros(501) self.sloper = zeros(501) - + self.deltal = zeros(501) self.deltac = zeros(501) self.deltar = zeros(501) - - self.f_size = 8 + + self.f_size = 10 helv = tkFont.Font(family='Helvetica',size=self.f_size, weight='bold') helv_res = tkFont.Font(family='Helvetica',size=self.f_size, weight='bold', underline = True) - + self.menubar = tk.Menu(self.master) self.menu = tk.Menu(self.menubar, tearoff=0) self.menu_props = tk.Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label = "File", menu=self.menu) + self.menu.add_command(label="Save", command=self.save_inputs) + self.menu.add_command(label="Open", command=self.open_existing) + self.menu.add_separator() self.menu.add_command(label="Quit", command=self.quit_app) try: self.master.config(menu=self.menubar) except AttributeError: self.master.tk.call(master, "config", "-menu", self.menubar) - + #Main Frames self.base_frame = tk.Frame(master, bd=2, relief='sunken', padx=1,pady=1) self.base_frame.pack(side=tk.BOTTOM, padx= 1, pady= 1, fill=tk.X) self.main_frame = tk.Frame(master, bd=2, relief='sunken', padx=1,pady=1) self.main_frame.pack(anchor='c', padx= 1, pady= 1, fill=tk.BOTH, expand=1) - + #Beam Canvas self.beam_canvas_frame = tk.Frame(self.main_frame, bd=2, relief='sunken', padx=1,pady=1) self.bm_canvas = tk.Canvas(self.beam_canvas_frame, width=750, height=200, bd=2, relief='sunken', background="black") @@ -84,17 +101,17 @@ def __init__(self, master): self.bm_canvas.bind("", self.draw_static_beam_mouse) self.bm_canvas.bind("", self.draw_static_beam_mouse) self.bm_canvas.pack(side = tk.LEFT, anchor='c', padx= 1, pady= 1, fill=tk.BOTH, expand=1) - + self.val_at_x = self.bm_canvas.create_line(0, 0,0,0,fill="gray90", width=1, dash=(4,4)) self.val_at_x_text = self.bm_canvas.create_line(0, 0,0,0,fill="gray90", width=1, dash=(4,4)) - + self.beam_canvas_frame.pack(side=tk.TOP, anchor='c', padx= 1, pady= 1, fill=tk.BOTH, expand=1) - + self.graph_b_frame = tk.Frame(self.beam_canvas_frame, bd=2, relief='sunken', padx=4 ,pady=1) - + self.show_l = tk.IntVar() self.show_l.set(1) - tk.Checkbutton(self.graph_b_frame, text=' : Show Loads', variable=self.show_l, command = self.bm_canvas_draw, font=helv).grid(row=1, column=1, sticky = tk.W) + tk.Checkbutton(self.graph_b_frame, text=' : Show Loads', variable=self.show_l, command = self.bm_canvas_draw, font=helv).grid(row=1, column=1, sticky = tk.W) self.show_v = tk.IntVar() tk.Checkbutton(self.graph_b_frame, text=' : Show V', variable=self.show_v, command = self.bm_canvas_draw, font=helv).grid(row=2, column=1, sticky = tk.W) self.show_m = tk.IntVar() @@ -110,72 +127,80 @@ def __init__(self, master): self.show_m_tension = tk.IntVar() self.show_m_tension.set(1) tk.Checkbutton(self.graph_b_frame, text=' : Show M on\ntension face', variable=self.show_m_tension, command = self.bm_canvas_draw, font=helv).grid(row=8, column=1, sticky = tk.W) - + self.graph_b_frame.pack(side=tk.RIGHT, anchor='e') - + self.nb = ttk.Notebook(self.main_frame) self.nb.pack(anchor='c', padx= 1, pady= 1, fill=tk.BOTH, expand=1) - + #Tab 1 - Span Data self.page1 = ttk.Frame(self.nb) self.nb.add(self.page1, text='Span Information') - + self.pg1_frame = tk.Frame(self.page1, bd=2, relief='sunken', padx=1,pady=1) - + self.bm_info_frame = tk.Frame(self.pg1_frame, bd=2, relief='sunken', padx=2,pady=1) - + tk.Label(self.bm_info_frame, text="Left Cantilever (ft):", font=helv).grid(row=1,column=1, sticky = tk.E) tk.Label(self.bm_info_frame, text="Center Span (ft):", font=helv).grid(row=2,column=1, sticky = tk.E) tk.Label(self.bm_info_frame, text="Right Cantilever (ft):", font=helv).grid(row=3,column=1, sticky = tk.E) - - self.left_cant_ft = tk.StringVar() + + self.left_cant_ft = tk.StringVar() + self.inputs.append(self.left_cant_ft) self.span_ft = tk.StringVar() + self.inputs.append(self.span_ft) self.right_cant_ft = tk.StringVar() - + self.inputs.append(self.right_cant_ft) + self.left_cant_ft.set(0.0) self.span_ft.set(10.0) self.right_cant_ft.set(0.0) - + self.left_cant_entry = tk.Entry(self.bm_info_frame, textvariable=self.left_cant_ft, width=10) self.left_cant_entry.grid(row=1,column=2, sticky = tk.W) self.span_entry = tk.Entry(self.bm_info_frame, textvariable=self.span_ft, width=10) self.span_entry.grid(row=2,column=2, sticky = tk.W) self.right_cant_entry = tk.Entry(self.bm_info_frame, textvariable=self.right_cant_ft, width=10) self.right_cant_entry.grid(row=3,column=2, sticky = tk.W) - + tk.Label(self.bm_info_frame, text="E (ksi):", font=helv).grid(row=4,column=1, sticky = tk.E) tk.Label(self.bm_info_frame, text="I (in^4):", font=helv).grid(row=5,column=1, sticky = tk.E) - - self.E_ksi = tk.StringVar() + + self.E_ksi = tk.StringVar() + self.inputs.append(self.E_ksi) self.I_in4 = tk.StringVar() - + self.inputs.append(self.I_in4) + self.E_ksi.set(29000) self.I_in4.set(30.8) - + self.E_entry = tk.Entry(self.bm_info_frame, textvariable=self.E_ksi, width=10) self.E_entry.grid(row=4,column=2, sticky = tk.W) self.I_entry = tk.Entry(self.bm_info_frame, textvariable=self.I_in4, width=10) self.I_entry.grid(row=5,column=2, sticky = tk.W) - + + tk.Label(self.bm_info_frame, text="Stations:", font=helv).grid(row=6,column=1, sticky = tk.E) - self.stations = tk.Spinbox(self.bm_info_frame, values=(4, 10, 20, 25, 50, 100, 200, 500, 1000), command=self.run) - self.stations.grid(row=6, column=2) + self.stations = tk.StringVar() + self.inputs.append(self.stations) + self.stations_sb= tk.Spinbox(self.bm_info_frame, values=(4, 10, 20, 25, 50, 100, 200, 500, 1000), textvariable=self.stations, command=self.run) + self.stations_sb.grid(row=6, column=2) + - self.b_run = tk.Button(self.bm_info_frame,text = "Update", command = self.update, font=helv) - self.b_run.grid(row=1,column=3, sticky = tk.W) - - self.bm_info_frame.pack(side=tk.LEFT, anchor='nw', padx=4 ,pady=1) - + self.b_run.grid(row=1,column=3, sticky = tk.W) + + self.bm_info_frame.pack(side=tk.LEFT, anchor='nw', padx=4 ,pady=1) + self.res_frame = tk.Frame(self.pg1_frame, bd=2, relief='sunken', padx=4 ,pady=1) - + self.res_labels = [] self.res_list = ['Results:','--','--','Cant. Left:','--','--','--','--','Center Span:','--','--','--','--','Cant. Right:','--','--','--','--'] label_fonts = [helv_res,helv,helv,helv_res,helv,helv,helv,helv,helv_res,helv,helv,helv,helv,helv_res,helv,helv,helv,helv] for i in range(0,18): self.res_labels.append(tk.Label(self.res_frame, text= self.res_list[i], font=label_fonts[i])) self.res_labels[i].grid(row=i+1,column=1, sticky = tk.W) - + self.resx_label = tk.Label(self.res_frame, text="x = ", font=helv) self.resx_label.grid(row=1,column=2) self.resx_var = tk.StringVar() @@ -183,47 +208,50 @@ def __init__(self, master): self.resx_entry = tk.Entry(self.res_frame, textvariable = self.resx_var, width=10) self.resx_entry.grid(row=1, column=3) tk.Label(self.res_frame, text = ' ft', font=helv).grid(row=1, column=4) - + self.b_runx = tk.Button(self.res_frame, text="Res. @ X", command = self.runx, font=helv) self.b_runx.grid(row=1, column=4) - + self.resx_labels = [] self.resx_list = ['Results @ x :','Cant. Left:','--','--','--','--','Center Span:','--','--','--','--','Cant. Right:','--','--','--','--'] label_fontsx = [helv_res,helv_res,helv,helv,helv,helv,helv_res,helv,helv,helv,helv,helv_res,helv,helv,helv,helv] for i in range(0,16): self.resx_labels.append(tk.Label(self.res_frame, text= self.resx_list[i], font=label_fontsx[i])) self.resx_labels[i].grid(row=i+2,column=3, sticky = tk.W) - + self.res_frame.pack(side=tk.LEFT, anchor='nw', padx=4 ,pady=1) - + self.res_calc_multi_frame = tk.Frame(self.pg1_frame, bd=2, relief='sunken', padx=4 ,pady=1) - + self.fixed_left = tk.IntVar() + self.inputs.append(self.fixed_left) self.fixed_left_check = tk.Checkbutton(self.res_calc_multi_frame , text=' : Fixed Left', variable=self.fixed_left, font=helv) self.fixed_left_check.grid(row=0, column=0, sticky = tk.W) - + self.fixed_right = tk.IntVar() + self.inputs.append(self.fixed_right) self.fixed_right_check = tk.Checkbutton(self.res_calc_multi_frame , text=' : Fixed Right', variable=self.fixed_right, font=helv) self.fixed_right_check.grid(row=0, column=2, sticky = tk.W) - + tk.Label(self.res_calc_multi_frame, text = 'Support Locations (ft):\nex. 10,20,30,...,Xi', font=helv).grid(row=1, column=0, columnspan= 3) self.internal_supports = tk.StringVar() + self.inputs.append(self.internal_supports) tk.Entry(self.res_calc_multi_frame, textvariable = self.internal_supports, width=40).grid(row=2, column=0, columnspan= 3) - + self.b_solve_multi = tk.Button(self.res_calc_multi_frame, text='Solve Fixed End and Interior Reactions', command = self.multi_solve, font=helv) self.b_solve_multi.grid(row=3, column=0, columnspan= 3) - + self.multi_result_label = tk.Label(self.res_calc_multi_frame, text = 'Mo = --\nML = --', font=helv) self.multi_result_label.grid(row=4, column=0, columnspan= 3) - + self.b_moment_area = tk.Button(self.res_calc_multi_frame, text="Area of Moment Curve and Centroid", command = self.moment_area, font=helv) self.b_moment_area.grid(row=5, column=0, columnspan=3) - + self.moment_area_label = tk.Label(self.res_calc_multi_frame, text= '-- ft-kips\n-- ft-kips', font=helv_res) self.moment_area_label.grid(row=6, column=0, columnspan=3) - + self.res_calc_multi_frame.pack(side=tk.LEFT, anchor='nw', padx=4 ,pady=1) - + self.pg1_frame.pack(anchor='c', padx= 1, pady= 1, fill=tk.BOTH, expand=1) #Tab 2 - Loads @@ -231,9 +259,9 @@ def __init__(self, master): self.nb.add(self.page2, text='Loads') self.pg2_frame = tk.Frame(self.page2, bd=2, relief='sunken', padx=1,pady=1) - + self.add_loads_frame = tk.Frame(self.pg2_frame, bd=2, relief='sunken', padx=4,pady=4) - + tk.Label(self.add_loads_frame, text="Add Loads:", font=helv).grid(row=1,column=1, sticky = tk.W) tk.Label(self.add_loads_frame, text="P,M,W1\n(kips, ft-kips, klf):", font=helv).grid(row=2,column=1, sticky = tk.W) tk.Label(self.add_loads_frame, text="W2\n(kips, ft-kips, klf):", font=helv).grid(row=2,column=2, sticky = tk.W) @@ -241,75 +269,75 @@ def __init__(self, master): tk.Label(self.add_loads_frame, text="b (ft):", font=helv).grid(row=2,column=4, sticky = tk.W) tk.Label(self.add_loads_frame, text="Load Type:", font=helv).grid(row=2,column=5, sticky = tk.W) tk.Label(self.add_loads_frame, text="Load Location:", font=helv).grid(row=2,column=6, sticky = tk.W) - - self.w1_gui = tk.StringVar() - self.w2_gui = tk.StringVar() - self.a_gui = tk.StringVar() + + self.w1_gui = tk.StringVar() + self.w2_gui = tk.StringVar() + self.a_gui = tk.StringVar() self.b_gui = tk.StringVar() - + self.w1_gui.set(0) self.w2_gui.set(0) - self.a_gui.set(0) + self.a_gui.set(0) self.b_gui.set(0) - + self.w1_gui_entry = tk.Entry(self.add_loads_frame, textvariable=self.w1_gui, width=10) self.w1_gui_entry.grid(row=3,column=1, sticky = tk.W) self.w2_gui_entry = tk.Entry(self.add_loads_frame, textvariable=self.w2_gui, width=10) self.w2_gui_entry.grid(row=3,column=2, sticky = tk.W) self.a_gui_entry = tk.Entry(self.add_loads_frame, textvariable=self.a_gui, width=10) self.a_gui_entry.grid(row=3,column=3, sticky = tk.W) - self.b_gui_entry = tk.Entry(self.add_loads_frame, textvariable=self.b_gui, width=10) + self.b_gui_entry = tk.Entry(self.add_loads_frame, textvariable=self.b_gui, width=10) self.b_gui_entry.grid(row=3,column=4, sticky = tk.W) self.load_type = tk.StringVar() self.load_type.set('Point') load_types = ['Point','Moment','UDL','TRAP'] self.load_type_selection = tk.OptionMenu(self.add_loads_frame, self.load_type, *load_types) self.load_type_selection.grid(row=3,column=5, sticky = tk.W) - + self.load_loc = tk.StringVar() self.load_loc.set('Center') load_locals = ['Left','Center','Right'] self.load_loc_selection = tk.OptionMenu(self.add_loads_frame, self.load_loc, *load_locals) self.load_loc_selection.grid(row=3,column=6, sticky = tk.W) - + self.b_add_load = tk.Button(self.add_loads_frame,text = "Add New Load", command = self.add_load, font=helv) - self.b_add_load.grid(row=3, column=7, sticky = tk.W) - + self.b_add_load.grid(row=3, column=7, sticky = tk.W) + self.b_remove_load = tk.Button(self.add_loads_frame,text = "Remove Unchecked Loads", command = self.remove_load, font=helv) self.b_remove_load.grid(row=3, column=8, sticky = tk.W) - + self.add_loads_frame.pack(anchor="nw", padx= 4, pady= 4) - + self.loads_scroll_frame = tk.Frame(self.pg2_frame, bd=2, relief='sunken', padx=4,pady=4) self.loads_scrollbar = tk.Scrollbar(self.loads_scroll_frame, orient="vertical") - self.loads_canvas = tk.Canvas(self.loads_scroll_frame, bd=1, scrollregion=(0,0,200,200)) - + self.loads_canvas = tk.Canvas(self.loads_scroll_frame, bd=1, scrollregion=(0,0,100,100)) + self.loads_frame = tk.Frame(self.loads_canvas, bd=2, relief='sunken', padx=4,pady=4) - + self.loads_gui_select_var = [] self.loads_gui = [] - + tk.Label(self.loads_frame, text="Use/Delete", font=helv_res).grid(row=0, column=1) tk.Label(self.loads_frame, text="P, M, or w1 (klf)", font=helv_res).grid(row=0, column=2) - tk.Label(self.loads_frame, text="w2 (klf)", font=helv_res).grid(row=0, column=3) - tk.Label(self.loads_frame, text="a (ft)", font=helv_res).grid(row=0, column=4) - tk.Label(self.loads_frame, text="b (ft)", font=helv_res).grid(row=0, column=5) - tk.Label(self.loads_frame, text="Span", font=helv_res).grid(row=0, column=6) - tk.Label(self.loads_frame, text="Type", font=helv_res).grid(row=0, column=7) - + tk.Label(self.loads_frame, text="w2 (klf)", font=helv_res).grid(row=0, column=3) + tk.Label(self.loads_frame, text="a (ft)", font=helv_res).grid(row=0, column=4) + tk.Label(self.loads_frame, text="b (ft)", font=helv_res).grid(row=0, column=5) + tk.Label(self.loads_frame, text="Span", font=helv_res).grid(row=0, column=6) + tk.Label(self.loads_frame, text="Type", font=helv_res).grid(row=0, column=7) + self.loads_frame.pack(anchor="nw", fill=tk.BOTH, expand=1) - + self.loads_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.loads_scrollbar.pack(side=tk.LEFT, fill=tk.Y, expand=tk.FALSE) self.loads_scroll_frame.pack(anchor="nw", padx= 4, pady= 4, fill=tk.BOTH, expand=1) - + self.loads_canvas.configure(yscrollcommand=self.loads_scrollbar.set) self.loads_scrollbar.configure(command=self.loads_canvas.yview) self.loads_canvas.create_window(0,0,window=self.loads_frame, anchor=tk.NW) self.loads_canvas.configure(scrollregion=(0,0,1000,1000)) - + self.loads_frame.bind("", self.ScrollFrameConfig) - + self.pg2_frame.pack(anchor='c', padx= 1, pady= 1, fill=tk.BOTH, expand=1) #Tab 3 - Detailed Results @@ -321,11 +349,11 @@ def __init__(self, master): self.nb_res = ttk.Notebook(self.pg3_frame) self.nb_res.pack(anchor='c', padx= 1, pady= 1, fill=tk.BOTH, expand=1) - + self.l_res_tab = ttk.Frame(self.nb_res) - self.nb_res.add(self.l_res_tab, text='Left Results') + self.nb_res.add(self.l_res_tab, text='Left Results') - self.res_l_frame = tk.Frame(self.l_res_tab, bd=2, relief='sunken', padx=1,pady=1) + self.res_l_frame = tk.Frame(self.l_res_tab, bd=2, relief='sunken', padx=1,pady=1) tk.Label(self.res_l_frame, text="X (ft)", font=helv_res).grid(row=0, column=1) tk.Label(self.res_l_frame, text="V (Kips)", font=helv_res).grid(row=0, column=2) tk.Label(self.res_l_frame, text="M (ft-Kips)", font=helv_res).grid(row=0, column=3) @@ -345,13 +373,13 @@ def __init__(self, master): self.ls_listbox.grid(row=1, column=4) self.ld_listbox = tk.Listbox(self.res_l_frame, height = 20, width = 16, font=helv, yscrollcommand=self.results_scrollbar_l.set) self.ld_listbox.grid(row=1, column=5) - + self.res_l_frame.pack(anchor='c', padx= 1, pady= 1, fill=tk.BOTH, expand=1) self.c_res_tab = ttk.Frame(self.nb_res) self.nb_res.add(self.c_res_tab, text='Center Results') - self.res_c_frame = tk.Frame(self.c_res_tab, bd=2, relief='sunken', padx=1,pady=1) + self.res_c_frame = tk.Frame(self.c_res_tab, bd=2, relief='sunken', padx=1,pady=1) tk.Label(self.res_c_frame, text="X (ft)", font=helv_res).grid(row=0, column=1) tk.Label(self.res_c_frame, text="V (Kips)", font=helv_res).grid(row=0, column=2) tk.Label(self.res_c_frame, text="M (ft-Kips)", font=helv_res).grid(row=0, column=3) @@ -371,13 +399,13 @@ def __init__(self, master): self.cs_listbox.grid(row=1, column=4) self.cd_listbox = tk.Listbox(self.res_c_frame, height = 30, width = 16, font=helv, yscrollcommand=self.results_scrollbar.set) self.cd_listbox.grid(row=1, column=5) - + self.res_c_frame.pack(anchor='c', padx= 1, pady= 1, fill=tk.BOTH, expand=1) self.r_res_tab = ttk.Frame(self.nb_res) - self.nb_res.add(self.r_res_tab, text='Right Results') - - self.res_r_frame = tk.Frame(self.r_res_tab, bd=2, relief='sunken', padx=1,pady=1) + self.nb_res.add(self.r_res_tab, text='Right Results') + + self.res_r_frame = tk.Frame(self.r_res_tab, bd=2, relief='sunken', padx=1,pady=1) tk.Label(self.res_r_frame, text="X (ft)", font=helv_res).grid(row=0, column=1) tk.Label(self.res_r_frame, text="V (Kips)", font=helv_res).grid(row=0, column=2) tk.Label(self.res_r_frame, text="M (ft-Kips)", font=helv_res).grid(row=0, column=3) @@ -397,193 +425,209 @@ def __init__(self, master): self.rs_listbox.grid(row=1, column=4) self.rd_listbox = tk.Listbox(self.res_r_frame, height = 30, width = 16, font=helv, yscrollcommand=self.results_scrollbar_r.set) self.rd_listbox.grid(row=1, column=5) - + self.res_r_frame.pack(anchor='c', padx= 1, pady= 1, fill=tk.BOTH, expand=1) self.pg3_frame.pack(anchor='c', padx= 1, pady= 1, fill=tk.BOTH, expand=1) - + + #Tab 4 - Piecewise Beam Functions + self.page4 = ttk.Frame(self.nb) + self.nb.add(self.page4, text='Center Span - Piecewise Beam Functions') + + self.pg4_frame = tk.Frame(self.page4, bd=2, relief='sunken', padx=1,pady=1) + + self.pfunc_frame = tk.Frame(self.pg4_frame, bd=2, relief='sunken', padx=1,pady=1) + self.pfunc_text_box = tk.Text(self.pfunc_frame, bg= "grey90", font= helv, wrap=tk.WORD) + self.pfunc_text_box.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + + self.pfunc_scroll = tk.Scrollbar(self.pfunc_frame, command=self.pfunc_text_box.yview) + self.pfunc_scroll.pack(side=tk.LEFT, fill=tk.Y) + + self.pfunc_text_box['yscrollcommand'] = self.pfunc_scroll.set + + self.pfunc_frame.pack(fill=tk.BOTH,expand=1, padx=5, pady=5) + + self.pg4_frame.pack(anchor='c', padx= 1, pady= 1, fill=tk.BOTH, expand=1) + #self.b_export_pdf = tk.Button(self.base_frame,text="Export PDF", command=self.export_pdf, font=helv) #self.b_export_pdf.pack(side=tk.RIGHT) self.b_export_html = tk.Button(self.base_frame,text="Export HTML", command=self.write_html_results, font=helv) self.b_export_html.pack(side=tk.RIGHT) self.b_quit = tk.Button(self.base_frame,text="Quit", command=self.quit_app, font=helv) self.b_quit.pack(side=tk.RIGHT) - + self.loads_left = [] - self.loads_center = [] + self.loads_center = [] self.loads_right = [] - + self.has_run = 0 - + self.build_loads() self.run() self.license_display() - + def license_display(self, *event): - license_string = ("This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n\n" - - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n\n" - - "You should have received a copy of the GNU General Public License along" - "with this program; if not, write to the Free Software Foundation, Inc.," - "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" - "\nA copy of the License can be viewed at:\n https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE") + license_string = ("Copyright (c) 2019, Donald N. Bockoven III\n" + "All rights reserved.\n\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" + " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" + " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" + " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" + " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" + " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" + " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," + " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" + "https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE" + ) tkMessageBox.showerror("License Information",license_string) self.master.focus_force() - + def ScrollFrameConfig(self, *event): self.loads_canvas.configure(scrollregion=self.loads_canvas.bbox("all")) - + def quit_app(self): self.master.destroy() self.master.quit() - + def bm_canvas_draw(self,*event): if self.left_cant_ft.get() == '' or self.span_ft.get()== '' or self.right_cant_ft.get() == '': pass - + else: self.bm_canvas.delete("all") w = self.bm_canvas.winfo_width() h = self.bm_canvas.winfo_height() hg = (h/2.0) - + ll = float(self.left_cant_ft.get()) lc = float(self.span_ft.get()) lr = float(self.right_cant_ft.get()) - + initial = 50 - + sf = (w-(2*initial)) / (ll+lc+lr) - + self.canvas_scale_x = sf - + l = (w-(2*initial)) + initial s1 = (sf * ll) + initial s2 = ((ll+lc) * sf) + initial - + self.bm_canvas.create_line(initial, h/2, l, h/2, fill="white", width=2) self.bm_canvas.create_line(s1, h/2, (s1+20), (h/2)+20, (s1-20), (h/2)+20,s1, h/2, fill="white", width=2) self.bm_canvas.create_line(s2, h/2, (s2+20), (h/2)+20, (s2-20), (h/2)+20,s2, h/2, fill="white", width=2) - + if self.show_l.get() == 1: - + loads_sf = (hg - 10) / max(max(self.loads_scale), abs(min(self.loads_scale))) - + for load in self.loads_left: - x = load.x_graph - y = load.y_graph + x,y = load.chart_load(sf,loads_sf,1) for i in range(1,len(x)): - self.bm_canvas.create_line((x[i-1]* sf)+initial,hg - (y[i-1] * loads_sf),(x[i]* sf)+initial,hg - (y[i] * loads_sf), fill = "blue", width=2) - + self.bm_canvas.create_line((x[i-1])+initial,hg - (y[i-1]),(x[i])+initial,hg - (y[i]), fill = "blue", width=2) + for load in self.loads_center: - x = load.x_graph - y = load.y_graph + x,y = load.chart_load(sf,loads_sf,1) for i in range(1,len(x)): - self.bm_canvas.create_line(((x[i-1] + ll)* sf)+initial,hg - (y[i-1] * loads_sf),((x[i]+ll)* sf)+initial,hg - (y[i] * loads_sf), fill = "blue", width=2) - + self.bm_canvas.create_line(((x[i-1] + (ll*sf)))+initial,hg - (y[i-1]),(x[i]+(ll* sf))+initial,hg - (y[i]), fill = "blue", width=2) + for load in self.loads_right: - x = load.x_graph - y = load.y_graph + x,y = load.chart_load(sf,loads_sf,1) for i in range(1,len(x)): - self.bm_canvas.create_line(((x[i-1]+ll+lc)* sf)+initial,hg - (y[i-1] * loads_sf),((x[i]+ll+lc)* sf)+initial,hg - (y[i] * loads_sf), fill = "blue", width=2) - - if self.has_run == 1: + self.bm_canvas.create_line((x[i-1]+((ll+lc)* sf))+initial,hg - (y[i-1]),(x[i]+((ll+lc)* sf))+initial,hg - (y[i]), fill = "blue", width=2) + + if self.has_run == 1: xl = self.xsl xc = self.xsc xr = self.xsr else: pass - + if self.show_v.get() == 1: - + if max(max(max(self.shearc), max(self.shearl), max(self.shearr)), abs(min(min(self.shearc), min(self.shearl), min(self.shearr)))) == 0: v_sf = (hg - 10) else: v_sf = (hg - 10) / max(max(max(self.shearc), max(self.shearl), max(self.shearr)), abs(min(min(self.shearc), min(self.shearl), min(self.shearr)))) - + self.bm_canvas.create_line((xl[-1] * sf) + initial, hg - (self.shearl[-1] * v_sf),(xc[0] * sf) + initial,hg - (self.shearc[0] * v_sf),fill="red", width=2) self.bm_canvas.create_line((xc[-1] * sf) + initial, hg - (self.shearc[-1] * v_sf),(xr[0] * sf) + initial,hg - (self.shearr[0] * v_sf),fill="red", width=2) - + for i in range(1,len(self.shearc)): self.bm_canvas.create_line((xl[i-1] * sf) + initial, hg - (self.shearl[i-1] * v_sf),(xl[i] * sf) + initial,hg - (self.shearl[i] * v_sf),fill="red", width=2) self.bm_canvas.create_line((xc[i-1] * sf) + initial, hg - (self.shearc[i-1] * v_sf),(xc[i] * sf) + initial,hg - (self.shearc[i] * v_sf),fill="red", width=2) self.bm_canvas.create_line((xr[i-1] * sf) + initial, hg - (self.shearr[i-1] * v_sf),(xr[i] * sf) + initial,hg - (self.shearr[i] * v_sf),fill="red", width=2) - + if self.show_stations.get() == 1: self.bm_canvas.create_line((xl[i-1] * sf) + initial, hg - (self.shearl[i-1] * v_sf),(xl[i-1] * sf) + initial,hg,fill="red3", width=1) self.bm_canvas.create_line((xc[i-1] * sf) + initial, hg - (self.shearc[i-1] * v_sf),(xc[i-1] * sf) + initial,hg,fill="red3", width=1) self.bm_canvas.create_line((xr[i-1] * sf) + initial, hg - (self.shearr[i-1] * v_sf),(xr[i-1] * sf) + initial,hg,fill="red3", width=1) - + if self.show_m.get() == 1: if self.show_m_tension.get() == 1: m_factor = -1.0 else: m_factor = 1.0 - + if max(max(max(self.momentc),max(self.momentl),max(self.momentr)), abs(min(min(self.momentc),min(self.momentl),min(self.momentr)))) == 0: m_sf = ((hg - 10))*m_factor else: m_sf = ((hg - 10) / max(max(max(self.momentc),max(self.momentl),max(self.momentr)), abs(min(min(self.momentc),min(self.momentl),min(self.momentr)))))*m_factor - + for i in range(1,len(self.momentc)): self.bm_canvas.create_line((xl[i-1] * sf) + initial, hg - (self.momentl[i-1] * m_sf),(xl[i] * sf) + initial,hg - (self.momentl[i] * m_sf),fill="green", width=2) self.bm_canvas.create_line((xc[i-1] * sf) + initial, hg - (self.momentc[i-1] * m_sf),(xc[i] * sf) + initial,hg - (self.momentc[i] * m_sf),fill="green", width=2) self.bm_canvas.create_line((xr[i-1] * sf) + initial, hg - (self.momentr[i-1] * m_sf),(xr[i] * sf) + initial,hg - (self.momentr[i] * m_sf),fill="green", width=2) - + if self.show_stations.get() == 1: self.bm_canvas.create_line((xl[i-1] * sf) + initial, hg - (self.momentl[i-1] * m_sf),(xl[i-1] * sf) + initial,hg,fill="PaleGreen3", width=1) self.bm_canvas.create_line((xc[i-1] * sf) + initial, hg - (self.momentc[i-1] * m_sf),(xc[i-1] * sf) + initial,hg,fill="PaleGreen3", width=1) self.bm_canvas.create_line((xr[i-1] * sf) + initial, hg - (self.momentr[i-1] * m_sf),(xr[i-1] * sf) + initial,hg,fill="PaleGreen3", width=1) - + if self.show_s.get() == 1: - + if max(max(max(self.slopec),max(self.slopel),max(self.sloper)), abs(min(min(self.slopec),min(self.slopel),min(self.sloper)))) == 0: s_sf = (hg - 10) else: s_sf = (hg - 10) / max(max(max(self.slopec),max(self.slopel),max(self.sloper)), abs(min(min(self.slopec),min(self.slopel),min(self.sloper)))) - + for i in range(1,len(self.slopec)): self.bm_canvas.create_line((xl[i-1] * sf) + initial, hg - (self.slopel[i-1] * s_sf),(xl[i] * sf) + initial,hg - (self.slopel[i] * s_sf),fill="magenta", width=2) self.bm_canvas.create_line((xc[i-1] * sf) + initial, hg - (self.slopec[i-1] * s_sf),(xc[i] * sf) + initial,hg - (self.slopec[i] * s_sf),fill="magenta", width=2) self.bm_canvas.create_line((xr[i-1] * sf) + initial, hg - (self.sloper[i-1] * s_sf),(xr[i] * sf) + initial,hg - (self.sloper[i] * s_sf),fill="magenta", width=2) - + if self.show_stations.get() == 1: self.bm_canvas.create_line((xl[i-1] * sf) + initial, hg - (self.slopel[i-1] * s_sf),(xl[i-1] * sf) + initial,hg,fill="orchid2", width=1) self.bm_canvas.create_line((xc[i-1] * sf) + initial, hg - (self.slopec[i-1] * s_sf),(xc[i-1] * sf) + initial,hg,fill="orchid2", width=1) self.bm_canvas.create_line((xr[i-1] * sf) + initial, hg - (self.sloper[i-1] * s_sf),(xr[i-1] * sf) + initial,hg,fill="orchid2", width=1) - + if self.show_d.get() == 1: - + if max(max(max(self.deltac),max(self.deltal),max(self.deltar)), abs(min(min(self.deltac),min(self.deltal),min(self.deltar)))) == 0: d_sf = (hg - 10) else: d_sf = (hg - 10) / max(max(max(self.deltac),max(self.deltal),max(self.deltar)), abs(min(min(self.deltac),min(self.deltal),min(self.deltar)))) - + for i in range(1,len(self.deltac)): self.bm_canvas.create_line((xl[i-1] * sf) + initial, hg - (self.deltal[i-1] * d_sf),(xl[i] * sf) + initial,hg - (self.deltal[i] * d_sf),fill="grey", width=2) self.bm_canvas.create_line((xc[i-1] * sf) + initial, hg - (self.deltac[i-1] * d_sf),(xc[i] * sf) + initial,hg - (self.deltac[i] * d_sf),fill="grey", width=2) self.bm_canvas.create_line((xr[i-1] * sf) + initial, hg - (self.deltar[i-1] * d_sf),(xr[i] * sf) + initial,hg - (self.deltar[i] * d_sf),fill="grey", width=2) - + if self.show_stations.get() == 1: self.bm_canvas.create_line((xl[i-1] * sf) + initial, hg - (self.deltal[i-1] * d_sf),(xl[i-1] * sf) + initial,hg,fill="light grey", width=1) self.bm_canvas.create_line((xc[i-1] * sf) + initial, hg - (self.deltac[i-1] * d_sf),(xc[i-1] * sf) + initial,hg,fill="light grey", width=1) self.bm_canvas.create_line((xr[i-1] * sf) + initial, hg - (self.deltar[i-1] * d_sf),(xr[i-1] * sf) + initial,hg,fill="light grey", width=1) if self.show_r.get() == 1: - + if max(max(max(self.rly),max(self.rry)), abs(min(min(self.rlx),min(self.rly)))) == 0: r_sf = (hg - 10) else: r_sf = (hg - 10) / max(max(max(self.rly),max(self.rry)), abs(min(min(self.rlx),min(self.rly)))) - + for i in range(1,len(self.rlx)): self.bm_canvas.create_line((self.rlx[i-1] * sf) + initial, hg - (self.rly[i-1] * r_sf),(self.rlx[i] * sf) + initial,hg - (self.rly[i] * r_sf),fill="light blue", width=2) self.bm_canvas.create_line((self.rrx[i-1] * sf) + initial, hg - (self.rry[i-1] * r_sf),(self.rrx[i] * sf) + initial,hg - (self.rry[i] * r_sf),fill="light blue", width=2) @@ -610,7 +654,7 @@ def det_res_scroll_r(self, *args): self.rd_listbox.yview(*args) def build_loads(self, *event): - + del self.loads_right[:] del self.loads_left[:] del self.loads_center[:] @@ -622,34 +666,34 @@ def build_loads(self, *event): self.extra_l_station = np.array([0]) self.extra_c_station = np.array([0]) self.extra_r_station = np.array([0]) - - + + for load in self.loads_gui_select_var: - + if load[0].get() == 0: - + pass - + else: - + w1 = float(load[1].get()) w2 = float(load[2].get()) a = float(load[3].get()) b = float(load[4].get()) load_location = load[5].get() load_type = load[6].get() - + if load_type == 'Moment': self.loads_scale.append(w1/2.0) - self.loads_scale.append(w2) + self.loads_scale.append(w2) else: self.loads_scale.append(w1) self.loads_scale.append(w2) - + #['Left','Center','Right'] if load_location == 'Left': #['Point','Moment','UDL','TRAP'] - + if load_type == 'Point': self.loads_left.append(ppbeam.cant_left_point(w1,a,ll,lc)) b = min(ll,a + 0.0001) @@ -665,13 +709,13 @@ def build_loads(self, *event): elif load_type == 'UDL': self.loads_left.append(ppbeam.cant_left_udl(w1,a,b,ll,lc)) self.extra_l_station = np.append(self.extra_l_station, [a,b]) - + elif load_type == 'TRAP': self.loads_left.append(ppbeam.cant_left_trap(w1,w2,a,b,ll,lc)) self.extra_l_station = np.append(self.extra_l_station, [a,b]) else: pass - + elif load_location == 'Center': #['Point','Moment','UDL','TRAP'] if load_type == 'Point': @@ -689,14 +733,14 @@ def build_loads(self, *event): elif load_type == 'UDL': self.loads_center.append(ppbeam.udl(w1,a,b,lc)) self.extra_c_station = np.append(self.extra_c_station, [a,b]) - + elif load_type == 'TRAP': self.loads_center.append(ppbeam.trap(w1,w2,a,b,lc)) self.extra_c_station = np.append(self.extra_c_station, [a,b]) - + else: pass - + elif load_location == 'Right': #['Point','Moment','UDL','TRAP'] if load_type == 'Point': @@ -710,28 +754,28 @@ def build_loads(self, *event): b = min(lr,a + 0.0001) c = max(0,a - 0.0001) self.extra_r_station = np.append(self.extra_r_station, [c,a,b]) - + elif load_type == 'UDL': self.loads_right.append(ppbeam.cant_right_udl(w1,a,b,lr,lc)) self.extra_r_station = np.append(self.extra_r_station, [a,b]) - + elif load_type == 'TRAP': self.loads_right.append(ppbeam.cant_right_trap(w1,w2,a,b,lr,lc)) self.extra_r_station = np.append(self.extra_r_station, [a,b]) - + else: pass - + else: pass - + self.extra_l_station = np.unique(self.extra_l_station) self.extra_c_station = np.unique(self.extra_c_station) self.extra_r_station = np.unique(self.extra_r_station) self.run() self.bm_canvas_draw() - + def build_loads_gui(self, *event): #Destroy all the individual tkinter gui elements for the current applied loads for load_gui in self.loads_gui: @@ -741,14 +785,14 @@ def build_loads_gui(self, *event): #Delete all the elements in the List containing the gui elements del self.loads_gui[:] del self.loads_scale[:] - + n = 0 for loads in self.loads_gui_select_var: load_types = ['Point','Moment','UDL','TRAP'] load_locals = ['Left','Center','Right'] - + if loads[6].get() == 'Moment': - self.loads_scale.append(float(loads[1].get())/2.0) + self.loads_scale.append(float(loads[1].get())/2.0) else: self.loads_scale.append(float(loads[1].get())) self.loads_scale.append(float(loads[2].get())) @@ -770,11 +814,11 @@ def build_loads_gui(self, *event): self.loads_gui[n][5].grid(row=n+1, column=6) self.loads_gui[n][6].grid(row=n+1, column=7) n+=1 - + def add_load(self, *event): - + self.loads_gui_select_var.append([tk.IntVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar()]) - + n = len(self.loads_gui_select_var) self.loads_gui_select_var[n-1][0].set(1) self.loads_gui_select_var[n-1][1].set(self.w1_gui.get()) @@ -783,37 +827,37 @@ def add_load(self, *event): self.loads_gui_select_var[n-1][4].set(self.b_gui.get()) self.loads_gui_select_var[n-1][5].set(self.load_loc.get()) self.loads_gui_select_var[n-1][6].set(self.load_type.get()) - + self.build_loads_gui() - self.build_loads() + self.build_loads() def remove_load(self, *event): - ''' + ''' for load in self.loads_gui[-1]: load.destroy() - + del self.loads_gui[-1] - + del self.loads_gui_select_var[-1] ''' - + self.loads_gui_select_var = [i for i in self.loads_gui_select_var if i[0].get() == 1] self.build_loads_gui() self.build_loads() - + def reaction_graph(self,r,x): r = -1.0 * r arrow_height = r/6.0 #30 degree arrow arrow_plus= x+(arrow_height*math.tan(math.radians(30))) arrow_minus= x-(arrow_height*math.tan(math.radians(30))) - + x_graph=[arrow_minus,x,arrow_plus,x,x] y_graph=[arrow_height,0,arrow_height,0,r] - + return x_graph, y_graph - + def run(self, *event): self.xl_listbox.delete(0,tk.END) self.lv_listbox.delete(0,tk.END) @@ -832,65 +876,66 @@ def run(self, *event): self.rm_listbox.delete(0,tk.END) self.rs_listbox.delete(0,tk.END) self.rd_listbox.delete(0,tk.END) + if self.left_cant_ft.get() == '' or self.span_ft.get()== '' or self.right_cant_ft.get() == '': pass - + else: self.ll = float(self.left_cant_ft.get()) self.lc = float(self.span_ft.get()) self.lr = float(self.right_cant_ft.get()) - + E = float(self.E_ksi.get()) * 144 #144 is conversion from ksi to ksf - 12^2 - I = float(self.I_in4.get()) / 12.0**4 #covert from in^4 to ft^4 - + I = float(self.I_in4.get()) / 12.0**4 #covert from in^4 to ft^4 + iters = int(self.stations.get()) - + step_left = self.ll/(iters+0.00) step_backspan = self.lc/(iters+0.00) step_right = self.lr/(iters+0.00) - + xsl = zeros(iters+1) xsc = zeros(iters+1) xsr = zeros(iters+1) - + reaction_left = 0 reaction_right = 0 - + xsl[0]=0 xsc[0]=0 xsr[0]=0 - + for i in range(1,(iters+1)): if xsl[i-1] + step_left > self.ll: xsl[i] = self.ll else: xsl[i] = xsl[i-1] + step_left - + if xsc[i-1] + step_backspan > self.lc: xsc[i] = self.lc else: xsc[i] = xsc[i-1] + step_backspan - + if xsr[i-1] + step_right > self.lr: xsr[i] = self.lr else: xsr[i] = xsr[i-1] + step_right - - + + xsl = np.append(xsl, self.extra_l_station) - xsc = np.append(xsc, self.extra_c_station) + xsc = np.append(xsc, self.extra_c_station) xsr = np.append(xsr, self.extra_r_station) xsl = np.sort(xsl) - xsc = np.sort(xsc) + xsc = np.sort(xsc) xsr = np.sort(xsr) xsl = np.unique(xsl) - xsc = np.unique(xsc) + xsc = np.unique(xsc) xsr = np.unique(xsr) - + i = max(xsl.shape[0], xsc.shape[0], xsr.shape[0]) @@ -916,114 +961,117 @@ def run(self, *event): shearl = zeros(i) shearc = zeros(i) shearr = zeros(i) - + momentl = zeros(i) momentc = zeros(i) momentr = zeros(i) - + slopel = zeros(i) slopec = zeros(i) sloper = zeros(i) - + deltal = zeros(i) deltac = zeros(i) - deltar = zeros(i) - + deltar = zeros(i) + if self.ll == 0: load_left = [ppbeam.cant_left_point(0,0,self.ll,self.lc)] - + else: load_left = self.loads_left - + if len(self.loads_center) == 0: - load_center = [ppbeam.pl(0,0,self.lc)] + if self.lc == 0: + load_center = [ppbeam.no_load(self.lc)] + else: + load_center = [ppbeam.pl(0,0,self.lc)] else: load_center = self.loads_center - + if self.lr == 0: load_right = [ppbeam.cant_right_point(0,0,self.lr,self.lc)] else: load_right = self.loads_right - - + + for load in load_left: reaction_left = reaction_left + load.rr + load.backspan.rl reaction_right = reaction_right + load.backspan.rr - + shearl = shearl + load.v(xsl) shearc = shearc + load.backspan.v(xsc) - + momentl = momentl + load.m(xsl) momentc = momentc + load.backspan.m(xsc) - + slopel = slopel + load.eis(xsl) slopec = slopec + load.backspan.eis(xsc) - sloper = sloper + ppbeam.cant_right_nl(load.backspan.eisx(self.lc)).eis(xsr) - + sloper = sloper + ppbeam.cant_right_nl(load.backspan.eisx(self.lc),self.lr).eis(xsr) + deltal = deltal + load.eid(xsl) deltac = deltac + load.backspan.eid(xsc) - deltar = deltar + ppbeam.cant_right_nl(load.backspan.eisx(self.lc)).eid(xsr) - + deltar = deltar + ppbeam.cant_right_nl(load.backspan.eisx(self.lc),self.lr).eid(xsr) + for load in load_center: reaction_left = reaction_left + load.rl reaction_right = reaction_right + load.rr - + shearc = shearc + load.v(xsc) - + momentc = momentc + load.m(xsc) - + slopel = slopel + ppbeam.cant_left_nl(load.eisx(0),self.ll).eis(xsl) slopec = slopec + load.eis(xsc) - sloper = sloper + ppbeam.cant_right_nl(load.eisx(self.lc)).eis(xsr) - + sloper = sloper + ppbeam.cant_right_nl(load.eisx(self.lc),self.lr).eis(xsr) + deltal = deltal + ppbeam.cant_left_nl(load.eisx(0),self.ll).eid(xsl) deltac = deltac + load.eid(xsc) - deltar = deltar + ppbeam.cant_right_nl(load.eisx(self.lc)).eid(xsr) - + deltar = deltar + ppbeam.cant_right_nl(load.eisx(self.lc),self.lr).eid(xsr) + for load in load_right: reaction_left = reaction_left + load.backspan.rl reaction_right = reaction_right + load.backspan.rr + load.rl - + shearc = shearc + load.backspan.v(xsc) shearr = shearr + load.v(xsr) - + momentc = momentc + load.backspan.m(xsc) momentr = momentr + load.m(xsr) - + slopel = slopel + ppbeam.cant_left_nl(load.backspan.eisx(0),self.ll).eis(xsl) slopec = slopec + load.backspan.eis(xsc) sloper = sloper + load.eis(xsr) - + deltal = deltal + ppbeam.cant_left_nl(load.backspan.eisx(0),self.ll).eid(xsl) deltac = deltac + load.backspan.eid(xsc) deltar = deltar + load.eid(xsr) - + self.shearl = shearl self.shearc = shearc self.shearr = shearr - + self.momentl = momentl self.momentc = momentc self.momentr = momentr - + self.slopel = slopel / (E*I) self.slopec = slopec / (E*I) self.sloper = sloper / (E*I) - + self.deltal = (deltal / (E*I))*12.0 self.deltac = (deltac / (E*I))*12.0 self.deltar = (deltar / (E*I))*12.0 - + self.rlx, self.rly = self.reaction_graph(reaction_left, self.ll) self.rrx, self.rry = self.reaction_graph(reaction_right, self.ll+self.lc) - + self.reaction_left = reaction_left self.reaction_right = reaction_right - + self.res_labels[1].configure(text = 'Rl = {0:.3f} kips'.format(reaction_left)) self.res_labels[2].configure(text = 'Rr = {0:.3f} kips'.format(reaction_right)) - + if self.ll == 0: self.res_labels[4].configure(text = '--') self.res_labels[5].configure(text = '--') @@ -1034,12 +1082,12 @@ def run(self, *event): self.res_labels[5].configure(text = 'Mmax = {0:.3f} ft-kips - Mmin = {1:.3f} ft-kips'.format(max(momentl), min(momentl))) self.res_labels[6].configure(text = 'Smax = {0:.5f} rad - Smin = {1:.5f} rad'.format(max(self.slopel), min(self.slopel))) self.res_labels[7].configure(text = 'Dmax = {0:.4f} in - Dmin = {1:.4f} in'.format(max(self.deltal), min(self.deltal))) - + self.res_labels[9].configure(text = 'Vmax = {0:.3f} kips - Vmin = {1:.3f} kips'.format(max(shearc), min(shearc))) self.res_labels[10].configure(text = 'Mmax = {0:.3f} ft-kips - Mmin = {1:.3f} ft-kips'.format(max(momentc), min(momentc))) self.res_labels[11].configure(text = 'Smax = {0:.5f} rad - Smin = {1:.5f} rad'.format(max(self.slopec), min(self.slopec))) self.res_labels[12].configure(text = 'Dmax = {0:.4f} in - Dmin = {1:.4f} in'.format(max(self.deltac), min(self.deltac))) - + if self.lr == 0: self.res_labels[14].configure(text = '--') self.res_labels[15].configure(text = '--') @@ -1050,74 +1098,74 @@ def run(self, *event): self.res_labels[15].configure(text = 'Mmax = {0:.3f} ft-kips - Mmin = {1:.3f} ft-kips'.format(max(momentr), min(momentr))) self.res_labels[16].configure(text = 'Smax = {0:.5f} rad - Smin = {1:.5f} rad'.format(max(self.sloper), min(self.sloper))) self.res_labels[17].configure(text = 'Dmax = {0:.4f} in - Dmin = {1:.4f} in'.format(max(self.deltar), min(self.deltar))) - + #Left detailed results to GUI color = "pale green" i=0 for x in xsl: self.xl_listbox.insert(tk.END,'{0:.4f}'.format(x)) - + if i % 2 == 0: self.xl_listbox.itemconfigure(i, background=color) else: pass i+=1 - + i=0 for v in self.shearl: self.lv_listbox.insert(tk.END,'{0:.4f}'.format(v)) - + if i % 2 == 0: self.lv_listbox.itemconfigure(i, background=color) else: pass i+=1 - + i=0 for m in self.momentl: self.lm_listbox.insert(tk.END,'{0:.4f}'.format(m)) - + if i % 2 == 0: self.lm_listbox.itemconfigure(i, background=color) else: pass i+=1 - + i=0 for s in self.slopel: self.ls_listbox.insert(tk.END,'{0:.8f}'.format(s)) - + if i % 2 == 0: self.ls_listbox.itemconfigure(i, background=color) else: pass i+=1 - + i=0 for d in self.deltal: self.ld_listbox.insert(tk.END,'{0:.6f}'.format(d)) - + if i % 2 == 0: self.ld_listbox.itemconfigure(i, background=color) else: pass - i+=1 - + i+=1 + #Center/Main detailed results to GUI i=0 for x in xsc: self.xc_listbox.insert(tk.END,'{0:.4f}'.format(x)) - + if i % 2 == 0: self.xc_listbox.itemconfigure(i, background=color) else: pass i+=1 - i=0 + i=0 for v in self.shearc: self.cv_listbox.insert(tk.END,'{0:.4f}'.format(v)) - + if i % 2 == 0: self.cv_listbox.itemconfigure(i, background=color) else: @@ -1127,7 +1175,7 @@ def run(self, *event): i=0 for m in self.momentc: self.cm_listbox.insert(tk.END,'{0:.4f}'.format(m)) - + if i % 2 == 0: self.cm_listbox.itemconfigure(i, background=color) else: @@ -1137,7 +1185,7 @@ def run(self, *event): i=0 for s in self.slopec: self.cs_listbox.insert(tk.END,'{0:.8f}'.format(s)) - + if i % 2 == 0: self.cs_listbox.itemconfigure(i, background=color) else: @@ -1147,7 +1195,7 @@ def run(self, *event): i=0 for d in self.deltac: self.cd_listbox.insert(tk.END,'{0:.6f}'.format(d)) - + if i % 2 == 0: self.cd_listbox.itemconfigure(i, background=color) else: @@ -1158,17 +1206,17 @@ def run(self, *event): i=0 for x in xsr: self.xr_listbox.insert(tk.END,'{0:.4f}'.format(x)) - + if i % 2 == 0: self.xr_listbox.itemconfigure(i, background=color) else: pass i+=1 - i=0 + i=0 for v in self.shearr: self.rv_listbox.insert(tk.END,'{0:.4f}'.format(v)) - + if i % 2 == 0: self.rv_listbox.itemconfigure(i, background=color) else: @@ -1178,7 +1226,7 @@ def run(self, *event): i=0 for m in self.momentr: self.rm_listbox.insert(tk.END,'{0:.4f}'.format(m)) - + if i % 2 == 0: self.rm_listbox.itemconfigure(i, background=color) else: @@ -1188,7 +1236,7 @@ def run(self, *event): i=0 for s in self.sloper: self.rs_listbox.insert(tk.END,'{0:.8f}'.format(s)) - + if i % 2 == 0: self.rs_listbox.itemconfigure(i, background=color) else: @@ -1198,48 +1246,77 @@ def run(self, *event): i=0 for d in self.deltar: self.rd_listbox.insert(tk.END,'{0:.6f}'.format(d)) - + if i % 2 == 0: self.rd_listbox.itemconfigure(i, background=color) else: pass i+=1 + #save station to global variables for other processes + self.xsl_local = xsl + self.xsc_local = xsc + self.xsr_local = xsr #convert x coordinates to global self.xsl = xsl self.xsc = xsc + xsl[-1] self.xsr = xsr + self.xsc[-1] - + self.has_run = 1 self.bm_canvas_draw() + self.loads_piece = [] + self.loads_piece.extend(self.loads_center) + + if self.ll == 0: + pass + else: + if self.lc == 0: + pass + else: + self.loads_piece.append(ppbeam.point_moment(momentl[-1],0,xsc[-1])) + + if self.lr == 0: + pass + else: + if self.lc == 0: + pass + else: + self.loads_piece.append(ppbeam.point_moment(-1*momentr[0],xsc[-1],xsc[-1])) + + + if len(self.loads_piece) == 0: + pass + else: + self.piece_function_gen() + def runx(self, *event): x = float(self.resx_var.get()) - + E = float(self.E_ksi.get()) * 144 #144 is conversion from ksi to ksf - 12^2 I = float(self.I_in4.get()) / 12.0**4 #covert from in^4 to ft^4 - + v,m,s,d = self.analysisx(x) - + shearlx = v[0] momentlx = m[0] slopelx = s[0] / (E*I) deltalx =(d[0] / (E*I))*12.0 - + shearcx = v[1] momentcx = m[1] slopecx = s[1] / (E*I) deltacx =(d[1] / (E*I))*12.0 - + shearrx = v[2] momentrx = m[2] sloperx = s[2] / (E*I) deltarx =(d[2] / (E*I))*12.0 - + self.deltacx = deltacx - + if self.ll == 0 or x > self.ll: - + self.resx_labels[2].configure(text = '--') self.resx_labels[3].configure(text = '--') self.resx_labels[4].configure(text = '--') @@ -1249,23 +1326,23 @@ def runx(self, *event): self.resx_labels[3].configure(text = 'M = {0:.3f} ft-kips'.format(momentlx)) self.resx_labels[4].configure(text = 'S = {0:.5f} rad'.format(slopelx)) self.resx_labels[5].configure(text = 'D = {0:.4f} in'.format(deltalx)) - + self.resx_labels[7].configure(text = 'V = {0:.3f} kips'.format(shearcx)) self.resx_labels[8].configure(text = 'M = {0:.3f} ft-kips'.format(momentcx)) self.resx_labels[9].configure(text = 'S = {0:.5f} rad'.format(slopecx)) self.resx_labels[10].configure(text = 'D = {0:.4f} in'.format(deltacx)) - + if self.lr == 0 or x > self.lr: self.resx_labels[12].configure(text = '--') self.resx_labels[13].configure(text = '--') self.resx_labels[14].configure(text = '--') - self.resx_labels[15].configure(text = '--') + self.resx_labels[15].configure(text = '--') else: self.resx_labels[12].configure(text = 'V = {0:.3f} kips'.format(shearrx)) self.resx_labels[13].configure(text = 'M = {0:.3f} ft-kips'.format(momentrx)) self.resx_labels[14].configure(text = 'S = {0:.5f} rad'.format(sloperx)) self.resx_labels[15].configure(text = 'D = {0:.4f} in'.format(deltarx)) - + def analysisx(self, x): if self.left_cant_ft.get() == '' or self.span_ft.get()== '' or self.right_cant_ft.get() == '': @@ -1275,195 +1352,206 @@ def analysisx(self, x): self.ll = float(self.left_cant_ft.get()) self.lc = float(self.span_ft.get()) self.lr = float(self.right_cant_ft.get()) - + x = x - + if x > self.ll: xsl = self.ll else: xsl = x xsc = x - + if x > self.lr: xsr = self.lr else: xsr = x - + shearlx = 0 shearcx = 0 shearrx = 0 - + momentlx = 0 momentcx = 0 momentrx = 0 - + slopelx = 0 slopecx = 0 sloperx = 0 - + deltalx = 0 deltacx = 0 deltarx = 0 - + if self.ll == 0: load_left = [ppbeam.cant_left_point(0,0,self.ll,self.lc)] - + else: load_left = self.loads_left - + if len(self.loads_center) == 0: - load_center = [ppbeam.pl(0,0,self.lc)] + if self.lc == 0: + load_center = [ppbeam.no_load(self.lc)] + else: + load_center = [ppbeam.pl(0,0,self.lc)] else: load_center = self.loads_center - + if self.lr == 0: load_right = [ppbeam.cant_right_point(0,0,self.lr,self.lc)] else: load_right = self.loads_right - - + + for load in load_left: - + shearlx = shearlx + load.vx(xsl) shearcx = shearcx + load.backspan.vx(xsc) - + momentlx = momentlx + load.mx(xsl) momentcx = momentcx + load.backspan.mx(xsc) - + slopelx = slopelx + load.eisx(xsl) slopecx = slopecx + load.backspan.eisx(xsc) - sloperx = sloperx + ppbeam.cant_right_nl(load.backspan.eisx(self.lc)).eisx(xsr) - + sloperx = sloperx + ppbeam.cant_right_nl(load.backspan.eisx(self.lc),self.lr).eisx(xsr) + deltalx = deltalx + load.eidx(xsl) deltacx = deltacx + load.backspan.eidx(xsc) - deltarx = deltarx + ppbeam.cant_right_nl(load.backspan.eisx(self.lc)).eidx(xsr) - + deltarx = deltarx + ppbeam.cant_right_nl(load.backspan.eisx(self.lc),self.lr).eidx(xsr) + for load in load_center: - + shearcx = shearcx + load.vx(xsc) - + momentcx = momentcx + load.mx(xsc) - + slopelx = slopelx + ppbeam.cant_left_nl(load.eisx(0),self.ll).eisx(xsl) slopecx = slopecx + load.eisx(xsc) - sloperx = sloperx + ppbeam.cant_right_nl(load.eisx(self.lc)).eisx(xsr) - + sloperx = sloperx + ppbeam.cant_right_nl(load.eisx(self.lc),self.lr).eisx(xsr) + deltalx = deltalx + ppbeam.cant_left_nl(load.eisx(0),self.ll).eidx(xsl) deltacx = deltacx + load.eidx(xsc) - deltarx = deltarx + ppbeam.cant_right_nl(load.eisx(self.lc)).eidx(xsr) - + deltarx = deltarx + ppbeam.cant_right_nl(load.eisx(self.lc),self.lr).eidx(xsr) + for load in load_right: - + shearcx = shearcx + load.backspan.vx(xsc) shearrx = shearrx + load.vx(xsr) - + momentcx = momentcx + load.backspan.mx(xsc) momentrx = momentrx + load.mx(xsr) - + slopelx = slopelx + ppbeam.cant_left_nl(load.backspan.eisx(0),self.ll).eisx(xsl) slopecx = slopecx + load.backspan.eisx(xsc) sloperx = sloperx + load.eisx(xsr) - + deltalx = deltalx + ppbeam.cant_left_nl(load.backspan.eisx(0),self.ll).eidx(xsl) deltacx = deltacx + load.backspan.eidx(xsc) deltarx = deltarx + load.eidx(xsr) - + v = [shearlx, shearcx, shearrx] m = [momentlx, momentcx, momentrx] s = [slopelx, slopecx, sloperx] d = [deltalx, deltacx, deltarx] - + return v,m,s,d - + + def analysisx_type(self, x, res=1,*event): + v,m,s,d = self.analysisx(x) + a = [v,m,s,d] + + out = a[res] + + return -1*out[1] + def update(self, *event): - + ll = float(self.left_cant_ft.get()) lc = float(self.span_ft.get()) lr = float(self.right_cant_ft.get()) - + n=0 - + if ll > 0: self.fixed_left.set(0) self.fixed_left_check.configure(state=tk.DISABLED) else: self.fixed_left_check.configure(state=tk.NORMAL) - + if lr > 0: self.fixed_right.set(0) self.fixed_right_check.configure(state=tk.DISABLED) else: self.fixed_right_check.configure(state=tk.NORMAL) - + for load in self.loads_gui_select_var: - + a = float(load[3].get()) b = float(load[4].get()) load_location = load[5].get() - + if ll == 0 and load_location == 'Left': del self.loads_gui_select_var[n] - + for widgets in self.loads_gui[n]: widgets.destroy() - + del self.loads_gui[n] - + elif lr == 0 and load_location == 'Right': del self.loads_gui_select_var[n] - + for widgets in self.loads_gui[n]: widgets.destroy() - + del self.loads_gui[n] - + elif load_location == 'Left' and a > ll: load[3].set(0) - + elif load_location == 'Right' and a > lr: load[3].set(0) - + elif load_location == 'Left' and b > ll: load[4].set(ll) - + if load[3].get() == load[4].get(): del self.loads_gui_select_var[n] - + for widgets in self.loads_gui[n]: widgets.destroy() - + del self.loads_gui[n] - + elif load_location == 'Right' and b > lr: load[4].set(lr) - + if load[3].get() == load[4].get(): del self.loads_gui_select_var[n] - + for widgets in self.loads_gui[n]: widgets.destroy() - + del self.loads_gui[n] - + elif load_location == 'Center' and a > lc: load[3].set(0) - + elif load_location == 'Center' and b > lc: load[4].set(lc) - + if load[3].get() == load[4].get(): del self.loads_gui_select_var[n] - + for widgets in self.loads_gui[n]: widgets.destroy() - + del self.loads_gui[n] else: pass - + n = n+1 - - self.build_loads() + + self.build_loads() def moment_area(self, *event): if self.has_run == 1: @@ -1474,211 +1562,50 @@ def moment_area(self, *event): ml = self.momentl mc = self.momentc mr = self.momentr - + xsl = self.xsl xsc = self.xsc - xsl[-1] xsr = self.xsr - self.xsc[-1] - + al = sci_int.cumtrapz(ml, xsl, initial = 0) ac = sci_int.cumtrapz(mc, xsc, initial = 0) ar = sci_int.cumtrapz(mr, xsr, initial = 0) - + m_xl = [] m_xc = [] m_xr = [] - + for i in range(0,len(xsl)): m_xl.append(ml[i]*xsl[i]) m_xc.append(mc[i]*xsc[i]) m_xr.append(mr[i]*xsr[i]) - + m_xl_a = sci_int.cumtrapz(m_xl, xsl, initial = 0) m_xc_a = sci_int.cumtrapz(m_xc, xsc, initial = 0) m_xr_a = sci_int.cumtrapz(m_xr, xsr, initial = 0) - + xl_l = (1/al[-1])*m_xl_a[-1] xl_c = (1/ac[-1])*m_xc_a[-1] xl_r = (1/ar[-1])*m_xr_a[-1] - + xr_l = xsl[-1] - xl_l xr_c = xsc[-1] - xl_c xr_r = xsr[-1] - xl_r - + res_string = 'Left:\nA = {0:.4f} Xleft = {1:.4f} ft Xright = {2:.4f} ft\n'.format(al[-1],xl_l,xr_l) res_string = res_string+'Center:\nA = {0:.4f} Xleft = {1:.4f} ft Xright = {2:.4f} ft\n'.format(ac[-1],xl_c,xr_c) res_string = res_string+'Right:\nA = {0:.4f} Xleft = {1:.4f} ft Xright = {2:.4f} ft\n'.format(ar[-1],xl_r,xr_r) - + self.moment_area_label.configure(text=res_string) - - # def export_pdf(self, *event): - # fig = plt.figure(figsize=(11,17),dpi=600) - - # axb_l = plt.subplot2grid((8, 1), (0, 0)) - # axb_p = plt.subplot2grid((8, 1), (1, 0)) - # axb_m = plt.subplot2grid((8, 1), (2, 0)) - - # axr = plt.subplot2grid((8, 1), (3, 0)) - # axv = plt.subplot2grid((8, 1), (4, 0)) - # axm = plt.subplot2grid((8, 1), (5, 0)) - # axs = plt.subplot2grid((8, 1), (6, 0)) - # axd = plt.subplot2grid((8, 1), (7, 0)) - - # for load in self.loads_left: - # if len(load.x_graph) > 11: - # axb_m.plot(load.x_graph,load.y_graph) - # elif len(load.x_graph) > 6: - # axb_l.plot(load.x_graph,load.y_graph) - # else: - # axb_p.plot(load.x_graph,load.y_graph) - - # for load in self.loads_center: - # if len(load.x_graph) > 11: - # axb_m.plot(load.x_graph+self.xsl[-1],load.y_graph) - # elif len(load.x_graph) > 6: - # axb_l.plot(load.x_graph+self.xsl[-1],load.y_graph) - # else: - # axb_p.plot(load.x_graph+self.xsl[-1],load.y_graph) - - # for load in self.loads_right: - # if len(load.x_graph) > 11: - # axb_m.plot(load.x_graph+self.xsc[-1],load.y_graph) - # elif len(load.x_graph) > 6: - # axb_l.plot(load.x_graph+self.xsc[-1],load.y_graph) - # else: - # axb_p.plot(load.x_graph+self.xsc[-1],load.y_graph) - - # axb_l.plot([0,0,0],[0.5,0,-0.5], alpha=0) - # axb_l.plot(self.xsl,[0]*len(self.xsl)) - # axb_l.plot(self.xsc,[0]*len(self.xsc)) - # axb_l.plot(self.xsr,[0]*len(self.xsr)) - - # axb_m.plot([0,0,0],[0.5,0,-0.5], alpha=0) - # axb_m.plot(self.xsl,[0]*len(self.xsl)) - # axb_m.plot(self.xsc,[0]*len(self.xsc)) - # axb_m.plot(self.xsr,[0]*len(self.xsr)) - - # axb_p.plot([0,0,0],[0.5,0,-0.5], alpha=0) - # axb_p.plot(self.xsl,[0]*len(self.xsl)) - # axb_p.plot(self.xsc,[0]*len(self.xsc)) - # axb_p.plot(self.xsr,[0]*len(self.xsr)) - - # #support symbols - # x0 = self.ll - # x2 = self.ll+self.lc - # axb_l.plot([x0,x0-0.25,x0+0.25,x0],[0,-0.25,-0.25,0], color='k') - # axb_l.plot([x2,x2-0.25,x2+0.25,x2],[0,-0.25,-0.25,0], color='k') - # axb_l.minorticks_on() - # axb_l.grid(b=True, which='major', color='k', linestyle='-', alpha=0.3) - # axb_l.grid(b=True, which='minor', color='g', linestyle='-', alpha=0.1) - - # axb_m.plot([x0,x0-0.25,x0+0.25,x0],[0,-0.25,-0.25,0], color='k') - # axb_m.plot([x2,x2-0.25,x2+0.25,x2],[0,-0.25,-0.25,0], color='k') - # axb_m.minorticks_on() - # axb_m.grid(b=True, which='major', color='k', linestyle='-', alpha=0.3) - # axb_m.grid(b=True, which='minor', color='g', linestyle='-', alpha=0.1) - - # axb_p.plot([x0,x0-0.25,x0+0.25,x0],[0,-0.25,-0.25,0], color='k') - # axb_p.plot([x2,x2-0.25,x2+0.25,x2],[0,-0.25,-0.25,0], color='k') - # axb_p.minorticks_on() - # axb_p.grid(b=True, which='major', color='k', linestyle='-', alpha=0.3) - # axb_p.grid(b=True, which='minor', color='g', linestyle='-', alpha=0.1) - - # axb_l.set_ylabel('Applied Loads\n(klf)') - # axb_m.set_ylabel('Applied Moments\n(ft-kips)') - # axb_p.set_ylabel('Applied Point Loads\n(kips)') - # axb_l.set_xlabel('L (ft)') - # axb_m.set_xlabel('L (ft)') - # axb_p.set_xlabel('L (ft)') - - # axr.plot(self.rlx,self.rly) - # axr.annotate('RL = {0:.3f} kips'.format(self.reaction_left), xy=(self.ll,min(self.rly))) - # axr.plot(self.rrx,self.rry) - # axr.annotate('RR = {0:.3f} kips'.format(self.reaction_right), xy=(self.ll+self.lc,min(self.rry)), ha="right") - # axr.plot([0,0,0],[0.5,0,-0.5], alpha=0) - # axr.plot(self.xsl,[0]*len(self.xsl)) - # axr.plot(self.xsc,[0]*len(self.xsc)) - # axr.plot(self.xsr,[0]*len(self.xsr)) - # axr.minorticks_on() - # axr.grid(b=True, which='major', color='k', linestyle='-', alpha=0.3) - # axr.grid(b=True, which='minor', color='g', linestyle='-', alpha=0.1) - # axr.set_ylabel('Reaction (kips)') - # axr.set_xlabel('L (ft)') - - # axv.plot(self.xsl,self.shearl) - # axv.plot(self.xsc,self.shearc) - # axv.plot(self.xsr,self.shearr) - # axv.plot(self.xsl,[0]*len(self.xsl)) - # axv.plot(self.xsc,[0]*len(self.xsc)) - # axv.plot(self.xsr,[0]*len(self.xsr)) - # axv.fill_between(self.xsl,self.shearl,[0]*len(self.xsl), facecolor='blue', alpha=0.2) - # axv.fill_between(self.xsc,self.shearc,[0]*len(self.xsc), facecolor='blue', alpha=0.2) - # axv.fill_between(self.xsr,self.shearr,[0]*len(self.xsr), facecolor='blue', alpha=0.2) - # axv.minorticks_on() - # axv.grid(b=True, which='major', color='k', linestyle='-', alpha=0.3) - # axv.grid(b=True, which='minor', color='g', linestyle='-', alpha=0.1) - # axv.set_ylabel('V (kips)') - # axv.set_xlabel('L (ft)') - - # axm.plot(self.xsl,self.momentl) - # axm.plot(self.xsc,self.momentc) - # axm.plot(self.xsr,self.momentr) - # axm.plot(self.xsl,[0]*len(self.xsl)) - # axm.plot(self.xsc,[0]*len(self.xsc)) - # axm.plot(self.xsr,[0]*len(self.xsr)) - # axm.fill_between(self.xsl,self.momentl,[0]*len(self.xsl), facecolor='red', alpha=0.2) - # axm.fill_between(self.xsc,self.momentc,[0]*len(self.xsc), facecolor='red', alpha=0.2) - # axm.fill_between(self.xsr,self.momentr,[0]*len(self.xsr), facecolor='red', alpha=0.2) - # axm.minorticks_on() - # axm.grid(b=True, which='major', color='k', linestyle='-', alpha=0.3) - # axm.grid(b=True, which='minor', color='g', linestyle='-', alpha=0.1) - # axm.set_ylabel('M (ft-kips)') - # axm.set_xlabel('L (ft)') - - # axs.plot(self.xsl,self.slopel) - # axs.plot(self.xsc,self.slopec) - # axs.plot(self.xsr,self.sloper) - # axs.plot(self.xsl,[0]*len(self.xsl)) - # axs.plot(self.xsc,[0]*len(self.xsc)) - # axs.plot(self.xsr,[0]*len(self.xsr)) - # axs.fill_between(self.xsl,self.slopel,[0]*len(self.xsl), facecolor='green', alpha=0.2) - # axs.fill_between(self.xsc,self.slopec,[0]*len(self.xsc), facecolor='green', alpha=0.2) - # axs.fill_between(self.xsr,self.sloper,[0]*len(self.xsr), facecolor='green', alpha=0.2) - # axs.minorticks_on() - # axs.grid(b=True, which='major', color='k', linestyle='-', alpha=0.3) - # axs.grid(b=True, which='minor', color='g', linestyle='-', alpha=0.1) - # axs.set_ylabel('S (rad)') - # axs.set_xlabel('L (ft)') - - # axd.plot(self.xsl,self.deltal) - # axd.plot(self.xsc,self.deltac) - # axd.plot(self.xsr,self.deltar) - # axd.plot(self.xsl,[0]*len(self.xsl)) - # axd.plot(self.xsc,[0]*len(self.xsc)) - # axd.plot(self.xsr,[0]*len(self.xsr)) - # axd.fill_between(self.xsl,self.deltal,[0]*len(self.xsl), facecolor='yellow', alpha=0.2) - # axd.fill_between(self.xsc,self.deltac,[0]*len(self.xsc), facecolor='yellow', alpha=0.2) - # axd.fill_between(self.xsr,self.deltar,[0]*len(self.xsr), facecolor='yellow', alpha=0.2) - # axd.minorticks_on() - # axd.grid(b=True, which='major', color='k', linestyle='-', alpha=0.3) - # axd.grid(b=True, which='minor', color='g', linestyle='-', alpha=0.1) - # axd.set_ylabel('D (in)') - # axd.set_xlabel('L (ft)') - - # plt.tight_layout() - # #plt.subplots_adjust(left=0.125, bottom=0.1, right=0.9, top=0.9, wspace=0.2, hspace=0.4) - - # fig.savefig('simple_beam.pdf', dpi=600) - # plt.close('all') - # self.write_html_results() def multi_solve(self, *args): l_ft = float(self.span_ft.get()) - + fem = [self.fixed_left.get(),self.fixed_right.get()] - + ####################################################################################################### ####################################################################################################### - # Solve Simultaneous equation for internal reactions and fixed end moments knowing + # Solve Simultaneous equation for internal reactions and fixed end moments knowing # deflection and end slopes of simple beam at support points: # # By compatibility for fixed ends initial and final slope should be 0, and deflection @@ -1727,92 +1654,92 @@ def multi_solve(self, *args): # ####################################################################################################### ####################################################################################################### - + #build the coefficient matrix rows and the deflection values delta = [] coeff_matrix = [] - + #Slope at each end of simple beam v0,m0,s0,d0 = self.analysisx(0) vl,ml,sl,dl = self.analysisx(l_ft) - + delta.append(s0[1]) delta.append(sl[1]) - + #Start Moment Component mo = ppbeam.point_moment(1,0,l_ft) ml = ppbeam.point_moment(1,l_ft,l_ft) - + coeff_matrix.append([mo.eisx(0)*fem[0],ml.eisx(0)*fem[1]]) coeff_matrix.append([mo.eisx(l_ft)*fem[0],ml.eisx(l_ft)*fem[1]]) - + if self.internal_supports.get() == '': pass else: reaction_points_string = self.internal_supports.get().split(',') reaction_points = [float(point) for point in reaction_points_string] - + for support in reaction_points: - + l = l_ft a = support - + pl = ppbeam.pl(1,a,l) - + #Deflection at each support location v,m,s,d = self.analysisx(a) delta.append(d[1]) - + coeff_row = [] - + coeff_row.append(mo.eidx(a)*fem[0]) coeff_row.append(ml.eidx(a)*fem[1]) - + for point in reaction_points: - + x = point new_pl = ppbeam.pl(1,x,l) eid_p = new_pl.eidx(a) - + coeff_row.append(eid_p) - + coeff_matrix[0].append(pl.eisx(0)) coeff_matrix[1].append(pl.eisx(l)) - - + + coeff_matrix.append(coeff_row) - + d = np.array(delta) coeff = np.array(coeff_matrix) - + if fem[0] == 0: d = np.delete(d, (0), axis=0) coeff = np.delete(coeff, (0), axis=0) coeff = np.delete(coeff, (0), axis=1) - + if fem == [1,0]: d = np.delete(d, (1), axis=0) coeff = np.delete(coeff, (1), axis=0) coeff = np.delete(coeff, (1), axis=1) - + elif fem == [0,0]: d = np.delete(d, (0), axis=0) coeff = np.delete(coeff, (0), axis=0) coeff = np.delete(coeff, (0), axis=1) else: pass - + R = np.linalg.solve(coeff,d) - + res_string = '' count = 0 if fem == [1,1]: res_string = res_string + 'M,0 = {0:.4f} ft-kips\n'.format(-1*R[0]) res_string = res_string + 'M,L = {0:.4f} ft-kips\n'.format(-1*R[1]) count = 2 - + self.loads_gui_select_var.append([tk.IntVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar()]) - + n = len(self.loads_gui_select_var) self.loads_gui_select_var[n-1][0].set(1) self.loads_gui_select_var[n-1][1].set(-1*R[0]) @@ -1821,9 +1748,9 @@ def multi_solve(self, *args): self.loads_gui_select_var[n-1][4].set(0) self.loads_gui_select_var[n-1][5].set('Center') self.loads_gui_select_var[n-1][6].set('Moment') - + self.loads_gui_select_var.append([tk.IntVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar()]) - + n = len(self.loads_gui_select_var) self.loads_gui_select_var[n-1][0].set(1) self.loads_gui_select_var[n-1][1].set(-1*R[1]) @@ -1832,13 +1759,13 @@ def multi_solve(self, *args): self.loads_gui_select_var[n-1][4].set(0) self.loads_gui_select_var[n-1][5].set('Center') self.loads_gui_select_var[n-1][6].set('Moment') - + elif fem == [1,0]: res_string = res_string + 'M,0 = {0:.4f} ft-kips\n'.format(-1*R[0]) count = 1 - + self.loads_gui_select_var.append([tk.IntVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar()]) - + n = len(self.loads_gui_select_var) self.loads_gui_select_var[n-1][0].set(1) self.loads_gui_select_var[n-1][1].set(-1*R[0]) @@ -1851,9 +1778,9 @@ def multi_solve(self, *args): elif fem == [0,1]: res_string = res_string + 'M,L = {0:.4f} ft-kips\n'.format(-1*R[0]) count = 1 - + self.loads_gui_select_var.append([tk.IntVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar()]) - + n = len(self.loads_gui_select_var) self.loads_gui_select_var[n-1][0].set(1) self.loads_gui_select_var[n-1][1].set(-1*R[0]) @@ -1865,17 +1792,17 @@ def multi_solve(self, *args): else: pass - + if self.internal_supports.get() == '': pass else: for reaction in reaction_points: - + res_string = res_string + 'R @ {0:.3f} ft = {1:.4f} kips\n'.format(reaction,-1*R[count]) - + #Add Redundant Interior Reaction as Point Load on Center Span self.loads_gui_select_var.append([tk.IntVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar()]) - + n = len(self.loads_gui_select_var) self.loads_gui_select_var[n-1][0].set(1) self.loads_gui_select_var[n-1][1].set(-1*R[count]) @@ -1884,11 +1811,11 @@ def multi_solve(self, *args): self.loads_gui_select_var[n-1][4].set(0) self.loads_gui_select_var[n-1][5].set('Center') self.loads_gui_select_var[n-1][6].set('Point') - + count+=1 - + self.multi_result_label.configure(text=res_string) - + self.build_loads_gui() self.build_loads() @@ -1908,19 +1835,19 @@ def draw_static_beam_mouse(self, event, *args): x_screen = event.x x = x_screen - initial - + E = float(self.E_ksi.get()) * 144 #144 is conversion from ksi to ksf - 12^2 I = float(self.I_in4.get()) / 12.0**4 #covert from in^4 to ft^4 - + text_color = 'yellow' - + if x > (ll*sf) and x < ((ll+lc) * sf): x_anal = (x/sf) - ll v,m,s,d = self.analysisx(x_anal) self.val_at_x_text = self.bm_canvas.create_text(w/2.0, (h-26), justify=tk.CENTER, text= '@ Xc = {0:.2f} ft\nV: {1:.2f} kips M: {2:.2f} ft-kips S: {3:.5f} rad D: {4:.4f} in'.format(x_anal,v[1],m[1],s[1]/(E*I),(d[1]/(E*I))*12.0), fill=text_color) - + elif x > ((ll+lc)*sf): x_anal = (x/sf) - (ll+lc) @@ -1940,9 +1867,9 @@ def draw_static_beam_mouse(self, event, *args): self.val_at_x_text = self.bm_canvas.create_text(w/2.0, (h-26), justify=tk.CENTER, text= '@ Xl = {0:.2f} ft\nV: {1:.2f} kips M: {2:.2f} ft-kips S: {3:.5f} rad D: {4:.4f} in'.format(x_anal,v[0],m[0],s[0]/(E*I),(d[0]/(E*I))*12.0), fill=text_color) self.val_at_x = self.bm_canvas.create_line(x_screen, 0,x_screen,h,fill="blue", width=1, dash=(6,6)) - + def write_html_results(self,*args): - + file = open('simple_beam.html','w') file.write('\n') file.write('\n\n') @@ -1950,130 +1877,190 @@ def write_html_results(self,*args): file.write('Simple Beam Diagrams\n') file.write('\n') file.write('\n') file.write('\n\n\n') - file.write('
\n\n
\n') - file.write('
\n\n
\n') - file.write('
\n\n
\n') - file.write('
\n\n
\n') - file.write("\n') + file.write('\n') + file.write('\n\n\n') + file.write('
\n') + file.write('
\n\n') + ins = ['Left Cant. (m):','Center Span (m):','Right Cant. (m):','E (MPa):','I (mm^4):','Stations:','Fixed Left:','Fixed Right:','Interior Supports(m):'] + i=0 + file.write('\n') + file.write('\n') + file.write('\n') + for x in self.inputs: + file.write('\n') + file.write('\n'.format(ins[i])) + file.write('\n'.format(x.get())) + file.write('\n') + i+=1 + file.write('
Inputs:
{0}{0}
\n
\n') + file.write('\n') + file.write('\n') + file.write('\n') + file.write('\n') + file.write('\n\n\n\n\n\n\n\n') + + for load in self.loads_gui_select_var: + if load[0].get() == 1: + file.write('\n') + file.write('\n'.format(load[1].get())) + file.write('\n'.format(load[2].get())) + file.write('\n'.format(load[3].get())) + file.write('\n'.format(load[4].get())) + file.write('\n'.format(load[5].get())) + file.write('\n'.format(load[6].get())) + file.write('\n') + + file.write('
Applied Loads: (includes interior reactions)
P,M, or W1 (kN/kN*m/kN/m)W2 (kN/m)a (m)b (m)LocationLoad Type
{0}{0}{0}{0}{0}{0}
\n
\n') + file.write('\n') + file.write('\n') + file.write('\n') + file.write('\n') + file.write('\n\n\n\n'.format(self.reaction_left)) + file.write('\n\n\n\n'.format(self.reaction_right)) + if self.lc == 0: + pass + else: + file.write('\n\n\n') + for x in self.zero_shear_loc: + v,m,s,d = self.analysisx(x) + file.write('\n\n\n\n'.format(x,m[1])) + file.write('\n\n\n') + + E = float(self.E_ksi.get()) * (1/1000) * (1/math.pow(0.001,2)) #convert Mpa = N/mm^2 to kN/m^2 + I = float(self.I_in4.get()) * (math.pow(0.001,4)) #covert from mm^4 to m^4 + + for x in self.zero_slope_loc: + v,m,s,d = self.analysisx(x) + file.write('\n\n\n\n'.format(x,(d[1]/(E*I))*1000.0)) + + file.write('
Results:
Reaction Left (kN):{0:.4f}
Reaction Right (kN):{0:.4f}
Center Span Max/Min Moments (kN*m):
@{0:.4f} m{1:.4f}
Center Span Max/Min Deflections (mm):
@{0:.3E} m{1:.4f}
\n
\n
\n
\n') + # Equations + if self.lc == 0: + pass + else: + file.write('

Center Span Piecewise Functions

\n
\n{0}
\n'.format(ppbeam.PieceFunctionStringHTMLTable(self.piece_eq_center[0],'Shear (kN):'))) + file.write('{0}
\n'.format(ppbeam.PieceFunctionStringHTMLTable(self.piece_eq_center[1],'Moment (kN*m):'))) + file.write('{0}
\n'.format(ppbeam.PieceFunctionStringHTMLTable(self.piece_eq_center[2],'EI*Slope (rads): [convert EI from mm to m first]'))) + file.write('{0}
\n'.format(ppbeam.PieceFunctionStringHTMLTable(self.piece_eq_center[3],'(EI/1000.0)*Deflection (mm):[convert EI from mm to m first]'))) + + file.write('
\n\n') + file.write('\n') + file.write('\n') + file.write('\n
\n') + file.write('\n') + + file.write("\n') + file.write('\n') + file.write('\n') + file.close() + + webbrowser.open('file://'+ os.path.realpath('simple_beam.html')) + + def piece_function_gen(self, *event): + eq, eqs = ppbeam.center_span_piecewise_function(self.loads_piece) + + self.zero_shear_loc = ppbeam.points_of_zero_shear(eq[0]) + + self.zero_moment_loc = ppbeam.points_of_zero_shear(eq[1]) + + self.zero_slope_loc = ppbeam.points_of_zero_shear(eq[2]) + + self.pfunc_text_box.delete(1.0,tk.END) + + string = 'Shear:\nPoints of 0 Shear:' + + for x in self.zero_shear_loc: + string = string + ' {0:.4f} m '.format(x) + + string = string + '\n' + string = string + eqs[0] + + string = string + '\nMoment:\nPoints of 0 Moment:' + + for x in self.zero_moment_loc: + string = string + ' {0:.4f} m '.format(x) + + string = string + '\n' + string = string + eqs[1] + + string = string + '\nEI*Slope:\nPoints of 0 Slope:' + + for x in self.zero_slope_loc: + string = string + ' {0:.4f} m '.format(x) + + string = string + '\n' + string = string + eqs[2] + + string = string + '\n(EI/1000.0)*Deflection:\n' + string = string + eqs[3] + + self.pfunc_text_box.insert(tk.END, string) + + color = "pale green" + self.pfunc_text_box.tag_configure("odd", background=color) + self.pfunc_text_box.tag_configure("even", background="#ffffff") + + lastline = self.pfunc_text_box.index("end-1c").split(".")[0] + tag = "odd" + for i in range(1, int(lastline)): + self.pfunc_text_box.tag_add(tag, "%s.0" % i, "%s.0" % (i+1)) + tag = "even" if tag == "odd" else "odd" + + self.piece_eq_center = eq + + def save_inputs(self, *args): + + out_file = tkFileDialog.asksaveasfile(mode='w', defaultextension=".simpbm") + + if out_file is None: + return + + for data in self.inputs: + text = '{0}\n'.format(data.get()) + out_file.write(text) + + out_file.write('*Loads*\n') + for load in self.loads_gui_select_var: + text = '{0},{1},{2},{3},{4},{5},{6}\n'.format(load[0].get(),load[1].get(),load[2].get(),load[3].get(),load[4].get(),load[5].get(),load[6].get()) + out_file.write(text) + out_file.close() + + def open_existing(self, *args): + + filename = tkFileDialog.askopenfilename() + + extension = filename.split('.')[-1] + + del self.loads_gui_select_var[:] + + if filename is None: + return + elif extension not in ['simpbm']: + tkMessageBox.showerror("ERROR!!","Selected File not a .simpbm file") + return + else: + calc_file = open(filename,'rU') + calc_data = calc_file.readlines() + calc_file.close() + + i=0 + load_section = 0 + for line in calc_data: + value = line.rstrip('\n') + if value == '*Loads*': + load_section = 1 + elif load_section == 0: + self.inputs[i].set(value) + else: + load = value.split(',') + + self.loads_gui_select_var.append([tk.IntVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar(), tk.StringVar()]) + + n = len(self.loads_gui_select_var) + self.loads_gui_select_var[n-1][0].set(load[0]) + self.loads_gui_select_var[n-1][1].set(load[1]) + self.loads_gui_select_var[n-1][2].set(load[2]) + self.loads_gui_select_var[n-1][3].set(load[3]) + self.loads_gui_select_var[n-1][4].set(load[4]) + self.loads_gui_select_var[n-1][5].set(load[5]) + self.loads_gui_select_var[n-1][6].set(load[6]) + + i+=1 + + self.build_loads_gui() + self.build_loads() + +def main(): + root = tk.Tk() + root.title("Simple Beam") + Master_window(root) + root.minsize(1280,720) + root.mainloop() + +if __name__ == '__main__': + main() diff --git a/Analysis/simple_beam_output_example.html b/Analysis/simple_beam_output_example.html new file mode 100644 index 0000000..b23c7ca --- /dev/null +++ b/Analysis/simple_beam_output_example.html @@ -0,0 +1,1749 @@ + + + + +Simple Beam Diagrams + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Inputs:
Left Cant. (ft):0.0
Center Span (ft):30
Right Cant. (ft):0
E (ksi):29000
I (in^4):30.8
Stations:50
Fixed Left:0
Fixed Right:0
Interior Supports(ft):10,20
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Applied Loads: (includes interior reactions)
P,M, or W1 (kips/ft-kips/klf)W2 (klf)a (ft)b (ft)LocationLoad Type
10010CenterUDL
102030CenterUDL
-5.5010.00CenterPoint
-5.5020.00CenterPoint
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Results:
Reaction Left (kips):4.5000
Reaction Right (kips):4.5000
Center Span Max/Min Moments (ft-kips):
@4.5000 ft10.1250
@25.5000 ft10.1250
@20.0000 ft-5.0000
Center Span Max/Min Deflections (in):
@4.7926 ft-0.1919
@15.0000 ft0.1209
@25.2074 ft-0.1919
+
+ + + + + + + + + + + + + + + + + + + + + + +
Shear (kips):
0.0000 < x <= 10.0000:
4.5000-1.0000*x
10.0000 < x <= 20.0000:
-0.0000
20.0000 < x <= 30.0000:
25.5000-1.0000*x
+
+ + + + + + + + + + + + + + + + + + + + + + +
Moment (kip-ft):
0.0000 < x <= 10.0000:
4.5000*x-0.5000*x2
10.0000 < x <= 20.0000:
-5.0000-0.0000*x
20.0000 < x <= 30.0000:
-315.0000+25.5000*x-0.5000*x2
+
+ + + + + + + + + + + + + + + + + + + + + + +
EI*Slope (rads): [convert EI from inch to ft first]
0.0000 < x <= 10.0000:
-33.3333+2.2500*x2-0.1667*x3
10.0000 < x <= 20.0000:
75.0000-5.0000*x-0.0000*x2
20.0000 < x <= 30.0000:
2508.3333-315.0000*x+12.7500*x2-0.1667*x3
+
+ + + + + + + + + + + + + + + + + + + + + + +
(EI/12)*Deflection (in):[convert EI from inch to ft first]
0.0000 < x <= 10.0000:
-33.3333*x+0.7500*x3-0.0417*x4
10.0000 < x <= 20.0000:
-500.0000+75.0000*x-2.5000*x2-0.0000*x3
20.0000 < x <= 30.0000:
-14500.0000+2508.3333*x-157.5000*x2+4.2500*x3-0.0417*x4
+
+
+
+ + + + +
+
+ + + diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_center_points_2_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_center_points_2_span.simpbm new file mode 100644 index 0000000..e073fb4 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_center_points_2_span.simpbm @@ -0,0 +1,13 @@ +0.0 +20 +0.0 +29000 +30.8 +200 +0 +0 +10 +*Loads* +1,1,0,5,0,Center,Point +1,1,0,15,0,Center,Point +1,-1.375,0,10.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_center_points_3_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_center_points_3_span.simpbm new file mode 100644 index 0000000..7e7441a --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_center_points_3_span.simpbm @@ -0,0 +1,15 @@ +0.0 +30 +0.0 +29000 +30.8 +200 +0 +0 +10,20 +*Loads* +1,1,0,5,0,Center,Point +1,1,0,15,0,Center,Point +1,1,0,25,0,Center,Point +1,-1.15,0,10.0,0,Center,Point +1,-1.15,0,20.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_center_points_5_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_center_points_5_span.simpbm new file mode 100644 index 0000000..a4094d8 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_center_points_5_span.simpbm @@ -0,0 +1,19 @@ +0.0 +50 +0.0 +29000 +30.8 +200 +0 +0 +10,20,30,40 +*Loads* +1,1,0,5,0,Center,Point +1,1,0,15,0,Center,Point +1,1,0,25,0,Center,Point +1,1,0,35,0,Center,Point +1,1,0,45,0,Center,Point +1,-1.19736842105,0,10.0,0,Center,Point +1,-0.960526315789,0,20.0,0,Center,Point +1,-0.960526315789,0,30.0,0,Center,Point +1,-1.19736842105,0,40.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_quarter_points_2_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_quarter_points_2_span.simpbm new file mode 100644 index 0000000..8f948b9 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_quarter_points_2_span.simpbm @@ -0,0 +1,17 @@ +0.0 +20 +0.0 +29000 +30.8 +200 +0 +0 +10 +*Loads* +1,1,0,2.5,0,Center,Point +1,1,0,5,0,Center,Point +1,1,0,7.5,0,Center,Point +1,1,0,12.5,0,Center,Point +1,1,0,15,0,Center,Point +1,1,0,17.5,0,Center,Point +1,-3.9375,0,10.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_quarter_points_3_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_quarter_points_3_span.simpbm new file mode 100644 index 0000000..fde15e3 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_quarter_points_3_span.simpbm @@ -0,0 +1,21 @@ +0.0 +30 +0.0 +29000 +30.8 +200 +0 +0 +10,20 +*Loads* +1,1,0,2.5,0,Center,Point +1,1,0,5,0,Center,Point +1,1,0,7.5,0,Center,Point +1,1,0,12.5,0,Center,Point +1,1,0,15,0,Center,Point +1,1,0,17.5,0,Center,Point +1,1,0,22.5,0,Center,Point +1,1,0,27.5,0,Center,Point +1,1,0,25,0,Center,Point +1,-3.375,0,10.0,0,Center,Point +1,-3.375,0,20.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_quarter_points_5_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_quarter_points_5_span.simpbm new file mode 100644 index 0000000..fb40e37 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_quarter_points_5_span.simpbm @@ -0,0 +1,29 @@ +0.0 +50 +0.0 +29000 +30.8 +200 +0 +0 +10,20,30,40 +*Loads* +1,1,0,2.5,0,Center,Point +1,1,0,5,0,Center,Point +1,1,0,7.5,0,Center,Point +1,1,0,12.5,0,Center,Point +1,1,0,15,0,Center,Point +1,1,0,17.5,0,Center,Point +1,1,0,22.5,0,Center,Point +1,1,0,27.5,0,Center,Point +1,1,0,25,0,Center,Point +1,1,0,32.5,0,Center,Point +1,1,0,35,0,Center,Point +1,1,0,37.5,0,Center,Point +1,1,0,42.5,0,Center,Point +1,1,0,45,0,Center,Point +1,1,0,47.5,0,Center,Point +1,-3.49342105263,0,10.0,0,Center,Point +1,-2.90131578947,0,20.0,0,Center,Point +1,-2.90131578947,0,30.0,0,Center,Point +1,-3.49342105263,0,40.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_third_points_2_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_third_points_2_span.simpbm new file mode 100644 index 0000000..55b6928 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_third_points_2_span.simpbm @@ -0,0 +1,15 @@ +0.0 +20 +0.0 +29000 +30.8 +200 +0 +0 +10 +*Loads* +1,1,0,3.33333,0,Center,Point +1,1,0,6.66666,0,Center,Point +1,1,0,13.33333,0,Center,Point +1,1,0,16.66666,0,Center,Point +1,-2.66666683333,0,10.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_third_points_3_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_third_points_3_span.simpbm new file mode 100644 index 0000000..e265c17 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_third_points_3_span.simpbm @@ -0,0 +1,18 @@ +0.0 +30 +0.0 +29000 +30.8 +200 +0 +0 +10,20 +*Loads* +1,1,0,3.33333,0,Center,Point +1,1,0,6.66666,0,Center,Point +1,1,0,13.33333,0,Center,Point +1,1,0,16.66666,0,Center,Point +1,1,0,26.66666,0,Center,Point +1,1,0,23.33333,0,Center,Point +1,-2.26666673333,0,10.0,0,Center,Point +1,-2.26666673333,0,20.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_third_points_5_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_third_points_5_span.simpbm new file mode 100644 index 0000000..617abb8 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_point_load_at_third_points_5_span.simpbm @@ -0,0 +1,24 @@ +0.0 +50 +0.0 +29000 +30.8 +200 +0 +0 +10,20,30,40 +*Loads* +1,1,0,3.33333,0,Center,Point +1,1,0,6.66666,0,Center,Point +1,1,0,13.33333,0,Center,Point +1,1,0,16.66666,0,Center,Point +1,1,0,26.66666,0,Center,Point +1,1,0,36.66666,0,Center,Point +1,1,0,46.66666,0,Center,Point +1,1,0,23.33333,0,Center,Point +1,1,0,33.33333,0,Center,Point +1,1,0,43.33333,0,Center,Point +1,-2.3508772807,0,10.0,0,Center,Point +1,-1.92982454386,0,20.0,0,Center,Point +1,-1.92982454386,0,30.0,0,Center,Point +1,-2.3508772807,0,40.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_2_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_2_span.simpbm new file mode 100644 index 0000000..13b23a7 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_2_span.simpbm @@ -0,0 +1,12 @@ +0.0 +20 +0.0 +29000 +30.8 +50 +0 +0 +10 +*Loads* +1,1,0,0,20,Center,UDL +1,-12.5,0,10.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_3_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_3_span.simpbm new file mode 100644 index 0000000..1e91dca --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_3_span.simpbm @@ -0,0 +1,13 @@ +0.0 +30 +0.0 +29000 +30.8 +50 +0 +0 +10,20 +*Loads* +1,1,0,0,30,Center,UDL +1,-11.0,0,10.0,0,Center,Point +1,-11.0,0,20.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_4_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_4_span.simpbm new file mode 100644 index 0000000..2744847 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_4_span.simpbm @@ -0,0 +1,14 @@ +0.0 +40 +0.0 +29000 +30.8 +50 +0 +0 +10,20,30 +*Loads* +1,1,0,0,40,Center,UDL +1,-11.4285714286,0,10.0,0,Center,Point +1,-9.28571428571,0,20.0,0,Center,Point +1,-11.4285714286,0,30.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_5_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_5_span.simpbm new file mode 100644 index 0000000..e63c8a9 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_5_span.simpbm @@ -0,0 +1,15 @@ +0.0 +50 +0.0 +29000 +30.8 +50 +0 +0 +10,20,30,40 +*Loads* +1,1,0,0,50,Center,UDL +1,-11.3157894737,0,10.0,0,Center,Point +1,-9.73684210526,0,20.0,0,Center,Point +1,-9.73684210526,0,30.0,0,Center,Point +1,-11.3157894737,0,40.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_6_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_6_span.simpbm new file mode 100644 index 0000000..c70cf1e --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_6_span.simpbm @@ -0,0 +1,16 @@ +0.0 +60 +0.0 +29000 +30.8 +50 +0 +0 +10,20,30,40,50 +*Loads* +1,1,0,0,60,Center,UDL +1,-11.3461538462,0,10.0,0,Center,Point +1,-9.61538461538,0,20.0,0,Center,Point +1,-10.1923076923,0,30.0,0,Center,Point +1,-9.61538461539,0,40.0,0,Center,Point +1,-11.3461538462,0,50.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_7_span.simpbm b/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_7_span.simpbm new file mode 100644 index 0000000..531f173 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_22c_uniform_load_7_span.simpbm @@ -0,0 +1,17 @@ +0.0 +70 +0.0 +29000 +30.8 +200 +0 +0 +10,20,30,40,50,60 +*Loads* +1,1,0,0,70,Center,UDL +1,-11.338028169,0,10.0,0,Center,Point +1,-9.64788732394,0,20.0,0,Center,Point +1,-10.0704225352,0,30.0,0,Center,Point +1,-10.0704225352,0,40.0,0,Center,Point +1,-9.64788732394,0,50.0,0,Center,Point +1,-11.338028169,0,60.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex01.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex01.simpbm new file mode 100644 index 0000000..61b665d --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex01.simpbm @@ -0,0 +1,11 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,0,10,Center,UDL diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex02.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex02.simpbm new file mode 100644 index 0000000..5e43edc --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex02.simpbm @@ -0,0 +1,11 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,0,1,0,10,Center,TRAP diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex03.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex03.simpbm new file mode 100644 index 0000000..591b737 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex03.simpbm @@ -0,0 +1,12 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,0,1,0,5,Center,TRAP +1,1,0,5,10,Center,TRAP diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex04.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex04.simpbm new file mode 100644 index 0000000..159bdc4 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex04.simpbm @@ -0,0 +1,11 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,3,5,Center,UDL diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex05.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex05.simpbm new file mode 100644 index 0000000..211aef4 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex05.simpbm @@ -0,0 +1,11 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,0,3,Center,UDL diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex06.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex06.simpbm new file mode 100644 index 0000000..3602fe3 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex06.simpbm @@ -0,0 +1,12 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,0,3,Center,UDL +1,0.5,0,7,10,Center,UDL diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex07.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex07.simpbm new file mode 100644 index 0000000..3e093c0 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex07.simpbm @@ -0,0 +1,11 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,5,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex08.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex08.simpbm new file mode 100644 index 0000000..11612ad --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex08.simpbm @@ -0,0 +1,11 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,8,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex09.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex09.simpbm new file mode 100644 index 0000000..d9c310d --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex09.simpbm @@ -0,0 +1,12 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,3,0,Center,Point +1,1,0,7,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex10.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex10.simpbm new file mode 100644 index 0000000..841f1e4 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex10.simpbm @@ -0,0 +1,12 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,3,0,Center,Point +1,1,0,6,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex11.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex11.simpbm new file mode 100644 index 0000000..33ce819 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex11.simpbm @@ -0,0 +1,12 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,3,0,Center,Point +1,0.5,0,6,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex12.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex12.simpbm new file mode 100644 index 0000000..6cbedbf --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex12.simpbm @@ -0,0 +1,12 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +1 + +*Loads* +1,1,0,0,10,Center,UDL +1,12.5,0,10.0,0,Center,Moment diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex13.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex13.simpbm new file mode 100644 index 0000000..f2f0c73 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex13.simpbm @@ -0,0 +1,12 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +1 + +*Loads* +1,1,0,5,0,Center,Point +1,1.875,0,10.0,0,Center,Moment diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex14.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex14.simpbm new file mode 100644 index 0000000..0c0d6c2 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex14.simpbm @@ -0,0 +1,12 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +1 + +*Loads* +1,1,0,3,0,Center,Point +1,1.365,0,10.0,0,Center,Moment diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex15.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex15.simpbm new file mode 100644 index 0000000..52a505d --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex15.simpbm @@ -0,0 +1,13 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +1 +1 + +*Loads* +1,1,0,0,10,Center,UDL +1,-8.33333333333,0,0,0,Center,Moment +1,8.33333333333,0,10.0,0,Center,Moment diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex16.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex16.simpbm new file mode 100644 index 0000000..81c6ba5 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex16.simpbm @@ -0,0 +1,13 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +1 +1 + +*Loads* +1,1,0,5,0,Center,Point +1,-1.25,0,0,0,Center,Moment +1,1.25,0,10.0,0,Center,Moment diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex17.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex17.simpbm new file mode 100644 index 0000000..910637f --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex17.simpbm @@ -0,0 +1,13 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +1 +1 + +*Loads* +1,1,0,7,0,Center,Point +1,-0.63,0,0,0,Center,Moment +1,1.47,0,10.0,0,Center,Moment diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex18.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex18.simpbm new file mode 100644 index 0000000..dd19236 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex18.simpbm @@ -0,0 +1,11 @@ +5 +0 +0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,0,1,0,5,Left,TRAP diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex19.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex19.simpbm new file mode 100644 index 0000000..c1a1278 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex19.simpbm @@ -0,0 +1,11 @@ +5 +0 +0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,0,5,Left,UDL diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex20.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex20.simpbm new file mode 100644 index 0000000..691e378 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex20.simpbm @@ -0,0 +1,12 @@ +5 +0 +0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,0,5,Left,UDL +1,4.16667,0,0,0,Left,Moment diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex21.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex21.simpbm new file mode 100644 index 0000000..24fb76e --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex21.simpbm @@ -0,0 +1,11 @@ +5 +0 +0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,2,0,Left,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex22.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex22.simpbm new file mode 100644 index 0000000..7698163 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex22.simpbm @@ -0,0 +1,11 @@ +5 +0 +0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,0,0,Left,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex23.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex23.simpbm new file mode 100644 index 0000000..d19da46 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex23.simpbm @@ -0,0 +1,12 @@ +5 +0 +0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,0,0,Left,Point +1,2.5,0,0,0,Left,Moment diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex24.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex24.simpbm new file mode 100644 index 0000000..d012096 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex24.simpbm @@ -0,0 +1,12 @@ +0.0 +10.0 +5 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,0,10,Center,UDL +1,1,0,0,5,Right,UDL diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex25.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex25.simpbm new file mode 100644 index 0000000..13244c1 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex25.simpbm @@ -0,0 +1,11 @@ +0.0 +10.0 +5 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,0,5,Right,UDL diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex26.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex26.simpbm new file mode 100644 index 0000000..73e2671 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex26.simpbm @@ -0,0 +1,11 @@ +0.0 +10.0 +5 +29000 +30.8 +25 +1 +0 + +*Loads* +1,1,0,5,0,Right,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex27.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex27.simpbm new file mode 100644 index 0000000..3d9b506 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex27.simpbm @@ -0,0 +1,11 @@ +0.0 +10.0 +5 +29000 +30.8 +25 +1 +0 + +*Loads* +1,1,0,0,10,Center,UDL diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex28.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex28.simpbm new file mode 100644 index 0000000..3ad15ba --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex28.simpbm @@ -0,0 +1,11 @@ +0.0 +10.0 +5 +29000 +30.8 +25 +1 +0 + +*Loads* +1,1,0,3,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex29.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex29.simpbm new file mode 100644 index 0000000..ed68cb9 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex29.simpbm @@ -0,0 +1,12 @@ +0.0 +20 +0 +29000 +30.8 +25 +0 +0 +10 +*Loads* +1,1,0,0,10,Center,UDL +1,-6.25,0,10.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex30.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex30.simpbm new file mode 100644 index 0000000..16efaa3 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex30.simpbm @@ -0,0 +1,12 @@ +0.0 +20 +0 +29000 +30.8 +25 +0 +0 +10 +*Loads* +1,1,0,5,0,Center,Point +1,-0.6875,0,10.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex31.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex31.simpbm new file mode 100644 index 0000000..f7ea90a --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex31.simpbm @@ -0,0 +1,12 @@ +0.0 +20 +0 +29000 +30.8 +25 +0 +0 +10 +*Loads* +1,1,0,7,0,Center,Point +1,-0.8785,0,10.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex32.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex32.simpbm new file mode 100644 index 0000000..8623328 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex32.simpbm @@ -0,0 +1,13 @@ +0.0 +10 +0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,0,10,Center,UDL +1,-10,0,0,0,Center,Moment +1,5,0,10,0,Center,Moment diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex33.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex33.simpbm new file mode 100644 index 0000000..5e3628d --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex33.simpbm @@ -0,0 +1,13 @@ +0.0 +10 +0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,5,0,Center,Point +1,-1,0,0,0,Center,Moment +1,0.5,0,10,0,Center,Moment diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex34.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex34.simpbm new file mode 100644 index 0000000..56d84e2 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex34.simpbm @@ -0,0 +1,12 @@ +0.0 +10 +0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,0,5,Center,TRAP +1,0,1,5,10,Center,TRAP diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex35.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex35.simpbm new file mode 100644 index 0000000..5481cff --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex35.simpbm @@ -0,0 +1,11 @@ +0.0 +10 +0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,0,0,Center,Moment diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex36.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex36.simpbm new file mode 100644 index 0000000..d34a0de --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex36.simpbm @@ -0,0 +1,11 @@ +0.0 +10 +0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,1,0,3,0,Center,Moment diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex37.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex37.simpbm new file mode 100644 index 0000000..6c90d21 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex37.simpbm @@ -0,0 +1,13 @@ +0.0 +30 +0 +29000 +30.8 +25 +0 +0 +10,20 +*Loads* +1,1,0,0,20,Center,UDL +1,-12.0,0,10.0,0,Center,Point +1,-4.5,0,20.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex38.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex38.simpbm new file mode 100644 index 0000000..21f1801 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex38.simpbm @@ -0,0 +1,14 @@ +0.0 +30 +0 +29000 +30.8 +25 +0 +0 +10,20 +*Loads* +1,1,0,0,10,Center,UDL +1,1,0,20,30,Center,UDL +1,-5.5,0,10.0,0,Center,Point +1,-5.5,0,20.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex39.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex39.simpbm new file mode 100644 index 0000000..14244a8 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex39.simpbm @@ -0,0 +1,13 @@ +0.0 +30 +0 +29000 +30.8 +25 +0 +0 +10,20 +*Loads* +1,1,0,0,30,Center,UDL +1,-11.0,0,10.0,0,Center,Point +1,-11.0,0,20.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex40.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex40.simpbm new file mode 100644 index 0000000..0368250 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex40.simpbm @@ -0,0 +1,15 @@ +0.0 +40 +0 +29000 +30.8 +25 +0 +0 +10,20,30 +*Loads* +1,1,0,0,20,Center,UDL +1,1,0,30,40,Center,UDL +1,-12.2321428571,0,10.0,0,Center,Point +1,-3.57142857143,0,20.0,0,Center,Point +1,-5.98214285714,0,30.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex41.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex41.simpbm new file mode 100644 index 0000000..3e4a776 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex41.simpbm @@ -0,0 +1,15 @@ +0.0 +40 +0 +29000 +30.8 +25 +0 +0 +10,20,30 +*Loads* +1,1,0,0,10,Center,UDL +1,1,0,20,30,Center,UDL +1,-5.71428571429,0,10.0,0,Center,Point +1,-4.64285714286,0,20.0,0,Center,Point +1,-5.71428571429,0,30.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/aisc_table_3_23_ex42.simpbm b/Analysis/simple_beam_validation/aisc_table_3_23_ex42.simpbm new file mode 100644 index 0000000..bb745b7 --- /dev/null +++ b/Analysis/simple_beam_validation/aisc_table_3_23_ex42.simpbm @@ -0,0 +1,14 @@ +0.0 +40 +0 +29000 +30.8 +25 +0 +0 +10,20,30 +*Loads* +1,1,0,0,40,Center,UDL +1,-11.4285714286,0,10.0,0,Center,Point +1,-9.28571428571,0,20.0,0,Center,Point +1,-11.4285714286,0,30.0,0,Center,Point diff --git a/Analysis/simple_beam_validation/unit_rotation_at_0_Ma_4EI_L_Mb_2EI_L.simpbm b/Analysis/simple_beam_validation/unit_rotation_at_0_Ma_4EI_L_Mb_2EI_L.simpbm new file mode 100644 index 0000000..b5eb090 --- /dev/null +++ b/Analysis/simple_beam_validation/unit_rotation_at_0_Ma_4EI_L_Mb_2EI_L.simpbm @@ -0,0 +1,12 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,2481.11,0,0,0,Center,Moment +1,1240.56,0,10,0,Center,Moment diff --git a/Analysis/simple_beam_validation/unit_rotation_at_L_Ma_2EI_L_Mb_4EI_L.simpbm b/Analysis/simple_beam_validation/unit_rotation_at_L_Ma_2EI_L_Mb_4EI_L.simpbm new file mode 100644 index 0000000..5105912 --- /dev/null +++ b/Analysis/simple_beam_validation/unit_rotation_at_L_Ma_2EI_L_Mb_4EI_L.simpbm @@ -0,0 +1,12 @@ +0.0 +10.0 +0.0 +29000 +30.8 +25 +0 +0 + +*Loads* +1,2481.11,0,10,0,Center,Moment +1,1240.56,0,0,0,Center,Moment diff --git a/Analysis/testing_file.py b/Analysis/testing_file.py deleted file mode 100644 index d83dabc..0000000 --- a/Analysis/testing_file.py +++ /dev/null @@ -1,85 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu Mar 29 17:35:53 2018 - -@author: DonB -""" - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - -import pin_pin_beam_equations_classes as ppbeam -import matplotlib.pyplot as plt -import datetime - -import three_moment_method_e as tmm - -L = 30.0 #ft - -E = 29000.00 * 144 #144 is conversion from ksi to ksf - 12^2 -I = 30.8 / 12.0**4 #covert from in^4 to ft^4 - -#Left Cantilever Loads -#loads = [ppbeam.cant_left_point(1,0,l,0), -# ppbeam.cant_left_point_moment(1,(l*0.5),l,0), -# ppbeam.cant_left_udl(1,0,l,l,0), -# ppbeam.cant_left_trap(0,1,0,l,l,0)] - -#Right Cantilever Loads -#loads = [ppbeam.cant_right_trap(1,0,0,l,l,0)] - -#Single Span Loads -loads = [ppbeam.udl(1,0,30,L)] - - -stations = 500 - -start_t = datetime.datetime.now() -#Cantilever Analysis -#analysis = ppbeam.fixed_free_right_by_stations(loads, stations) -analysis = ppbeam.pin_pin_single_span_by_stations(loads, stations) - -interior = [10,20] - -delta = [analysis[5][0],analysis[5][-1]] - -for support in interior: - - delta.append(ppbeam.pin_pin_single_span_at_x(loads,support)[3]) - -R, reaction_loads = ppbeam.single_span_solve_fixed_ends_and_redundant_interiors(delta, interior, L, [0,0]) - -loads = loads + reaction_loads - -analysis = ppbeam.pin_pin_single_span_by_stations(loads, stations) - -end_t = datetime.datetime.now() - -analysis_time = end_t - start_t - -start_t = datetime.datetime.now() - -w = 1000/12.0 -test_3mm = tmm.three_moment_method([120.0,120.0,120.0],[30.8,30.8,30.8],'N',[[w,w,0,120,'UDL',0],[w,w,0,120,'UDL',1],[w,w,0,120,'UDL',2]], 29000000.00,167,[0,0,0,0]) - -end_t = datetime.datetime.now() - -analysis_3mm_time = end_t - start_t - -results_3mm = test_3mm.res() - - -print 'Analysis: {0}'.format(analysis_time) -print 'Analysis - 3mm: {0}'.format(analysis_3mm_time) \ No newline at end of file diff --git a/Analysis/three_moment_method.py b/Analysis/three_moment_method.py index 68b5922..81ddfc2 100644 --- a/Analysis/three_moment_method.py +++ b/Analysis/three_moment_method.py @@ -1,18 +1,28 @@ -#!/usr/bin/env python - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import numpy as np @@ -20,6 +30,8 @@ import scipy as sci import scipy.integrate +#import time + def pl(p, a, l, x): b = l - a rl = (p * b) / l @@ -638,4 +650,10 @@ def __init__(self,beam_spans=[120.00], beam_momentofinertia=[120.00], cant='N', self.R = R self.M = M - +''' +start = time.time() +test = three_moment_method([60,120,120,60],[30.8,30.8,30.8,30.8],'B',[[1000.00,1000.00,60.0,60.0,'POINT',1]], 29000000.00, 20, [0,0,0,0,0]) +end = time.time() +t = end-start +m = test.m_diag +''' \ No newline at end of file diff --git a/Analysis/three_moment_method_e.py b/Analysis/three_moment_method_e.py index c5c97d7..6ca4ad0 100644 --- a/Analysis/three_moment_method_e.py +++ b/Analysis/three_moment_method_e.py @@ -1,18 +1,28 @@ -#!/usr/bin/env python - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import numpy as np @@ -22,9 +32,11 @@ import pin_pin_beam_equations_classes as ppbeam import math +import time + class three_moment_method(object): - def __init__(self,beam_spans=[120.00], beam_momentofinertia=[120.00], cant='N', beam_loads_raw=[[1000.00,1000.00,60.00,60.00,'POINT',0]], E=29000000.00, iters=100, displace=[0,0]): + def __init__(self,beam_spans=[120.00], beam_momentofinertia=[120.00], cant='N', beam_loads_raw=[[1000.00,1000.00,60.00,60.00,'POINT',0]], E=29000000.00, iters=20, displace=[0,0]): # Implementation of the Theory of Three Momements, https://en.wikipedia.org/wiki/Theorem_of_three_moments # Inputs: # beam_spans = a list of span lengths -- Expected Units: in -- Example: [120,120] @@ -92,8 +104,39 @@ def __init__(self,beam_spans=[120.00], beam_momentofinertia=[120.00], cant='N', sumL = np.cumsum(beam_spans) # cumulative sum of beam lengths sumL = sumL.tolist() - - xs = np.zeros((iters+1, N)) + + #Additional calculation stations at point loads +/-0.0001 and start and end of line loads + xs_add = []#create a list of 0's x N - to add additional stations per span + + for s in range(0,N): + xs_add.append([]) + + for load in beam_loads_raw: + if load[4] == 'POINT' or load[4] == "POINT_MOMENT": + inspan = int(load[5]) + xs_add[inspan].append(load[2]) + if load[2]+0.0001 > beam_spans[inspan]: + pass + else: + xs_add[inspan].append(load[2]+0.0001) + if load[2]-0.0001 < beam_spans[inspan]: + pass + else: + xs_add[inspan].append(load[2]-0.0001) + else: + inspan = int(load[5]) + xs_add[inspan].append(load[2]) + xs_add[inspan].append(load[3]) + + xs_add = [list(set(i)) for i in xs_add] + max_plus = max([len(i) for i in xs_add]) + [i.extend([0]*(max_plus-len(i))) for i in xs_add if len(i) < max_plus] + + self.add_stations = xs_add + + #Create calculation stations + new_iters = iters+max_plus+1 + xs = np.zeros((new_iters, N)) j = 0 for j in range(0, N): xs[0, j] = 0 @@ -101,15 +144,26 @@ def __init__(self,beam_spans=[120.00], beam_momentofinertia=[120.00], cant='N', i = 0 for i in range(1, iters): xs[i, j] = xs[i-1, j] + beam_spans[j]/iters - - v_diag = np.zeros((iters+1, N)) - v_diag_cantL = np.zeros((iters+1, N)) - v_diag_cantR = np.zeros((iters+1, N)) - m_diag = np.zeros((iters+1, N)) - m_diag_cantL = np.zeros((iters+1, N)) - m_diag_cantR = np.zeros((iters+1, N)) - s_diag = np.zeros((iters+1, N)) - d_diag = np.zeros((iters+1, N)) + + z=0 + for i in range((iters+1),(new_iters)): + xs[i,j] = xs_add[j][z] + z+=1 + j = 0 + for j in range(0, N): + to_sort = xs[:,j].tolist() + to_sort.sort() + xs[:,j] = np.asarray(to_sort) + + self.stations = xs + v_diag = np.zeros((new_iters, N)) + v_diag_cantL = np.zeros((new_iters, N)) + v_diag_cantR = np.zeros((new_iters, N)) + m_diag = np.zeros((new_iters, N)) + m_diag_cantL = np.zeros((new_iters, N)) + m_diag_cantR = np.zeros((new_iters, N)) + s_diag = np.zeros((new_iters, N)) + d_diag = np.zeros((new_iters, N)) r_span = np.zeros((2, N)) # Span as simple support Moment, Shears, and Reactions @@ -168,6 +222,7 @@ def __init__(self,beam_spans=[120.00], beam_momentofinertia=[120.00], cant='N', d_diag[:, j] = d_diag[:, j]+d r_span[0, j] = r_span[0, j]+load.rl r_span[1, j] = r_span[1, j]+load.rr + elif loads[4] == "NL": load = ppbeam.no_load() v = load.v(xs[:,j]) @@ -188,20 +243,23 @@ def __init__(self,beam_spans=[120.00], beam_momentofinertia=[120.00], cant='N', # Horizontal center of moment region j = 0 a_xl_xr = np.zeros((3, N)) - m_xx = np.zeros((iters+1, N)) + m_xx = np.zeros((new_iters, N)) for j in range(0, N): m_xx[:, j] = m_diag[:, j]*xs[:, j] - A = sci.integrate.simps(m_diag[:, j], xs[:, j]) + A = sci.integrate.cumtrapz(m_diag[:, j], xs[:, j]) + A = A[-1] + print A a_xl_xr[0, j] = A if A == 0: a_xl_xr[1, j] = 0 a_xl_xr[2, j] = 0 else: - xl = (1/A)*sci.integrate.simps(m_xx[:, j], xs[:, j]) + xl_A = sci.integrate.cumtrapz(m_xx[:, j], xs[:, j]) + xl = (1/A)*xl_A[-1] a_xl_xr[1, j] = xl a_xl_xr[2, j] = beam_spans[j] - xl - + # Cantilever Moments, Shears, and reactions mr_cant = 0 ml_cant = 0 @@ -471,31 +529,41 @@ def __init__(self,beam_spans=[120.00], beam_momentofinertia=[120.00], cant='N', s_diag[:, j] = s_diag[:, j]+s d_diag[:, j] = d_diag[:, j]+d - #correct d for support displacement - for j in range(0,N): - span = beam_spans[j] + run = 0 + for con in displace: + if con == 0: + run = run + 0 + else: + run = run + 1 - slope_i = math.atan(-1.0*(displace[j]-displace[j+1])/span) - s_diag[:,j] = s_diag[:,j] + slope_i + if run == 1: + #correct d for support displacement + for j in range(0,N): + span = beam_spans[j] - for i in range(0,len(xs[:,j])): - delt_i = displace[j] + (((displace[j+1]-displace[j])/span)*xs[i,j]) - d_diag[i,j] = d_diag[i,j] + delt_i + slope_i = math.atan(-1.0*(displace[j]-displace[j+1])/span) + s_diag[:,j] = s_diag[:,j] + slope_i - #correct cantilever d for support displacement - if cant[0]=='L' or cant[0] =='B': - if displace[2] == 0 and displace[1] == 0: - pass - else: - d_diag[:,0] = d_diag[:,0]+displace[1] + for i in range(0,len(xs[:,j])): + delt_i = displace[j] + (((displace[j+1]-displace[j])/span)*xs[i,j]) + d_diag[i,j] = d_diag[i,j] + delt_i + #correct cantilever d for support displacement + if cant[0]=='L' or cant[0] =='B': + if displace[2] == 0 and displace[1] == 0: + pass + else: + d_diag[:,0] = d_diag[:,0]+displace[1] - if cant[0]=='R' or cant[0] =='B': - if displace[N-2] == 0 and displace[N-1] == 0: - pass - else: - d_diag[:,-1] = d_diag[:,-1]+displace[-2] + if cant[0]=='R' or cant[0] =='B': + if displace[N-2] == 0 and displace[N-1] == 0: + pass + else: + d_diag[:,-1] = d_diag[:,-1]+displace[-2] + else: + pass + #correct cantilever slope and deflection for interior span end slopes if cant[0]=='L' or cant[0]=='B': cant_l_fix = ppbeam.cant_left_nl(s_diag[0,1], beam_spans[0]) @@ -517,7 +585,7 @@ def __init__(self,beam_spans=[120.00], beam_momentofinertia=[120.00], cant='N', j=0 for j in range(1,N): - xs[:,j] = xs[:,j] + sumL[j-1] #converts lengths to global rather than local ie span 2 x[0] now = span 1 x[-1] or length in lieu of 0 + xs[:,j] = xs[:,j] + sumL[j-1] #converts lengths to global rather than local ie span 2 x[0] now = span 1 x[-1] or length in lieu of 0 xs = xs/12 for j in range(0,N): @@ -534,3 +602,19 @@ def __init__(self,beam_spans=[120.00], beam_momentofinertia=[120.00], cant='N', def res(self): return self.xs, self.v_diag, self.m_diag, self.s_diag, self.d_diag, self.R, self.M + + +start = time.time() +loads = [[1000.00,1000.00,30.0,30.0,'POINT',0],[1000.00,1000.00,0,120.0,'UDL',1],[1000.00,1000.00,60.0,60.0,'POINT_MOMENT',2],[1000.00,1000.00,45.0,45.0,'POINT',2],[1000.00,1000.00,0,60.0,'UDL',3]] +test = three_moment_method([60.0,120.0,120.0,60.0],[30.8,30.8,30.8,30.8],'B',loads, 29000000.00, 20, [0,0,0,0,0]) +end = time.time() +t = end-start +m = test.m_diag +s = test.s_diag +s1 = s[:,1] + +stations = test.stations +add_stations = test.add_stations +len_add = max([len(i) for i in add_stations]) +Mo = test.M +Re = test.R \ No newline at end of file diff --git a/Analysis/timotrap.py b/Analysis/timotrap.py new file mode 100644 index 0000000..1ff2eb0 --- /dev/null +++ b/Analysis/timotrap.py @@ -0,0 +1,453 @@ + +from __future__ import division +import numpy as np +import math +import TimoshenkoFormulas as timoforms + +class VariableLoad: + def __init__(self, w1, w2, a, b, L, E, I, G, kA): + ''' + Timoshenko derivation for trapezoidal/variable loading + pin-pin single span beam + + w1 - Load left end value + w2 - load right end value + a - load start point from left end of beam + b - load end point from left end of beam + d - load width = b - a + s - slope of load = (w2 - w1) / d + L - beam span + E = beam modulus of elastacity + I = beam second moment of area about the axis of bending + G = beam shear modulus + kA = beam shear area, typically the beam web area for steel W shapes + + sign convention: + (+) positive moments are applied clockwise + (+) positive reactions are in the (+) positive y direction + ''' + self.w1 = w1 + self.w2 = w2 + self.a = a + self.b = b + self.L = L + self.E = E + self.I = I + self.G = G + self.kA = kA + + d= b - a + self.d = d + s= (w2 - w1) / d + self.s = s + + + ''' + Reactions: + W = (w1 + w2)*d*0.5 + sum Fy = 0 + --> RL + RR - W = 0 + xbar = (d * ((2 * w2) + w1)) / (3 * (w2 + w1)) + sum Mx,rl,cw+ = 0 + --> -RR*L + W*(a+xbar) = 0 + --> RR = W*(a+xbar) / L + + RL = W - RR + ''' + + W = (w1 + w2)*d*0.5 + self.W = W + xbar = (d * ((2 * w2) + w1)) / (3 * (w2 + w1)) + self.xbar = xbar + + RR = W*(a+xbar) / L + RL = W - RR + + self.RR = RR + self.RL = RL + + #Boundary and Compatibility equation + #Lists of coefficients and lists of associated equalities + ''' + Solve for Constants using boundary conditions and compatibility: + **Boundary @ x=0, V=RL:** + //c1 = RL + + **Boundary @ x=L, V=-RR:** + //c3 = -RR + + **Compatibility @ x=a, V=constant:** + c1 = -1*w1*a - (s(a-a)^2)/2 + c2 + + //-c1 + c2 = w1*a + + **Boundary @ x=0, M=0:** + //c4 = 0 + + **Boundary @ x=L, M=0:** + //c3*L + c6 = 0 + c6 = -c3*L + + **Compatibility @ x=a, M=constant:** + c1*a = (-1*w1*a^2)/2 - (s(a-a)^3)/6 + c2*a + c5 + + //-c1*a + c2*a + c5 = (w1*a^2)/2 + (s(a-a)^3)/6 + + **Boundary @ x=0, delta=0:** + //c10 = 0 + + **Boundary @ x=L, delta=0:** + //0 = c3*L/kAG + (-c3*L^3)/(6*EI) - c6*L^2/2*EI + c9*L + c12 + + **Compatibility @ x=a, delta=constant:** + c1*a/kAG + (-c1*a^3)/(6*EI) - c4*a^2/2*EI + c7*a = + -1*w1*a^2/2*kAG - (s(a-a)^3)/6*kAG + c2*a/kAG + (w1*a^4)/(24*EI) + (s(a-a)^5)/(120*EI) - (c2*a^3)/6*EI - c5*a^2/2*EI + c8*a + c11 + + //c1*a/kAG + (-c1*a^3)/(6*EI) - c2*a/kAG + (c2*a^3)/6*EI - c4*a^2/2*EI + c5*a^2/2*EI + c7*a - c8*a - c11 = + -1*w1*a^2/2*kAG + (w1*a^4)/(24*EI) + + **Compatibility @ x=a, theta=constant:** + (-c1*a^2)/(2*EI) - c4*a/EI + c7 = (w1*a^3)/(6*EI) + (s(a-a)^4)/(24*EI) - (c2*a^2)/2*EI - c5*a/EI + c8 + + //(-c1*a^2)/(2*EI) + (c2*a^2)/2*EI - c4*a/EI + c5*a/EI + c7 - c8 = (w1*a^3)/(6*EI) + + **Compatibility @ x=b, theta = constant:** + (w1*b^3)/(6*EI) + (s(b-a)^4)/(24*EI) - (c2*b^2)/2*EI - c5*b/EI + c8 = (-c3*b^2)/(2*EI) - c6*b/EI + c9 + + //(-c2*b^2)/2*EI + (c3*b^2)/(2*EI) - c5*b/EI + c6*b/EI + c8 - c9 = (-1*w1*b^3)/(6*EI) - (s(b-a)^4)/(24*EI) + + + **Compatibility @ x=b, delta = constant:** + c3*b/kAG + (-c3*b^3)/(6*EI) - c6*b^2/2*EI + c9*b + c12 = + -1*w1*b^2/2*kAG - (s(b-a)^3)/6*kAG + c2*b/kAG + (w1*b^4)/(24*EI) + (s(b-a)^5)/(120*EI) - (c2*b^3)/6*EI - c5*b^2/2*EI + c8*b + c11 + + //-c2*b/kAG + (c2*b^3)/6*EI + c3*b/kAG + (-c3*b^3)/(6*EI) + c5*b^2/2*EI - c6*b^2/2*EI - c8*b + c9*b - c11 + c12 = -1*w1*b^2/2*kAG - (s(b-a)^3)/6*kAG + (w1*b^4)/(24*EI) + (s(b-a)^5)/(120*EI) + + Matrix formulation for constants: + // above indicates formula in matrix + c1 [1,0,0,0,0,0,0,0,0,0,0,0] [RL] + c2 [-1,1,0,0,0,0,0,0,0,0,0,0] [w1*a] + c3 [0,0,1,0,0,0,0,0,0,0,0,0] [-RR] + c4 [0,0,0,1,0,0,0,0,0,0,0,0] [0] + c5 [-a,a,0,0,1,0,0,0,0,0,0,0] [(w1*a^2)/2] + c6 [0,0,L,0,0,1,0,0,0,0,0,0] [0] + c7 [(-1*a^2)/(2*EI),(a^2)/2*EI,0,-1*a/EI,a/EI,0,1,-1,0,0,0,0] [(w1*a^3)/(6*EI)] + c8 [0,(-1*b^2)/2*EI,(b^2)/(2*EI),0,-1*b/EI,b/EI,0,1,-1,0,0,0] [(-1*w1*b^3)/(6*EI) - (s(b-a)^4)/(24*EI)] + c9 [0,0,L/kAG + (-1*L^3)/(6*EI),0,0,-1*L^2/2*EI,0,0,L,0,0,1] [0] + c10 [0,0,0,0,0,0,0,0,0,1,0,0] [0] + c11 [a/kAG + (-1*a^3)/(6*EI),-1*a/kAG + (a^3)/6*EI,0,-1*a^2/2*EI,a^2/2*EI,0,a,-a,0,0,-1,0] [-1*w1*a^2/2*kAG + (w1*a^4)/(24*EI)] + c12 [0,-1*b/kAG + (b^3)/6*EI,d/kAG + (-1*b^3)/(6*EI),0,b^2/2*EI,-1*b^2/2*EI,0,-1*b,b,0,-1,1] [-1*w1*b^2/2*kAG - (s(b-a)^3)/6*kAG + (w1*b^4)/(24*EI) + (s(b-a)^5)/(120*EI)] + ''' + bc1_coeff = [1,0,0,0,0,0,0,0,0,0,0,0] + bc1_eq = [RL] + + bc2_coeff = [-1,1,0,0,0,0,0,0,0,0,0,0] + bc2_eq = [w1*a] + + bc3_coeff = [0,0,1,0,0,0,0,0,0,0,0,0] + bc3_eq = [-1*RR] + + bc4_coeff = [0,0,0,1,0,0,0,0,0,0,0,0] + bc4_eq = [0] + + bc5_coeff = [-1*a,a,0,0,1,0,0,0,0,0,0,0] + bc5_eq = [(w1*math.pow(a,2))/2.0] + + bc6_coeff = [0,0,L,0,0,1,0,0,0,0,0,0] + bc6_eq = [0] + + bc7_coeff = [(-1*math.pow(a,2))/(2*E*I),(math.pow(a,2))/(2*E*I),0,-1*a/(E*I),a/(E*I),0,1,-1,0,0,0,0] + bc7_eq = [(w1*math.pow(a,3))/(6*E*I)] + + bc8_coeff = [0, + (-1*math.pow(b,2))/(2*E*I), + (math.pow(b,2))/(2*E*I), + 0, + -1*b/(E*I), + b/(E*I), + 0, + 1, + -1, + 0, + 0, + 0] + + bc8_eq = [((-1*w1*math.pow(b,3))/(6*E*I)) - ((s*math.pow((b-a),4))/(24*E*I))] + + bc9_coeff = [0,0,(L/(kA*G)) + ((-1*math.pow(L,3))/(6*E*I)),0,0,-1*math.pow(L,2)/(2*E*I),0,0,L,0,0,1] + bc9_eq = [0] + + bc10_coeff = [0,0,0,0,0,0,0,0,0,1,0,0] + bc10_eq = [0] + + bc11_coeff = [(a/(kA*G)) + ((-1*math.pow(a,3))/(6*E*I)), + (-1*a/(kA*G)) + ((math.pow(a,3))/(6*E*I)), + 0, + ((-1*math.pow(a,2))/(2*E*I)), + (math.pow(a,2)/(2*E*I)), + 0, + a, + -1*a, + 0, + 0, + -1, + 0] + + bc11_eq = [(-1*w1*math.pow(a,2)/(2*kA*G)) + ((w1*math.pow(a,4))/(24*E*I))] + + bc12_coeff = [0, + (-1*b/(kA*G)) + ((math.pow(b,3))/(6*E*I)), + (b/(kA*G)) + ((-1*math.pow(b,3))/(6*E*I)), + 0, + math.pow(b,2)/(2*E*I), + -1*math.pow(b,2)/(2*E*I), + 0, + -1*b, + b, + 0, + -1, + 1] + + bc12_eq = [((-1*w1*math.pow(b,2))/(2*kA*G)) - ((s*math.pow((b-a),3))/(6*kA*G)) + ((w1*math.pow(b,4))/(24*E*I)) + ((s*math.pow((b-a),5))/(120*E*I))] + + + bceq = [bc1_coeff,bc2_coeff,bc3_coeff,bc4_coeff,bc5_coeff,bc6_coeff,bc7_coeff,bc8_coeff,bc9_coeff,bc10_coeff,bc11_coeff,bc12_coeff] + bcs = [bc1_eq,bc2_eq,bc3_eq,bc4_eq,bc5_eq,bc6_eq,bc7_eq,bc8_eq,bc9_eq,bc10_eq,bc11_eq,bc12_eq] + + bceq = np.array(bceq) + bcs = np.array(bcs) + + c = np.linalg.solve(bceq,bcs) + self.c = c + + ''' + Load Formulas: + 0 < x < a: + w = 0 + + a < x < b: + w = -1*w1 - s(x-a) + + b < x < L: + w = 0 + + Shear Formulas: + w = dV/dx, therefore V = integral w dx + + 0 < x < a: + V = c1 + + a < x < b: + V = -1*w1*x - (s(x-a)^2)/2 + c2 + + c < x < L: + V = c3 + ''' + + def vx(self,x): + + # redefine variables from self. to local to + # make formulas easier to read + w1 = self.w1 + a = self.a + s = self.s + c = self.c + b = self.b + L = self.L + + if 0 <= x <= a: + v = c[0][0] + elif a < x <= b: + v = (-1*w1*x) - ((s*math.pow((x-a),2))/2.0) + c[1][0] + elif b < x <= L: + v = c[2][0] + else: + v = 0 + + return v + + ''' + Moment Formulas: + V = dM/dx, therefore M = integral V dx + + 0 < x < a: + M = c1*x + c4 + + a < x < b: + M = (-1*w1*x^2)/2 - (s(x-a)^3)/6 + c2*x + c5 + + b < x < L: + M = c3*x + c6 + ''' + def mx(self,x): + # redefine variables from self. to local to + # make formulas easier to read + w1 = self.w1 + a = self.a + s = self.s + c = self.c + b = self.b + L = self.L + + if 0 <= x <= a: + m = c[0][0]*x + c[3][0] + elif a < x <= b: + m = (((-1*w1*math.pow(x,2))/2.0) - + ((s*math.pow((x-a),3))/6.0) + + c[1][0]*x + + c[4][0]) + elif b < x <= L: + m = c[2][0]*x + c[5][0] + else: + m = 0 + return m + + ''' + Timoshenko Relationship for Rotation, theta, and Deflection, delta + M = -E*I d theta/dx + V = kAG (-theta + d delta/dx) + + Rotation Formulas: + theta = integral M/-EI dx + + 0 < x < a: + theta = (-c1*x^2)/(2*EI) - c4*x/EI + c7 + + a < x < b: + theta = (w1*x^3)/(6*EI) + (s(x-a)^4)/(24*EI) - (c2*x^2)/2*EI - c5*x/EI + c8 + + b < x < L: + theta = (-c3*x^2)/(2*EI) - c6*x/EI + c9 + ''' + + def thetax(self,x): + + # redefine variables from self. to local to + # make formulas easier to read + w1 = self.w1 + a = self.a + s = self.s + c = self.c + b = self.b + L = self.L + E = self.E + I = self.I + + if 0 <= x <= a: + theta = (((-1*c[0][0]*math.pow(x,2))/(2.0*E*I)) - + ((c[3][0]*x)/(E*I)) + + c[6][0]) + elif a < x <= b: + theta = (((w1*math.pow(x,3))/(6.0*E*I)) + + ((s*math.pow((x-a),4))/(24.0*E*I)) - + ((c[1][0]*math.pow(x,2))/(2.0*E*I)) - + ((c[4][0]*x)/(E*I)) + + c[7][0]) + elif b < x <= L: + theta = (((-1*c[2][0]*math.pow(x,2))/(2.0*E*I)) - + ((c[5][0]*x)/(E*I)) + + c[8][0]) + else: + theta = 0 + + return theta + + ''' + Delta Formulas: + delta = integral V/kAG + theta dx + + 0 < x < a: + delta = c1*x/kAG + (-c1*x^3)/(6*EI) - c4*x^2/2*EI + c7*x + c10 + + a < x < b: + delta = -1*w1*x^2/2*kAG - (s(x-a)^3)/6*kAG + c2*x/kAG + (w1*x^4)/(24*EI) + (s(x-a)^5)/(120*EI) - (c2*x^3)/6*EI - c5*x^2/2*EI + c8*x + c11 + + b < x < L: + delta = c3*x/kAG + (-c3*x^3)/(6*EI) - c6*x^2/2*EI + c9*x + c12 + ''' + def deltax(self,x): + # redefine variables from self. to local to + # make formulas easier to read + w1 = self.w1 + a = self.a + s = self.s + c = self.c + b = self.b + L = self.L + E = self.E + I = self.I + G = self.G + kA = self.kA + + if 0 <= x <= a: + delta = (((c[0][0]*x)/(kA*G)) + + ((-1*c[0][0]*math.pow(x,3))/(6.0*E*I)) - + ((c[3][0]*math.pow(x,2))/(2.0*E*I)) + + (c[6][0]*x) + + c[9][0]) + elif a < x <= b: + delta = (((-1*w1*math.pow(x,2))/(2.0*kA*G)) - + ((s*math.pow((x-a),3))/(6.0*kA*G)) + + ((c[1][0]*x)/(kA*G)) + + ((w1*math.pow(x,4))/(24.0*E*I)) + + ((s*math.pow((x-a),5))/(120.0*E*I)) - + ((c[1][0]*math.pow(x,3))/(6.0*E*I)) - + ((c[4][0]*math.pow(x,2))/(2.0*E*I)) + + (c[7][0]*x) + + c[10][0]) + elif b < x <= L: + delta = (((c[2][0]*x)/(kA*G)) + + ((-1*c[2][0]*math.pow(x,3))/(6.0*E*I)) - + ((c[5][0]*math.pow(x,2))/(2*E*I)) + + (c[8][0]*x) + + c[11][0]) + else: + delta = 0 + + return delta + + def fef(self): + L = self.L + E = self.E + I = self.I + G = self.G + kA = self.kA + + fem = timoforms.fixedendmomentsTimoshenko(self.thetax(0), self.thetax(L), L, E, I, G, kA, [1,1]) + + ML = fem[0][0] + MR = fem[1][0] + + mo = timoforms.PointMoment(ML,0,L,E,I,G,kA) + ml = timoforms.PointMoment(MR,L,L,E,I,G,kA) + + RL = self.RL + mo.rl + ml.rl + RR = self.RR + mo.rr + ml.rr + + return [RL,ML,RR,MR] + + + + +w1= 1 +w2= 0.5 +a= 3 +b= 7 +L=10 + +#Material and Cross section data +E = 29000*math.pow(12,2) +I = 30.8 * 1/math.pow(12,4) +kA = 1.34 * 1/math.pow(12,2) +#kA = 10000000000000000000.0 +G = E /(2+(2*0.3)) + +load = VariableLoad(w1, w2, a, b, L, E, I, G, kA) + +fef = load.fef() + +res0 = [load.vx(0),load.mx(0),load.thetax(0),load.deltax(0)*12.0] +res2 = [load.vx(2),load.mx(2),load.thetax(2),load.deltax(2)*12.0] +res5 = [load.vx(5),load.mx(5),load.thetax(5),load.deltax(5)*12.0] +res8 = [load.vx(8),load.mx(8),load.thetax(8),load.deltax(8)*12.0] +resL = [load.vx(L),load.mx(L),load.thetax(L),load.deltax(L)*12.0] \ No newline at end of file diff --git a/Analysis/timoudl.py b/Analysis/timoudl.py new file mode 100644 index 0000000..6621059 --- /dev/null +++ b/Analysis/timoudl.py @@ -0,0 +1,401 @@ + +from __future__ import division +import numpy as np +import math + +class UniformLoad: + def __init__(self, w, a, b, L, E, I, G, kA): + ''' + Timoshenko derivation for uniform loading + pin-pin single span beam + + w - Load left end value + a - load start point from left end of beam + b - load end point from left end of beam + d - load width = b - a + L - beam span + E = beam modulus of elastacity + I = beam second moment of area about the axis of bending + G = beam shear modulus + kA = beam shear area, typically the beam web area for steel W shapes + + sign convention: + (+) positive moments are applied clockwise + (+) positive reactions are in the (+) positive y direction + ''' + self.w = w + self.a = a + self.b = b + self.L = L + self.E = E + self.I = I + self.G = G + self.kA = kA + + d= b - a + self.d = d + + ''' + Reactions: + W = w*d + sum Fy = 0 + --> RL + RR - W = 0 + xbar = (a + d/2) + sum Mx,rl,cw+ = 0 + --> -RR*L + W*(xbar) = 0 + --> RR = W*(xbar) / L + + RL = W - RR + ''' + + W = w*d + self.W = W + xbar = a + (d/2.0) + self.xbar = xbar + + RR = (W*xbar) / L + RL = W - RR + + self.RR = RR + self.RL = RL + + #Boundary and Compatibility equation + #Lists of coefficients and lists of associated equalities + ''' + Solve for Constants using boundary conditions and compatibility: + **Boundary @ x=0, V=RL:** + //c1 = RL + + **Boundary @ x=L, V=-RR:** + //c3 = -RR + + **Compatibility @ x=a, V=constant:** + c1 = -1*w*a + c2 + + //-c1 + c2 = w*a + + **Boundary @ x=0, M=0:** + //c4 = 0 + + **Boundary @ x=L, M=0:** + //c3*L + c6 = 0 + c6 = -c3*L + + **Compatibility @ x=a, M=constant:** + c1*a = (-1*w*a^2)/2 + c2*a + c5 + + //c1*a - c2*a - c5 = (-1*w*a^2)/2 + + **Boundary @ x=0, delta=0:** + //c10 = 0 + + **Boundary @ x=L, delta=0:** + //0 = c3*L/kAG + (-c3*L^3)/(6*EI) - c6*L^2/2*EI + c9*L + c12 + + **Compatibility @ x=a, delta=constant:** + c1*a/kAG + (-c1*a^3)/(6*EI) - c4*a^2/2*EI + c7*a = + -1*w*a^2/2*kAG + c2*a/kAG + (w*a^4)/(24*EI) - (c2*a^3)/6*EI - c5*a^2/2*EI + c8*a + c11 + + //c1*a/kAG + (-c1*a^3)/(6*EI) - c2*a/kAG + (c2*a^3)/6*EI - c4*a^2/2*EI + c5*a^2/2*EI + c7*a - c8*a - c11 = + -1*w*a^2/2*kAG + (w*a^4)/(24*EI) + + **Compatibility @ x=b, delta = constant:** + c3*b/kAG + (-c3*b^3)/(6*EI) - c6*b^2/2*EI + c9*b + c12 = + -1*w*b^2/2*kAG + c2*b/kAG + (w*b^4)/(24*EI) - (c2*b^3)/6*EI - c5*b^2/2*EI + c8*b + c11 + + //-c2*b/kAG + (c2*b^3)/6*EI + c3*b/kAG + (-c3*b^3)/(6*EI) + c5*b^2/2*EI - c6*b^2/2*EI - c8*b + c9*b - c11 + c12 = + -1*w1*b^2/2*kAG + (w1*b^4)/(24*EI) + + **Compatibility @ x=a, theta=constant:** + (-c1*a^2)/(2*EI) - c4*a/EI + c7 = (w*a^3)/(6*EI) - (c2*a^2)/2*EI - c5*a/EI + c8 + + //(-c1*a^2)/(2*EI) + (c2*a^2)/2*EI - c4*a/EI + c5*a/EI + c7 - c8 = (w*a^3)/(6*EI) + + **Compatibility @ x=b, theta = constant:** + (w*b^3)/(6*EI) - (c2*b^2)/2*EI - c5*b/EI + c8 = (-c3*b^2)/(2*EI) - c6*b/EI + c9 + + //(-c2*b^2)/2*EI + (c3*b^2)/(2*EI) - c5*b/EI + c6*b/EI + c8 - c9 = (-1*w*b^3)/(6*EI) + + ''' + bc1_coeff = [1,0,0,0,0,0,0,0,0,0,0,0] + bc1_eq = [RL] + + bc2_coeff = [-1,1,0,0,0,0,0,0,0,0,0,0] + bc2_eq = [w*a] + + bc3_coeff = [0,0,1,0,0,0,0,0,0,0,0,0] + bc3_eq = [-1*RR] + + bc4_coeff = [0,0,0,1,0,0,0,0,0,0,0,0] + bc4_eq = [0] + + bc5_coeff = [-1*a,a,0,0,1,0,0,0,0,0,0,0] + bc5_eq = [(w*math.pow(a,2))/2.0] + + bc6_coeff = [0,0,L,0,0,1,0,0,0,0,0,0] + bc6_eq = [0] + + bc7_coeff = [(-1*math.pow(a,2))/(2*E*I),(math.pow(a,2))/(2*E*I),0,0,a/(E*I),0,1,-1,0,0,0,0] + bc7_eq = [(w*math.pow(a,3))/(6*E*I)] + + bc8_coeff = [0, + (math.pow(b,2))/(2*E*I), + (-1*math.pow(b,2))/(2*E*I), + 0, + b/(E*I), + (-1*b)/(E*I), + 0, + -1, + 1, + 0, + 0, + 0] + + bc8_eq = [((w*math.pow(b,3))/(6*E*I))] + + bc9_coeff = [0,0,(L/(kA*G)) + ((-1*math.pow(L,3))/(6*E*I)),0,0,-1*math.pow(L,2)/(2*E*I),0,0,L,0,0,1] + bc9_eq = [0] + + bc10_coeff = [0,0,0,0,0,0,0,0,0,1,0,0] + bc10_eq = [0] + + bc11_coeff = [(a/(kA*G)) + ((-1*math.pow(a,3))/(6*E*I)), + (-1*a/(kA*G)) + ((math.pow(a,3))/(6*E*I)), + 0, + 0, + (math.pow(a,2)/(2*E*I)), + 0, + a, + -1*a, + 0, + 0, + -1, + 0] + + bc11_eq = [(-1*w*math.pow(a,2)/(2*kA*G)) + ((w*math.pow(a,4))/(24*E*I))] + + bc12_coeff = [0, + (-1*b/(kA*G)) + ((math.pow(b,3))/(6*E*I)), + (b/(kA*G)) + ((-1*math.pow(b,3))/(6*E*I)), + 0, + math.pow(b,2)/(2*E*I), + -1*math.pow(b,2)/(2*E*I), + 0, + -1*b, + b, + 0, + -1, + 1] + + bc12_eq = [((-1*w*math.pow(b,2))/(2*kA*G)) + ((w*math.pow(b,4))/(24*E*I))] + + + bceq = [bc1_coeff,bc2_coeff,bc3_coeff,bc4_coeff,bc5_coeff,bc6_coeff,bc7_coeff,bc8_coeff,bc9_coeff,bc10_coeff,bc11_coeff,bc12_coeff] + bcs = [bc1_eq,bc2_eq,bc3_eq,bc4_eq,bc5_eq,bc6_eq,bc7_eq,bc8_eq,bc9_eq,bc10_eq,bc11_eq,bc12_eq] + + bceq = np.array(bceq) + bcs = np.array(bcs) + + c = np.linalg.solve(bceq,bcs) + self.c = c + + ''' + Load Formulas: + 0 < x < a: + w = 0 + + a < x < b: + w = -1*w + + b < x < L: + w = 0 + + Shear Formulas: + w = dV/dx, therefore V = integral w dx + + 0 < x < a: + V = c1 + + a < x < b: + V = -1*w*x + c2 + + c < x < L: + V = c3 + ''' + def vx(self,x): + + # redefine variables from self. to local to + # make formulas easier to read + w = self.w + a = self.a + c = self.c + b = self.b + L = self.L + + if 0 <= x <= a: + v = c[0][0] + elif a < x <= b: + v = (-1*w*x) + c[1][0] + elif b < x <= L: + v = c[2][0] + else: + v = 0 + + return v + + ''' + Moment Formulas: + V = dM/dx, therefore M = integral V dx + + 0 < x < a: + M = c1*x + c4 + + a < x < b: + M = (-1*w*x^2)/2 + c2*x + c5 + + b < x < L: + M = c3*x + c6 + ''' + def mx(self,x): + # redefine variables from self. to local to + # make formulas easier to read + w = self.w + a = self.a + c = self.c + b = self.b + L = self.L + + if 0 <= x <= a: + m = c[0][0]*x + c[3][0] + elif a < x <= b: + m = (((-1*w*math.pow(x,2))/2.0) + + c[1][0]*x + + c[4][0]) + elif b < x <= L: + m = c[2][0]*x + c[5][0] + else: + m = 0 + return m + + ''' + Timoshenko Relationship for Rotation, theta, and Deflection, delta + M = -E*I d theta/dx + V = kAG (-theta + d delta/dx) + + Rotation Formulas: + theta = integral M/-EI dx + + 0 < x < a: + theta = (-c1*x^2)/(2*EI) - c4*x/EI + c7 + + a < x < b: + theta = (w1*x^3)/(6*EI) - (c2*x^2)/2*EI - c5*x/EI + c8 + + b < x < L: + theta = (-c3*x^2)/(2*EI) - c6*x/EI + c9 + ''' + + def thetax(self,x): + + # redefine variables from self. to local to + # make formulas easier to read + w = self.w + a = self.a + c = self.c + b = self.b + L = self.L + E = self.E + I = self.I + + if 0 <= x <= a: + theta = (((-1*c[0][0]*math.pow(x,2))/(2.0*E*I)) - + ((c[3][0]*x)/(E*I)) + + c[6][0]) + elif a < x <= b: + theta = (((w*math.pow(x,3))/(6.0*E*I)) - + ((c[1][0]*math.pow(x,2))/(2.0*E*I)) - + ((c[4][0]*x)/(E*I)) + + c[7][0]) + elif b < x <= L: + theta = (((-1*c[2][0]*math.pow(x,2))/(2.0*E*I)) - + ((c[5][0]*x)/(E*I)) + + c[8][0]) + else: + theta = 0 + + return theta + + ''' + Delta Formulas: + delta = integral V/kAG + theta dx + + 0 < x < a: + delta = c1*x/kAG + (-c1*x^3)/(6*EI) - c4*x^2/2*EI + c7*x + c10 + + a < x < b: + delta = -1*w1*x^2/2*kAG + c2*x/kAG + (w1*x^4)/(24*EI) - (c2*x^3)/6*EI - c5*x^2/2*EI + c8*x + c11 + + b < x < L: + delta = c3*x/kAG + (-c3*x^3)/(6*EI) - c6*x^2/2*EI + c9*x + c12 + ''' + def deltax(self,x): + # redefine variables from self. to local to + # make formulas easier to read + w = self.w + a = self.a + c = self.c + b = self.b + L = self.L + E = self.E + I = self.I + G = self.G + kA = self.kA + + if 0 <= x <= a: + delta = (((c[0][0]*x)/(kA*G)) + + ((-1*c[0][0]*math.pow(x,3))/(6.0*E*I)) - + ((c[3][0]*math.pow(x,2))/(2.0*E*I)) + + (c[6][0]*x) + + c[9][0]) + elif a < x <= b: + delta = (((-1*w*math.pow(x,2))/(2.0*kA*G)) + + ((c[1][0]*x)/(kA*G)) + + ((w*math.pow(x,4))/(24.0*E*I)) - + ((c[1][0]*math.pow(x,3))/(6.0*E*I)) - + ((c[4][0]*math.pow(x,2))/(2.0*E*I)) + + (c[7][0]*x) + + c[10][0]) + elif b < x <= L: + delta = (((c[2][0]*x)/(kA*G)) + + ((-1*c[2][0]*math.pow(x,3))/(6.0*E*I)) - + ((c[5][0]*math.pow(x,2))/(2*E*I)) + + (c[8][0]*x) + + c[11][0]) + else: + delta = 0 + + return delta + + + + + +w= 1 +a= 3 +b= 7 +L=10 + +#Material and Cross section data +E = 29000*math.pow(12,2) +I = 30.8 * 1/math.pow(12,4) +kA = 1.34 * 1/math.pow(12,2) +#kA = 10000000000000000000.0 +G = E /(2+(2*0.3)) + +load = UniformLoad(w, a, b, L, E, I, G, kA) + +res0 = [load.vx(0),load.mx(0),load.thetax(0),load.deltax(0)*12.0] +res2 = [load.vx(2),load.mx(2),load.thetax(2),load.deltax(2)*12.0] +res5 = [load.vx(5),load.mx(5),load.thetax(5),load.deltax(5)*12.0] +res8 = [load.vx(8),load.mx(8),load.thetax(8),load.deltax(8)*12.0] +resL = [load.vx(L),load.mx(L),load.thetax(L),load.deltax(L)*12.0] \ No newline at end of file diff --git a/Analysis/torsion.py b/Analysis/torsion.py new file mode 100644 index 0000000..3a75ab3 --- /dev/null +++ b/Analysis/torsion.py @@ -0,0 +1,444 @@ +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' + +from __future__ import division +import math as m + +#Torsion Equitions from AISC Design Guide 9 Appendix C + +#Case 1 - Concentrated End Torques with Free Ends +#T = Applied Concentrated Torsional Moment, Kip-in +#G = Shear Modulus of Elasticity, Ksi, 11200 for steel +#J = Torsinal Constant of Cross Section, in^4 +class torsion_case1: + def __init__(self, T_k_in, G_ksi, J_in4): + self.T_k_in = T_k_in + self.G_ksi = G_ksi + self.J_in4 = J_in4 + + def theta(self,z_in): + T = self.T_k_in + G = self.G_ksi + J = self.J_in4 + z = z_in + + thet = (T*z) / (G*J) + + return thet + + def thetap(self,z_in): + + theta_prime = T / (G*J) + + return theta_prime + + def thetapp(self,z_in): + + theta_doubleprime = 0 + + return theta_doubleprime + +#Case 2 - Concentrated End Torques with Fixed Ends +#T = Applied Concentrated Torsional Moment, Kip-in +#G = Shear Modulus of Elasticity, Ksi, 11200 for steel +#J = Torsinal Constant of Cross Section, in^4 +#l = Span Lenght, in +#a = Torsional Constant +class torsion_case2: + def __init__(self, T_k_in, G_ksi, J_in4, l_in, a): + self.T_k_in = T_k_in + self.G_ksi = G_ksi + self.J_in4 = J_in4 + self.l_in = l_in + self.a = a + + def theta(self,z_in): + T = self.T_k_in + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + z = z_in + + thet = ((T*a) / (G*J))*((m.tanh(l/(2*a))*m.cosh(z/a))-(m.tanh(l/(2*a)))+(z/a)-(m.sinh(z/a))) + + return thet + + def thetap(self,z_in): + T = self.T_k_in + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + z = z_in + theta_prime = (T - T*m.cosh(z/a) + T*m.sinh(z/a)*m.tanh(l/(2*a)))/(G*J) + + return theta_prime + + def thetapp(self,z_in): + T = self.T_k_in + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + z = z_in + theta_doubleprime = (-(T*m.sinh(z/a)) + T*m.cosh(z/a)*m.tanh(l/(2*a)))/(a*G*J) + + return theta_doubleprime + + def thetappp(self,z_in): + T = self.T_k_in + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + z = z_in + theta_tripleprime = (-(T*m.cosh(z/a)) + T*m.sinh(z/a)*m.tanh(l/(2*a)))/(G*J*a**2) + + return theta_tripleprime + +#Case 3 - Concentrated Torque at alpha*l with Pinned Ends +#T = Applied Concentrated Torsional Moment, Kip-in +#G = Shear Modulus of Elasticity, Ksi, 11200 for steel +#J = Torsinal Constant of Cross Section, in^4 +#l = Span Lenght, in +#a = Torsional Constant +#alpa = load application point/l +class torsion_case3: + def __init__(self, T_k_in, G_ksi, J_in4, l_in, a, alpha): + self.T_k_in = T_k_in + self.G_ksi = G_ksi + self.J_in4 = J_in4 + self.l_in = l_in + self.a = a + self.alpha = alpha + + def theta(self,z_in): + T = self.T_k_in + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + alpha = self.alpha + z = z_in + + if 0 <= z_in <= (alpha*l): + thet = ((T*l) / (G*J))*(((1.0-alpha)*(z/l))+(((a/l)*((m.sinh((alpha*l)/a)/m.tanh(l/a)) - m.cosh((alpha*l)/a)))*m.sinh(z/a))) + else: + thet = ((T*l) / (G*J))*(((l-z)*(alpha/l))+((a/l)*(((m.sinh((alpha*l)/a) / m.tanh(l/a))*m.sinh(z/a)) - (m.sinh((alpha*l)/a)*m.cosh(z/a))))) + + return thet + + def thetap(self,z_in): + T = self.T_k_in + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + alpha = self.alpha + z = z_in + if 0 <= z_in <= (alpha*l): + theta_prime = ((-1.0*T)/(G*J))*(alpha - 1.0 + (m.cosh(z/a)*((m.cosh((l*alpha)/a) - (m.sinh((l*alpha)/a)/m.tanh(l/a)))))) + else: + theta_prime = -1.0*((T*(alpha - m.cosh(z/a)*m.sinh((l*alpha)/a)/m.tanh(l/a) + m.sinh(z/a)*m.sinh((l*alpha)/a))/(G*J))) + return theta_prime + + def thetapp(self,z_in): + T = self.T_k_in + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + alpha = self.alpha + z = z_in + if 0 <= z_in <= (alpha*l): + theta_doubleprime = -((T*m.sinh(z/a)*(m.cosh((l*alpha)/a) - m.sinh((l*alpha)/a)/m.tanh(l/a)))/(a*G*J)) + else: + theta_doubleprime = (T*(-1.0*m.cosh(z/a) + m.sinh(z/a)/m.tanh(l/a))*m.sinh((l*alpha)/a))/(a*G*J) + return theta_doubleprime + + def thetappp(self,z_in): + T = self.T_k_in + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + alpha = self.alpha + z = z_in + if 0 <= z_in <= (alpha*l): + theta_tripleprime = -((T*m.cosh(z/a)*(m.cosh((l*alpha)/a) - m.sinh((l*alpha)/a)/m.tanh(l/a)))/(G*J*a**2)) + else: + theta_tripleprime = (T*(m.cosh(z/a)/m.tanh(l/a) - m.sinh(z/a))*m.sinh((l*alpha)/a))/(G*J*a**2) + return theta_tripleprime + +#Case 4 - Uniformly Distributed Torque with Pinned Ends +#t = Distributed torque, Kip-in / in +#G = Shear Modulus of Elasticity, Ksi, 11200 for steel +#J = Torsinal Constant of Cross Section, in^4 +#l = Span Lenght, in +#a = Torsional Constant +class torsion_case4: + def __init__(self, t_k_inpin, G_ksi, J_in4, l_in, a): + self.t_k_inpin = t_k_inpin + self.G_ksi = G_ksi + self.J_in4 = J_in4 + self.l_in = l_in + self.a = a + + def theta(self,z_in): + t = self.t_k_inpin + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + z = z_in + + thet = ((t*a**2) / (G*J))*(((l**2 / (2*a**2))*((z/l) - ((z**2)/(l**2))))+m.cosh(z/a)-(m.tanh(l/(2*a))*m.sinh(z/a))-1.0) + + return thet + + def thetap(self,z_in): + t = self.t_k_inpin + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + z = z_in + theta_prime = (t*(l - 2*z + 2*a*m.sinh(z/a) - 2*a*m.cosh(z/a)*m.tanh(l/(2*a))))/(2*G*J) + + return theta_prime + + def thetapp(self,z_in): + t = self.t_k_inpin + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + z = z_in + theta_doubleprime = (t*(-1 + m.cosh(z/a) - m.sinh(z/a)*m.tanh(l/(2*a))))/(G*J) + + return theta_doubleprime + + def thetappp(self,z_in): + t = self.t_k_inpin + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + z = z_in + theta_tripleprime = (t*(m.sinh(z/a) - m.cosh(z/a)*m.tanh(l/(2*a))))/(a*G*J) + + return theta_tripleprime + +#Case 5 - Linearly Varying Torque with Pinned Ends - 0 at left to t at right +#t = Distributed torque, Kip-in / in +#G = Shear Modulus of Elasticity, Ksi, 11200 for steel +#J = Torsinal Constant of Cross Section, in^4 +#l = Span Lenght, in +#a = Torsional Constant +class torsion_case5: + def __init__(self, t_k_inpin, G_ksi, J_in4, l_in, a): + self.t_k_inpin = t_k_inpin + self.G_ksi = G_ksi + self.J_in4 = J_in4 + self.l_in = l_in + self.a = a + + def theta(self,z_in): + t = self.t_k_inpin + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + z = z_in + + + + thet = ((t*l**2) / (G*J))*((z/(6*l)) + ((a**2)/(l**2)*((m.sinh(z/a)/m.sinh(l/a))-(z/l)))-((z**3)/(6*l**3))) + + return thet + + def thetap(self,z_in): + t = self.t_k_inpin + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + z = z_in + theta_prime = (t*(-6.0*a**2 + l**2 - 3*z**2 + 6*a*l*(m.cosh(z/a)/m.sinh(l/a))))/(6*G*J*l) + + return theta_prime + + def thetapp(self,z_in): + t = self.t_k_inpin + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + z = z_in + theta_doubleprime = (t*(-1.0*z + l*(m.sinh(z/a)/m.sinh(l/a))))/(G*J*l) + + return theta_doubleprime + + def thetappp(self,z_in): + t = self.t_k_inpin + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + z = z_in + theta_tripleprime = (t*(-1 + (l*(m.cosh(z/a)/m.sinh(l/a)))/a))/(G*J*l) + + return theta_tripleprime + +#Case 6 - Concentrated Torque at alpha*l with Fixed Ends +#T = Applied Concentrated Torsional Moment, Kip-in +#G = Shear Modulus of Elasticity, Ksi, 11200 for steel +#J = Torsinal Constant of Cross Section, in^4 +#l = Span Lenght, in +#a = Torsional Constant +#alpa = load application point/l +class torsion_case6: + def __init__(self, T_k_in, G_ksi, J_in4, l_in, a, alpha): + self.T_k_in = T_k_in + self.G_ksi = G_ksi + self.J_in4 = J_in4 + self.l_in = l_in + self.a = a + self.alpha = alpha + self.H = (((1.0-m.cosh((alpha*l)/a)) / m.tanh(l/a)) + ((m.cosh((alpha*l)/a)-1.0) / m.sinh(l/a)) + m.sinh((alpha*l)/a) - ((alpha*l)/a)) / \ + (((m.cosh(l/a)+(m.cosh((alpha*l)/a)*m.cosh(l/a))-m.cosh((alpha*l)/a)-1.0)/m.sinh(l/a))+((l/a)*(alpha-1.0))-m.sinh((alpha*l)/a)) + + def theta(self,z_in): + T = self.T_k_in + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + alpha = self.alpha + H = self.H + z = z_in + + if 0 <= z_in <= (alpha*l): + thet = ((T*a) / ((H+1.0)*G*J))*\ + ((((H*((1.0/m.sinh(l/a))+m.sinh((alpha*l)/a)-(m.cosh((alpha*l)/a)/m.tanh(l/a))))+ \ + (m.sinh((alpha*l)/a) - (m.cosh((alpha*l)/a)/m.tanh(l/a)) + (1.0/m.tanh(l/a))))* \ + (m.cosh(z/a)-1.0)) - \ + m.sinh(z/a) + \ + (z/a)) + + + else: + thet = (T*a / ((1+(1/H))*G*J))*\ + ((m.cosh((alpha*l)/a) - 1.0/(H*m.sinh(l/a)) +\ + (m.cosh((alpha*l)/a)-m.cosh(l/a)+((l/a)*m.sinh(l/a))) / m.sinh(l/a)) +\ + m.cosh(z/a)*\ + ((1.0-m.cosh((alpha*l)/a))/(H*m.tanh(l/a)) +\ + (1.0-(m.cosh((alpha*l)/a)*m.cosh(l/a)))/m.sinh(l/a)) +\ + m.sinh(z/a)*\ + (((m.cosh((alpha*l)/a)-1.0)/H) + m.cosh((alpha*l)/a)) -\ + (z/a)) + + return thet + + def thetap(self,z_in): + T = self.T_k_in + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + alpha = self.alpha + H = self.H + z = z_in + + if 0 <= z_in <= (alpha*l): + theta_prime = (-1.0*T*(-1.0 + m.cosh(z/a) + (-1.0 + (1.0 + H)*m.cosh((l*alpha)/a))*(m.sinh(z/a)/m.tanh(l/a)) - 1.0*H*(m.sinh(z/a)/m.sinh(l/a)) - 1.0*m.sinh(z/a)*m.sinh((l*alpha)/a) - 1.0*H*m.sinh(z/a)*m.sinh((l*alpha)/a)))/(G*(1.0 + H)*J) + else: + theta_prime = 0 + return theta_prime + + def thetapp(self,z_in): + T = self.T_k_in + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + alpha = self.alpha + H = self.H + z = z_in + + if 0 <= z_in <= (alpha*l): + theta_doubleprime = -((T*((m.cosh(z/a)*(-1.0 + (1.0 + H)*(m.cosh((l*alpha)/a))/m.tanh(l/a)))/a - (H*(m.cosh(z/a)/m.sinh(l/a)))/a + m.sinh(z/a)/a - (m.cosh(z/a)*m.sinh((l*alpha)/a))/a - (H*m.cosh(z/a)*m.sinh((l*alpha)/a))/a))/(G*(1.0 + H)*J)) + else: + theta_doubleprime = 0 + return theta_doubleprime + + def thetappp(self,z_in): + T = self.T_k_in + G = self.G_ksi + J = self.J_in4 + l = self.l_in + a = self.a + alpha = self.alpha + H = self.H + z = z_in + + if 0 <= z_in <= (alpha*l): + theta_tripleprime = -((T*(m.cosh(z/a)/a**2 + ((-1.0 + (1.0 + H)*(m.cosh((l*alpha)/a))/m.tanh(l/a))*m.sinh(z/a))/a**2 - (H*(m.sinh(z/a)/m.sinh(l/a)))/a**2 - (m.sinh(z/a)*m.sinh((l*alpha)/a))/a**2 - (H*m.sinh(z/a)*m.sinh((l*alpha)/a))/a**2))/(G*(1.0 + H)*J)) + else: + theta_tripleprime = 0 + return theta_tripleprime +#Test Area + +T = 90 #k-in +G = 11200 #ksi +J = 1.39 #in4 +Cw = 2070 #in6 +E = 29000 #ksi +a = ((E*Cw) / (G*J))**0.5 #Torsional Constant +l = 180 #in +alpha = 0.5 + +test = torsion_case6(T, G, J, l, a, alpha) +check = [] + +test_theta = test.theta(90) + +check.append(test_theta*((G*J)/T)*(1/a)) + +test_thetap = test.thetap(90) + +check.append(test_thetap*((G*J)/(T))) + +test_thetapp = test.thetapp(90) + +check.append(test_thetapp*((G*J)/T)*a) + +test_thetappp = test.thetappp(90) + +check.append(test_thetappp * ((G*J)/T)*a*a) + + diff --git a/Code/line_helper_gui.py b/Code/line_helper_gui.py index 9a0e727..a0d3a53 100644 --- a/Code/line_helper_gui.py +++ b/Code/line_helper_gui.py @@ -1,18 +1,28 @@ -#!/usr/bin/env python - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import Tkinter as tk diff --git a/Code/snow_drift by polygons.py b/Code/snow_drift by polygons.py deleted file mode 100644 index 6b89207..0000000 --- a/Code/snow_drift by polygons.py +++ /dev/null @@ -1,768 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu May 10 16:08:02 2018 - -@author: DonB -""" -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -from __future__ import division -import math -import numpy as np -import matplotlib.pyplot as plt - -def length_by_two_points(ax,ay,bx,by): - dx = abs(bx - ax) - dy = abs(by - ay) - - length = (dx*dx + dy*dy)**0.5 - - return length - -def angle_by_two_points(ax,ay,bx,by): - dx = bx-ax - dy = by-ay - - if dx == 0 and dy > 0: - angle = 90 - - elif dx == 0 and dy <0: - angle = 270 - - else: - angle = math.atan2(dy, dx) - angle = angle * (180/math.pi) - - if angle < 0: - angle = angle + 360 - - return angle - -def point_at_angle_distance(a=[0,0],angle_degrees=0,distance=1): - #determine point at distance and angle from point 0 - - dx = math.cos(math.radians(angle_degrees))*distance - dy = math.sin(math.radians(angle_degrees))*distance - - point = [a[0] + dx, a[1] + dy] - - return point - -def line_line_intersection_points(a0x,a0y,a1x,a1y,b0x,b0y,b1x,b1y): - - try: - A = np.array([[a0x, a0y], [a1x, a1y]]) - B = np.array([[b0x, b0y], [b1x, b1y]]) - t, s = np.linalg.solve(np.array([A[1]-A[0], B[0]-B[1]]).T, B[0]-A[0]) - res = [] - res.append(((1-t)*A[0] + t*A[1])) - res.append(((1-s)*B[0] + s*B[1])) - except: - res = 'no int' - - return res - -def vector_direction(x1,y1,x2,y2): - dx = x2-x1 - dy = y2-y1 - angle = math.atan2(dy,dx) % (2*math.pi) - - return angle - -class Line: - def __init__(self, start=[0,0], end=[1,1], hc_ft = 1.0, label='1', location='e'): - self.error_string = '' - - if start == end: - self.error_string = 'Not Valid - Start Point = End Point' - - else: - self.start = start - self.end = end - self.startx = start[0] - self.starty = start[1] - self.endx = end[0] - self.endy = end[1] - - self.location = location - self.length_calc() - self.angle_degrees_calc() - self.hc_ft = hc_ft - self.label = label - - self.drift_line_x = [] - self.drift_line_y = [] - self.drift_lu = [] - self.drift_hd = [] - self.drift_pd = [] - self.drift_w = [] - self.drift_plot_labels = [] - - - def reset_drift_lines(self): - self.drift_line_x = [] - self.drift_line_y = [] - self.drift_lu = [] - self.drift_hd = [] - self.drift_pd = [] - self.drift_plot_labels = [] - - def length_calc(self): - dx = abs(self.endx - self.startx) - dy = abs(self.endy - self.starty) - - self.length = (dx**2 + dy**2)**0.5 - - return self.length - - def angle_degrees_calc(self): - dx = self.endx - self.startx - dy = self.endy - self.starty - - if dx == 0 and dy > 0: - angle = 90 - - elif dx == 0 and dy <0: - angle = 270 - - else: - angle = math.atan2(dy, dx) - angle = angle * (180/math.pi) - - if angle < 0: - angle = angle + 360 - - self.perp_angle = angle + 90 - - if self.location == 'i': - self.perp_angle = self.perp_angle + 180 - else: - pass - - self.angle = angle - - return angle - - def interior_points_calc(self,num_points): - l = self.length - step = l/(num_points+1) - - start = point_at_angle_distance(self.start,self.angle,0.125) - end = point_at_angle_distance(self.end,self.angle,-0.125) - points = [start] - - for i in range(1,num_points+1): - t = (i*step)/self.length - - x = ((1-t)*self.startx) + (t*self.endx) - y = ((1-t)*self.starty) + (t*self.endy) - - point = [x,y] - - points.append(point) - - points.append(end) - self.internal_points = points - self.internal_points_x = [coordx[0] for coordx in points] - self.internal_points_y = [coordy[1] for coordy in points] - - return points - - def drift_at_point(self, point_on_self, lines, snow_density_pcf, pg_psf, logging=1): - dist=10 - perp_line_start = point_on_self - angle = self.perp_angle - - calc_log = '' - - perp_lines = [] - intersect_points = [] - points_x = [] - points_y = [] - - if logging == 1: - calc_log = calc_log + indent + 'Internal Point ({0:.3f},{1:.3f}):\n'.format(point_on_self[0],point_on_self[1]) - calc_log = calc_log + 2*indent + 'Perpendicular Angle:{0:.4f} degrees\n'.format(angle) - else: - pass - - perp_line_end = point_at_angle_distance(perp_line_start, angle, dist) - - b0x = perp_line_start[0] - b0y = perp_line_start[1] - b1x = perp_line_end[0] - b1y = perp_line_end[1] - - perp_line_vector = vector_direction(b0x,b0y,b1x,b1y) - - if logging == 1: - calc_log = calc_log + 2*indent + 'Perpendicular Line:\n'+ 2*indent +'start:({0:.4f},{1:.4f})\n{4}end:({2:.4f},{3:.4f})\n'.format(b0x,b0y,b1x,b1y,2*indent) - else: - pass - - valid_point = 0 - lu_valid = [] - for check_line in lines: - if check_line == self: - pass - else: - if logging == 1: - calc_log = calc_log + '\n' + 3*indent + 'Intersection with {0}:\n'.format(check_line.label) - else: - pass - a0x = check_line.startx - a0y = check_line.starty - a1x = check_line.endx - a1y = check_line.endy - - intersect_point = line_line_intersection_points(a0x,a0y,a1x,a1y,b0x,b0y,b1x,b1y) - - if intersect_point == 'no int': - if logging == 1: - calc_log = calc_log + 3*indent + 'No Intersection\n' - else: - pass - else: - point_x = intersect_point[0][0] - point_y = intersect_point[0][1] - - #check point within start, end vertices of line being checked against - x_ok = min(a0x,a1x)-tolerance <= point_x <= max(a0x,a1x)+tolerance - y_ok = min(a0y,a1y)-tolerance <= point_y <= max(a0y,a1y)+tolerance - - #check point vector same as perp line - point_vector = vector_direction(b0x,b0y,point_x,point_y) - - if logging == 1: - calc_log = calc_log + 3*indent + 'x = {0}\n'.format(point_x) - calc_log = calc_log + 3*indent + 'range: {0} - {1}\n'.format(a0x,a1x) - calc_log = calc_log + 3*indent + 'check: {0}\n'.format(x_ok) - calc_log = calc_log + 3*indent + 'y = {0}\n'.format(point_y) - calc_log = calc_log + 3*indent + 'range: {0} - {1}\n'.format(a0y,a1y) - calc_log = calc_log + 3*indent + 'check: {0}\n'.format(y_ok) - calc_log = calc_log + 3*indent + 'Vector: {0} = Perp-Vector: {1}\n'.format(point_vector,perp_line_vector) - else: - pass - - if x_ok == True and y_ok == True and (perp_line_vector-tolerance) <= point_vector <= (perp_line_vector+tolerance): - valid_point +=1 - - intersect_points.append(intersect_point) - points_x.append(point_x) - points_y.append(point_y) - - dx = abs(point_x - b0x) - dy = abs(point_y - b0y) - - lu = (dx**2 + dy**2)**0.5 - lu_calc = lu - lu = max(lu,25) - - lu_valid.append(lu) - - if logging == 1: - calc_log = calc_log + 3*indent + 'Valid Intersection\n' - calc_log = calc_log + 4*indent + 'Lu = {0:.3f}\n'.format(lu_calc) - calc_log = calc_log + 4*indent + 'Lu = {0:.3f} - min lu of 25\n'.format(lu) - else: - pass - - else: - pass - try: - lu = min(lu_valid) - except: - lu = 0 - - hd_ft = (0.43 * (lu**(1.0/3.0))*((pg_psf+10)**(1.0/4.0))) - 1.5 - hd_calc = hd_ft - hd_ft = 0.75 * hd_ft - - if logging == 1: - calc_log = calc_log + '\n' + 2*indent + 'Valid Intersections:{0}\n\n'.format(valid_point) - calc_log = calc_log + 2*indent + '**Drift Calculation**\n'.format(lu) - calc_log = calc_log + 2*indent + 'Lu = {0:.3f}\n'.format(lu) - calc_log = calc_log + 2*indent + 'Lu = {0:.3f} - min lu of 25\n'.format(lu) - calc_log = calc_log + 2*indent + 'hd = {0:.3f}\n'.format(hd_calc) - calc_log = calc_log + 2*indent + '0.75*hd = {0:.3f}\n'.format(hd_ft) - calc_log = calc_log + 2*indent + 'Edge Height = {0:.3f}\n'.format(self.hc_ft) - else: - pass - - if hd_ft <= self.hc_ft: - w_ft = 4*hd_ft - hd_ft = hd_ft - if logging == 1: - calc_log = calc_log + 2*indent + 'w = 4*hd = {0:.3f}\n'.format(w_ft) - calc_log = calc_log + 2*indent + 'hd = hd = {0:.3f}\n'.format(hd_ft) - else: - pass - else: - w_ft = min((4*hd_ft**2)/self.hc_ft, 8*self.hc_ft) - hd_ft = self.hc_ft - if logging == 1: - calc_log = calc_log + 2*indent + 'w = min of 4*hd^2 / hc and 8*hc = {0:.3f}\n'.format(w_ft) - calc_log = calc_log + 2*indent + 'hd = hc = {0:.3f}\n'.format(self.hc_ft) - else: - pass - - drift_point = point_at_angle_distance(perp_line_start, angle, w_ft) - - pd_psf = snow_density_pcf*hd_ft - - if logging == 1: - calc_log = calc_log + 2*indent + 'Angle to Intersection: {0:.3f}\n'.format(angle) - calc_log = calc_log + 2*indent + 'pd = {0:.3f}\n'.format(pd_psf) - calc_log = calc_log + 2*indent + 'Interior Drift Coord = ({0:.3f},{1:.3f})\n\n'.format(drift_point[0],drift_point[1]) - else: - pass - - drift_string = 'lu = {0:.2f} ft\nhd = {1:.2f} ft\nw = {2:.2f} ft\npd = {3:.2f} psf'.format(lu,hd_ft,w_ft,pd_psf) - - return calc_log, perp_lines, intersect_points, points_x, points_y, drift_string - -def drift_all(lines, snow_density_pcf, pg_psf,number_of_points=10, logging=1): - - calc_log = '' - - perp_lines = [] - intersect_points = [] - points_x = [] - points_y = [] - - dist = 10 - - for line in lines: - if logging == 1: - int_points = number_of_points - calc_log = calc_log + 'Number of Interior Points: {0}:\n'.format(int_points) - else: - int_points = number_of_points - - line.interior_points_calc(int_points) - line.reset_drift_lines() - - if logging == 1: - calc_log = calc_log + '\n--Intersection points for {0}--:\n'.format(line.label) - else: - pass - - count = 0 - for interior_point in line.internal_points: - perp_line_start = interior_point - angle = line.perp_angle - - if logging == 1: - calc_log = calc_log + indent + 'Internal Point {0}:\n'.format(count+1) - calc_log = calc_log + 2*indent + 'Perpendicular Angle:{0:.4f} degrees\n'.format(angle) - else: - pass - - perp_line_end = point_at_angle_distance(perp_line_start, angle, dist) - - perp_lines.append([perp_line_start, perp_line_end]) - - b0x = perp_line_start[0] - b0y = perp_line_start[1] - b1x = perp_line_end[0] - b1y = perp_line_end[1] - - perp_line_vector = vector_direction(b0x,b0y,b1x,b1y) - - if logging == 1: - calc_log = calc_log + 2*indent + 'Perpendicular Line:\n'+ 2*indent +'start:({0:.4f},{1:.4f})\n{4}end:({2:.4f},{3:.4f})\n'.format(b0x,b0y,b1x,b1y,2*indent) - else: - pass - - valid_point = 0 - lu_valid = [] - for check_line in lines: - if check_line == line: - pass - else: - if logging == 1: - calc_log = calc_log + '\n' + 3*indent + 'Intersection with {0}:\n'.format(check_line.label) - else: - pass - a0x = check_line.startx - a0y = check_line.starty - a1x = check_line.endx - a1y = check_line.endy - - intersect_point = line_line_intersection_points(a0x,a0y,a1x,a1y,b0x,b0y,b1x,b1y) - - if intersect_point == 'no int': - if logging == 1: - calc_log = calc_log + 3*indent + 'No Intersection\n' - else: - pass - else: - point_x = intersect_point[0][0] - point_y = intersect_point[0][1] - - #check point within start, end vertices of line being checked against - x_ok = min(a0x,a1x)-tolerance <= point_x <= max(a0x,a1x)+tolerance - y_ok = min(a0y,a1y)-tolerance <= point_y <= max(a0y,a1y)+tolerance - - #check point vector same as perp line - point_vector = vector_direction(b0x,b0y,point_x,point_y) - - if logging == 1: - calc_log = calc_log + 3*indent + 'x = {0}\n'.format(point_x) - calc_log = calc_log + 3*indent + 'range: {0} - {1}\n'.format(a0x,a1x) - calc_log = calc_log + 3*indent + 'check: {0}\n'.format(x_ok) - calc_log = calc_log + 3*indent + 'y = {0}\n'.format(point_y) - calc_log = calc_log + 3*indent + 'range: {0} - {1}\n'.format(a0y,a1y) - calc_log = calc_log + 3*indent + 'check: {0}\n'.format(y_ok) - calc_log = calc_log + 3*indent + 'Vector: {0} = Perp-Vector: {1}\n'.format(point_vector,perp_line_vector) - else: - pass - - if x_ok == True and y_ok == True and (perp_line_vector-tolerance) <= point_vector <= (perp_line_vector+tolerance): - valid_point +=1 - - intersect_points.append(intersect_point) - points_x.append(point_x) - points_y.append(point_y) - - dx = abs(point_x - b0x) - dy = abs(point_y - b0y) - - lu = (dx**2 + dy**2)**0.5 - lu_calc = lu - lu = max(lu,25) - - lu_valid.append(lu) - - if logging == 1: - calc_log = calc_log + 3*indent + 'Valid Intersection\n' - calc_log = calc_log + 4*indent + 'Lu = {0:.3f}\n'.format(lu_calc) - calc_log = calc_log + 4*indent + 'Lu = {0:.3f} - min lu of 25\n'.format(lu) - else: - pass - - else: - pass - try: - lu = min(lu_valid) - except: - lu = 0 - - hd_ft = (0.43 * (lu**(1.0/3.0))*((pg_psf+10)**(1.0/4.0))) - 1.5 - hd_calc = hd_ft - hd_ft = 0.75 * hd_ft - - if logging == 1: - calc_log = calc_log + '\n' + 2*indent + 'Valid Intersections:{0}\n\n'.format(valid_point) - calc_log = calc_log + 2*indent + '**Drift Calculation**\n'.format(lu) - calc_log = calc_log + 2*indent + 'Lu = {0:.3f}\n'.format(lu) - calc_log = calc_log + 2*indent + 'Lu = {0:.3f} - min lu of 25\n'.format(lu) - calc_log = calc_log + 2*indent + 'hd = {0:.3f}\n'.format(hd_calc) - calc_log = calc_log + 2*indent + '0.75*hd = {0:.3f}\n'.format(hd_ft) - calc_log = calc_log + 2*indent + 'Edge Height = {0:.3f}\n'.format(line.hc_ft) - else: - pass - - if hd_ft <= line.hc_ft: - w_ft = 4*hd_ft - hd_ft = hd_ft - if logging == 1: - calc_log = calc_log + 2*indent + 'w = 4*hd = {0:.3f}\n'.format(w_ft) - calc_log = calc_log + 2*indent + 'hd = hd = {0:.3f}\n'.format(hd_ft) - else: - pass - else: - w_ft = min((4*hd_ft**2)/line.hc_ft, 8*line.hc_ft) - hd_ft = line.hc_ft - if logging == 1: - calc_log = calc_log + 2*indent + 'w = min of 4*hd^2 / hc and 8*hc = {0:.3f}\n'.format(w_ft) - calc_log = calc_log + 2*indent + 'hd = hc = {0:.3f}\n'.format(line.hc_ft) - else: - pass - - drift_point = point_at_angle_distance(perp_line_start, angle, w_ft) - - pd_psf = snow_density_pcf*hd_ft - - if logging == 1: - calc_log = calc_log + 2*indent + 'Angle to Intersection: {0:.3f}\n'.format(angle) - calc_log = calc_log + 2*indent + 'pd = {0:.3f}\n'.format(pd_psf) - calc_log = calc_log + 2*indent + 'Interior Drift Coord = ({0:.3f},{1:.3f})\n\n'.format(drift_point[0],drift_point[1]) - else: - pass - - line.drift_line_x.append(drift_point[0]) - line.drift_line_y.append(drift_point[1]) - line.drift_lu.append(lu) - line.drift_hd.append(hd_ft) - line.drift_pd.append(pd_psf) - line.drift_w.append(w_ft) - drift_string = 'lu = {0:.2f} ft, hd = {1:.2f} ft, w = {2:.2f} ft\npd = {3:.2f} psf'.format(lu,hd_ft,w_ft,pd_psf) - line.drift_plot_labels.append(drift_string) - - count+=1 - - return calc_log, perp_lines, intersect_points, points_x, points_y - -def lines_transformation_to_origin(lines): - x = [] - y = [] - - for line in lines: - x.append(line.startx) - y.append(line.starty) - x.append(line.endx) - y.append(line.endy) - - shift_x = min(x) - shift_y = min(y) - - max_x = max(x) - shift_x - max_y = max(y) - shift_y - - return shift_x, shift_y, max_x, max_y - -def line_closest_to_point_and_point_on_line(point, lines): - point_x = point[0] - point_y = point[1] - - distance_to_each_line = [] - point_on_each_line = [] - - tolerance = 0.000001 - - for line in lines: - a0x = line.startx - a0y = line.starty - a1x = line.endx - a1y = line.endy - #check point within start, end vertices of line being checked against - x_ok = min(a0x,a1x)-tolerance <= point_x <= max(a0x,a1x)+tolerance - y_ok = min(a0y,a1y)-tolerance <= point_y <= max(a0y,a1y)+tolerance - - #secondary point at unit distance at 180+line perp angle - point_2 = point_at_angle_distance(point,line.perp_angle+180,1) - int_point = line_line_intersection_points(a0x,a0y,a1x,a1y,point[0],point[1],point_2[0],point_2[1]) - - if int_point == 'no int': - distance_to_each_line.append(1000000) - point_on_each_line.append([line.startx,line.starty]) - else: - #check point within start, end vertices of line being checked against - x1_ok = min(a0x,a1x)-tolerance <= int_point[0][0] <= max(a0x,a1x)+tolerance - y1_ok = min(a0y,a1y)-tolerance <= int_point[0][1] <= max(a0y,a1y)+tolerance - - if x1_ok==False or y1_ok==False: - distance_to_each_line.append(1000000) - point_on_each_line.append([line.startx,line.starty]) - else: - distance = length_by_two_points(point[0],point[1],int_point[0][0],int_point[0][1]) - distance_to_each_line.append(distance) - point_on_each_line.append([int_point[0][0],int_point[0][1]]) - - segment = distance_to_each_line.index(min(distance_to_each_line)) - segment_point = point_on_each_line[segment] - segment += 1 - - return distance_to_each_line, point_on_each_line, segment, segment_point - - - - - -##testing area -logging = 0 -write_dxf = 0 -create_plot = 1 - -tolerance = 0.000001 - -pg_psf = 25 -snow_density_pcf = min((0.13*pg_psf) + 14, 30) -Ce = 1.0 -Ct = 1.0 -Cs = 1.0 -I = 1.0 -pf_psf = 0.7*Ce*Ct*I*pg_psf -ps_psf = Cs*pf_psf -hb_ft = ps_psf/snow_density_pcf - -hc_ft = [3,3,3,3,3,3,3,3] - -x = [1,51,51,51,51,26,26,26,26,11,11,11,11,1,1,1] -y = [1,1,1,51,51,51,51,26,26,26,26,61,61,61,61,1] - -loc = ['e','e','e','e','e','e','e','e'] - -if logging == 1: - calc_log = '---Calculation Log---\n\n--Create Lines--\n' -else: - pass - -indent = ' ' -lines = [] - -hc=0 -for i in range(0, int(len(x)/2)): - if logging == 1: - calc_log = calc_log + 'Line {0}:\n'.format(i+1) - label = 'Line {0}'.format(i+1) - if i == 0: - i = i - else: - i *=2 - - xs = x[i] - ys = y[i] - start = [xs,ys] - xe = x[i+1] - ye = y[i+1] - end = [xe,ye] - lines.append(Line(start,end, hc_ft[hc],label,loc[hc])) - if logging == 1: - calc_log = calc_log + 'start:({0:.4f},{1:.4f})\nend:({2:.4f},{3:.4f})\n\n'.format(xs,ys,xe,ye) - else: - pass - hc+=1 - -aab = ((1-0.5)*lines[0].startx) + (0.5*lines[0].endx) -baa = ((1-0.5)*lines[0].starty) + (0.5*lines[0].endy) - -point_on_self = [aab,baa] -a_calc_log_line, a_perp_lines_line, a_intersect_points_line, a_points_x_line, a_points_y_line, a_drift_string_line = lines[0].drift_at_point(point_on_self, lines, snow_density_pcf, pg_psf, 1) - -calc_log, perp_lines, intersect_points, points_x, points_y = drift_all(lines,snow_density_pcf,pg_psf,25,1) - -s_x, s_y, mx, my = lines_transformation_to_origin(lines) -print s_x -print s_y -print mx -print my - -test1, test2, segment, segment_point = line_closest_to_point_and_point_on_line([35.5,9.4],lines) -print test1 -print test2 -print segment -print segment_point - -colors = ['r','b','g','c','m','y','k','r','b','g','c','m','y','k','r','b','g','c','m','y','k','r','b','g','c','m','y','k','r','b','g','c','m','y','k','r','b','g','c','m','y','k','r','b','g','c','m','y','k'] -i=0 - -if create_plot == 1: - for line in lines: - plt.plot([line.startx,line.endx], [line.starty,line.endy], color=colors[i]) - plt.plot(line.drift_line_x, line.drift_line_y, color=colors[i], marker = '+') - plt.plot(line.internal_points_x, line.internal_points_y, color=colors[i], marker = '+') - #plt.plot(line.drift_line_x, line.drift_line_y, color=colors[i]) - #plt.plot(line.internal_points_x, line.internal_points_y, color=colors[i]) - k=0 - prev_label = '' - for point in line.internal_points_x: - label = '{0:.2f} psf\nw = {1:.2f} ft'.format(line.drift_pd[k], line.drift_w[k]) - if k+1 > len(line.drift_w)-1: - next_label = '' - else: - next_label = '{0:.2f} psf\nw = {1:.2f} ft'.format(line.drift_pd[k+1], line.drift_w[k+1]) - if label != prev_label or label != next_label: - angle = 45 - plt.annotate(label,xy=(line.internal_points_x[k], line.internal_points_y[k]), xycoords='data', rotation=angle, horizontalalignment='left', verticalalignment='bottom' ) - plt.plot([line.internal_points_x[k],line.drift_line_x[k]], [line.internal_points_y[k],line.drift_line_y[k]], color='k') - else: - pass - k+=1 - prev_label = label - i+=1 - - plt.ylim(ymax=max(y)+5, ymin=min(y)-5) - plt.xlim(xmax=max(x)+5, xmin=min(x)-5) - - plt.show() -else: - pass - -if logging == 1: - file = open('Drift_by_lines_log.txt','w') - file.write(calc_log) - file.close() -else: - pass - -#DXF file -if write_dxf == 1: - file = open('Drift_by_lines.dxf','w') - file.write(' 0\nSECTION\n 2\nENTITIES\n') - - for line in lines: - x0 = line.startx - y0 = line.starty - x1 = line.endx - y1 = line.endy - if line.location == 'e': - layer = 'Exterior' - else: - layer = 'Interior' - - file.write(' 0\nPOLYLINE\n 8\n{0}\n 66\n1\n 10\n0.0\n 20\n0.0\n 30\n0.0\n 70\n8\n'.format(layer)) - file.write(' 0\nVERTEX\n 8\n{0}\n 10\n{1:.3f}\n 20\n{2:.3f}\n 30\n0.0\n'.format(layer,x0,y0)) - file.write(' 0\nVERTEX\n 8\n{0}\n 10\n{1:.3f}\n 20\n{2:.3f}\n 30\n0.0\n'.format(layer,x1,y1)) - file.write(' 0\nSEQEND\n') - - file.write(' 0\nPOLYLINE\n 62\n4\n 8\nDrift\n 66\n1\n 10\n0.0\n 20\n0.0\n 30\n0.0\n 70\n8\n') - - for i in range(0, len(line.drift_line_x)): - x_drift = line.drift_line_x[i] - y_drift = line.drift_line_y[i] - file.write(' 0\nVERTEX\n 8\nDrift\n 10\n{0:.3f}\n 20\n{1:.3f}\n 30\n0.0\n'.format(x_drift,y_drift)) - file.write(' 0\nSEQEND\n') - - k=0 - prev_label = '' - for point in line.internal_points_x: - label = '{0:.2f} psf - w = {1:.2f} ft'.format(line.drift_pd[k], line.drift_w[k]) - if k+1 > len(line.drift_w)-1: - next_label = '' - else: - next_label = '{0:.2f} psf - w = {1:.2f} ft'.format(line.drift_pd[k+1], line.drift_w[k+1]) - if label != prev_label or label != next_label: - file.write(' 0\nPOLYLINE\n 8\nDrift-Label\n 66\n1\n 10\n0.0\n 20\n0.0\n 30\n0.0\n 70\n8\n') - x2 = line.internal_points_x[k] - y2 = line.internal_points_y[k] - x3 = line.drift_line_x[k] - y3 = line.drift_line_y[k] - file.write(' 0\nVERTEX\n 8\nDrift-Label\n 10\n{0:.3f}\n 20\n{1:.3f}\n 30\n0.0\n'.format(x2,y2)) - file.write(' 0\nVERTEX\n 8\nDrift-Label\n 10\n{0:.3f}\n 20\n{1:.3f}\n 30\n0.0\n'.format(x3,y3)) - file.write(' 0\nSEQEND\n') - - real_label = 'pd = {0:.2f} psf, w = {1:.2f} ft'.format(line.drift_pd[k], line.drift_w[k]) - - angle = angle_by_two_points(x2,y2,x3,y3) - length = length_by_two_points(x2,y2,x3,y3) - anno_pt = point_at_angle_distance([x2,y2],angle,0) - - if 90.99 < angle < 269.99: - angle = angle + 180 - else: - pass - - file.write(' 0\nTEXT\n 62\n3\n 8\nDrift-Label\n 10\n{0:.3f}\n 20\n{1:.3f}\n 30\n0.0\n 40\n0.5\n 1\n{2}\n 72\n0\n 50\n{3:.4f}\n 11\n{0:.3f}\n 21\n{1:.3f}\n 31\n0.0\n 73\n1\n'.format(anno_pt[0],anno_pt[1],real_label,angle)) - else: - pass - k+=1 - prev_label = label - - file.write(' 0\nENDSEC\n 0\nEOF') - file.close() -else: - pass diff --git a/Code/snow_drift_by_polygons.py b/Code/snow_drift_by_polygons.py index f569fad..1c7d80c 100644 --- a/Code/snow_drift_by_polygons.py +++ b/Code/snow_drift_by_polygons.py @@ -1,22 +1,28 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu May 10 16:08:02 2018 - -@author: DonB -""" -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import math diff --git a/Code/snow_drift_gui.py b/Code/snow_drift_gui.py index 2ed9f17..8dfb867 100644 --- a/Code/snow_drift_gui.py +++ b/Code/snow_drift_gui.py @@ -1,18 +1,28 @@ -# -*- coding: utf-8 -*- - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import math as m @@ -92,7 +102,7 @@ def __init__(self, master): self.g_plan_frame = tk.Frame(self.g_plan, bd=2, relief='sunken', padx=1,pady=1) self.g_plan_frame.pack(fill=tk.BOTH,expand=1, padx=5, pady=5) - self.g_plan_canvas = tk.Canvas(self.g_plan_frame, width=50, height=50, bd=2, relief='sunken', background="gray60") + self.g_plan_canvas = tk.Canvas(self.g_plan_frame, width=50, height=50, bd=2, relief='sunken', background="black") self.g_plan_canvas.bind("", self.draw_drift) self.g_plan_canvas.pack(side = tk.LEFT, anchor='c', padx= 1, pady= 1, fill=tk.BOTH, expand=1) @@ -103,7 +113,7 @@ def __init__(self, master): self.g_elev_frame = tk.Frame(self.g_elev, bd=2, relief='sunken', padx=1,pady=1) self.g_elev_frame.pack(fill=tk.BOTH,expand=1, padx=5, pady=5) - self.g_elev_canvas = tk.Canvas(self.g_elev_frame, width=50, height=50, bd=2, relief='sunken', background="gray60") + self.g_elev_canvas = tk.Canvas(self.g_elev_frame, width=50, height=50, bd=2, relief='sunken', background="black") #self.g_elev_canvas.bind("", self.draw_elevation) self.g_elev_canvas.pack(side = tk.LEFT, anchor='c', padx= 1, pady= 1, fill=tk.BOTH, expand=1) @@ -278,20 +288,20 @@ def __init__(self, master): def license_display(self, *event): # Function to display license dialog on app start - license_string = ("This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n\n" - - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n\n" - - "You should have received a copy of the GNU General Public License along" - "with this program; if not, write to the Free Software Foundation, Inc.," - "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" - "\nA copy of the License can be viewed at:\n https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE") + license_string = ("Copyright (c) 2019, Donald N. Bockoven III\n" + "All rights reserved.\n\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" + " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" + " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" + " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" + " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" + " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" + " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," + " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" + "https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE" + ) tkMessageBox.showerror("License Information",license_string) self.master.focus_force() diff --git a/Concrete/Circular Arc - Constant Stress Block.pdf b/Concrete/Circular Arc - Constant Stress Block.pdf new file mode 100644 index 0000000..ecdcd48 Binary files /dev/null and b/Concrete/Circular Arc - Constant Stress Block.pdf differ diff --git a/Concrete/Concrete.pdf b/Concrete/Concrete.pdf new file mode 100644 index 0000000..a15a8a9 Binary files /dev/null and b/Concrete/Concrete.pdf differ diff --git a/Concrete/concrete_T_beam_any_steel_gui.py b/Concrete/concrete_T_beam_any_steel_gui.py index f0c6b7e..cefefa3 100644 --- a/Concrete/concrete_T_beam_any_steel_gui.py +++ b/Concrete/concrete_T_beam_any_steel_gui.py @@ -1,18 +1,28 @@ -# -*- coding: utf-8 -*- - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division @@ -346,20 +356,20 @@ def __init__(self, master): self.license_display() def license_display(self, *event): - license_string = ("This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n\n" - - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n\n" - - "You should have received a copy of the GNU General Public License along" - "with this program; if not, write to the Free Software Foundation, Inc.," - "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" - "\nA copy of the License can be viewed at:\n https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE") + license_string = ("Copyright (c) 2019, Donald N. Bockoven III\n" + "All rights reserved.\n\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" + " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" + " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" + " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" + " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" + " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" + " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," + " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" + "https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE" + ) tkMessageBox.showerror("License Information",license_string) self.master.focus_force() @@ -803,7 +813,10 @@ def print_dxf(self): num_interior = int(self.flexural_bars_array_dxf[1][i]) - 2 num_interior_spaces = num_interior + 1 interior_space = (self.beamsection.bw_in - self.beamsection.first_interior_bar_in) - self.beamsection.first_interior_bar_in - spacing = interior_space/(1.00*num_interior_spaces) + if num_interior_spaces == 0: + spacing = 0 + else: + spacing = interior_space/(1.00*num_interior_spaces) if self.flexural_bars_array_dxf[6][i] <0: color = 10 else: diff --git a/Concrete/concrete_T_beam_gui.py b/Concrete/concrete_T_beam_gui.py index a7ee6a0..50671ec 100644 --- a/Concrete/concrete_T_beam_gui.py +++ b/Concrete/concrete_T_beam_gui.py @@ -1,18 +1,28 @@ -# -*- coding: utf-8 -*- - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division @@ -398,20 +408,20 @@ def __init__(self, master): self.license_display() def license_display(self, *event): - license_string = ("This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n\n" - - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n\n" - - "You should have received a copy of the GNU General Public License along" - "with this program; if not, write to the Free Software Foundation, Inc.," - "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" - "\nA copy of the License can be viewed at:\n https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE") + license_string = ("Copyright (c) 2019, Donald N. Bockoven III\n" + "All rights reserved.\n\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" + " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" + " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" + " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" + " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" + " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" + " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," + " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" + "https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE" + ) tkMessageBox.showerror("License Information",license_string) self.master.focus_force() diff --git a/Concrete/concrete_beam_classes.py b/Concrete/concrete_beam_classes.py index ff5d40b..760a364 100644 --- a/Concrete/concrete_beam_classes.py +++ b/Concrete/concrete_beam_classes.py @@ -1,16 +1,28 @@ -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import math @@ -470,11 +482,19 @@ def strain_compatibility_steel(self,bars_as_array,bars_d_array,c_in,fy_psi,Es_ps steel_strain.append(0.003*((bars_d_array[i]/c_in)-1)) fs = steel_strain[i] * Es_psi if fs < -1*fy_psi or fs > fy_psi: - steel_stress.append((fs/abs(fs))*fy_psi) - steel_tension_force_layer_lbs.append(((fs/abs(fs))*fy_psi)*bars_as_array[i]) + if fs<0: + steel_stress.append((fs/abs(fs))*fy_psi) + steel_tension_force_layer_lbs.append((((fs/abs(fs))*fy_psi)+0.85*self.f_prime_c_psi)*bars_as_array[i]) + else: + steel_stress.append((fs/abs(fs))*fy_psi) + steel_tension_force_layer_lbs.append(((fs/abs(fs))*fy_psi)*bars_as_array[i]) else: - steel_stress.append(fs) - steel_tension_force_layer_lbs.append(fs*bars_as_array[i]) + if fs<0: + steel_stress.append(fs) + steel_tension_force_layer_lbs.append((fs+0.85*self.f_prime_c_psi)*bars_as_array[i]) + else: + steel_stress.append(fs) + steel_tension_force_layer_lbs.append(fs*bars_as_array[i]) steel_tension_force_lbs = sum(steel_tension_force_layer_lbs) @@ -515,8 +535,8 @@ def find_pna(self,bars_as_array,bars_d_array,bars_cg,fy_psi,Es_psi): else: a = c loop+=1 - print tension_c - print pna + print(tension_c) + print(pna) return pna def moment_capacity_inlbs(self,bars_as_array,bars_d_array,bars_cg,c_in,fy_psi,Es_psi): diff --git a/Concrete/concrete_common.py b/Concrete/concrete_common.py new file mode 100644 index 0000000..285447d --- /dev/null +++ b/Concrete/concrete_common.py @@ -0,0 +1,595 @@ +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' + +from __future__ import division +import math +import matplotlib.pyplot as plt + +def stress_strain_pca(fprimec, ultimate_strain, concrete_modulus, strain): + ''' + PCA Stress-Strain Relationship + formula presented in the PCA notes to ACI 318-05 + ''' + + e = strain + Ec = concrete_modulus + eu = ultimate_strain + fc = fprimec + + eo = (2*0.85*fc)/(Ec) + + if e <= 0: + stress = 0 + + elif 0<=e and e<=eo: + stress = 0.85*fc*((2*(e/eo))-((e/eo)*(e/eo))) + + elif e<=eu: + stress = 0.85*fc + else: + stress = 0 + + return stress + +def stress_strain_desayi_krishnan(fprimec, ultimate_strain, k, strain): + ''' + method for a parabolic stress-strain relationship for concrete in compression + Desayi, P. and Krishnan, S., Equation for the Stress-Strain Curve of Concrete, ACI + Journal, Proceedings V. 61, No. 3, Mar. 1964, pp. 345-350 + + fprimec = f'c = 28-day compressive strength of concrete -- type: float + ultimate_strain = eu = strain at failure -- type: float ACI: 0.003 (English Units) + k = k*f'c = stress at ultimate strain -- type: float ACI: 0.85 (English Units) + strain_report = e = strain at location where stress is desired -- type: float + ''' + if strain <=0: + return 0 + + elif strain > ultimate_strain: + return 0 + + else: + fo = fprimec + + # solve for eo = strain at fo + # E = 2*fo / eo + # eo has two possible solutions + # eo = eu - sqrt(-1*(k^2 - 1) * eu^2) / k or sqrt(-1*(k^2 - 1) * eu^2) + eu / k + + eo1 = (ultimate_strain - math.sqrt(-1*(math.pow(k,2) - 1)*math.pow(ultimate_strain,2))) / k + eo2 = (math.sqrt(-1*(math.pow(k,2) - 1)*math.pow(ultimate_strain,2))+ultimate_strain) / k + + eo = min(eo1,eo2) + + E = 2*fo / eo + + f = (E*strain) / (1+math.pow(strain/eo,2)) + + return f*0.85 + +def stress_strain_collins_et_all(fprimec, ultimate_strain, strain): + ''' + method for a parabolic stress-strain relationship for concrete in compression + Collins, M.P., Mitchell D. and MacGregor, J.G., Structural Consideration for High-Strength + Concrete, Concrete International, V. 15, No. 5, May 1993, pp. 27-34. + ''' + if strain <=0: + return 0 + elif strain > ultimate_strain: + return 0 + + else: + k = 0.67 + (fprimec / 9000.0) # for PSI units + n = 0.8 + (fprimec / 2500.0) # for PSI units + Ec = (40000*math.sqrt(fprimec)) + 1000000 # for PSI units + + ecprime = (fprimec / Ec)*(n/(n-1)) + + e = strain/ecprime + + if e <= 1: + f = ((e) * (n / (n-1+math.pow(e,n)))) * fprimec + else: + f = ((e) * (n / (n-1+math.pow(e,n*k)))) * fprimec + + return f*0.85 + +def stress_strain_whitney(fprimec, ultimate_strain, strain): + ''' + method for the Whitney Stress block used in ACI 318 + ''' + + if fprimec <= 4000: + beta1 = 0.85 + elif fprimec <= 8000: + beta1 = 0.85 - ((0.05*(fprimec-4000))/1000) + else: + beta1 = 0.65 + + if strain <= (ultimate_strain - (ultimate_strain*beta1)): + return [0, beta1] + + elif strain <= ultimate_strain: + return [0.85*fprimec, beta1] + + else: + return [0, beta1] + +def stress_strain_steel(fy, yield_strain, Es, strain): + ''' + Linear stress strain definition that will return + a linear value between 0 and +/- the yield strain + or Fy is the strain is above or below the yield strain + ''' + if Es == 0: + if abs(strain) >= yield_strain: + return (strain/abs(strain)) * fy + + else: + return (strain*fy)/yield_strain + else: + if abs(strain)*Es >= fy: + return (strain/abs(strain)) * fy + + else: + return (strain*Es) + + +def strain_at_depth(eu,neutral_axis_depth,depth_of_interest): + ''' + Given and Neutral Axis Depth and the maximum compressive strain + at the extreme compression fiber + + return the associated strain at the depth of interest + + assumptions: + the strain varies linearly along the elevation axis (y-axis) + 0 depth is the point max compression strain, eu. + + will return a (+) strain for areas in compression and a (-) negative + strain when area is in tension + ''' + + c = neutral_axis_depth + d = depth_of_interest + + if c == 0: + c = 0.000001 + else: + c = c + if c-d > 0: + + e = ((c-d)/c)*eu + + else: + e = ((c-d)/c)*eu + + return e + +def plastic_center(bars_x=[1], bars_y=[1], fy=60000, As=[0.31], fc=3000, eu=0.003, k=0.85, conc_area=1, conc_centroid=[0,0]): + ''' + given the ulitmate strain, f'c (28-day) strength and k for concrete + return a the plastic centroid for the three stress-strain equations + of the concrete + + accounting for the bar area subtracting from the concrete area by (fy/fc@eu - 1) + similar approach to transformed sections using n = Es/Ec + ''' + + fc_collins = stress_strain_collins_et_all(fc,eu,eu) + fc_desayi = stress_strain_desayi_krishnan(fc,eu,k,eu) + fc_whitney = stress_strain_whitney(fc,eu,eu) + + fc = [fc_collins, fc_desayi, fc_whitney[0]] + + cc = [i*conc_area for i in fc] + cc_mx = [i*conc_centroid[1] for i in cc] + cc_my = [i*conc_centroid[0] for i in cc] + + C = [] + C_mx = [] + C_my = [] + cb = [] + cb_mx = [] + cb_my = [] + pc = [] + + count = 0 + for c in fc: + cb.append([i * (fy-c) for i in As]) + + C.append(cc[count] + sum(cb[-1])) + + cb_mx.append([(cb[-1][i] * bars_y[i]) for i in range(len(bars_x))]) + cb_my.append([(cb[-1][i] * bars_x[i]) for i in range(len(bars_x))]) + + + C_mx.append(cc_mx[count]+sum(cb_mx[-1])) + C_my.append(cc_my[count]+sum(cb_my[-1])) + + yp = C_mx[-1]/C[-1] + xp = C_my[-1]/C[-1] + + pc.append([xp,yp]) + + count +=1 + + return pc,[fc,cc,cc_mx,cc_my,cb,cb_mx,cb_my,C,C_mx,C_my] + + +#----- START UNI-AXIAL COLUMN EXAMPLE DIAGRAM -----# +# Test the strain at depth function +# assume a 12"x24" section with the na located at 16" +# above the base. The section if oriented with the 24" +# vertical. +b=20 +h=30 +#na = 12 +##lets create a list of y dstances from the top lets say 1 per 0.25" +#count = int(24/0.25)+1 +#y = [0+(i*0.25) for i in range(0,count)] +# +#x = [strain_at_depth(0.003,na,j) for j in y] +# +#plt.close('all') +#plt.plot(x, y, 'r-') +#plt.plot(x,[na]*len(x),'b-') +#plt.plot([0]*len(y),y,'k-') +#plt.set_ylim([-70,70]) +#plt.set_xlim([-0.005,0.005]) +#plt.show() + +# expand on the 12x24 column test subject and generate a P-M value +# for it's strong axis using all three stress block methods at a given +# Neutral-Axis Depth +# Say F'c = 5000 psi and Fy = 60,000 psi +# notice units here axial force will be in pounds +# and moment will be in in-lbs +fc = 5000 +Ec = 57000*math.sqrt(fc) +fy = 60000 +Es = 29000000 +eu = 0.003 +es = 0.002 +k = 0.85 +# lets add a non-symetric steel layout +# with (2)#8 bars in the bottom and (3)#8 bars at the top +# cover = 2" to each corner bar +xb = [4,16,16,10,4] +yb = [4,4,26,26,26] +ab = [1.27]*len(xb) + +acm = (b*h)-sum(ab) +P_max = 0.8*0.65*((0.85*fc*acm)+(fy*sum(ab)))/1000.0 + +xc = b/2.0 +yc = h/2.0 + +# set a point to sum moments about +# lets try the plastic centroid + +pc, pc_backup = plastic_center(xb,yb,fy,ab,fc,eu,k,b*h,[b/2.0,h/2.0]) + +#yc_collins = pc[0][1] +#yc_desayi = pc[0][1] +#yc_whitney = pc[0][1] +#yc_pca = pc[0][1] + +yc_collins = yc +yc_desayi = yc +yc_whitney = yc +yc_pca = yc + + +# Define some empty lists to dump data into for plotting +P_collins_plot = [] +M_collins_plot = [] +P_desayi_plot = [] +M_desayi_plot = [] +P_whitney_plot = [] +M_whitney_plot = [] +P_pca_plot = [] +M_pca_plot = [] +aci_reduction = [] + +e_checks = [] + +#list neutral axis depths +step = (h+400)/500.0 +nas = [(h+400)-(i*step) for i in range(0,499)] + +nas.append(0.000001) +print([nas[0],nas[-1]]) +#nas = [400] + +for na in nas: + # determine the bar strains and stresses + # since this is a unixial check only care + # about the bar Y coordinate + # also remember we need the bar depth + # so we need H-y + b_depths = [h-j for j in yb] + if na > 0: + bstrains = [strain_at_depth(eu, na, j) for j in b_depths] + else: + bstrains = [-0.005]*len(b_depths) + + bstresses = [stress_strain_steel(fy, es, Es, i) for i in bstrains] + + b_strain_phi = min(bstrains) + if b_strain_phi > -0.002: + aci = 0.65 + + elif b_strain_phi <= -0.005: + aci = 0.9 + + else: + aci = 0.65-((b_strain_phi+0.002)*(250/3.0)) + + aci_reduction.append(aci) + + # Bar force is now just Bar Area * Stress + bforce = [i*j for i,j in zip(ab,bstresses)] + + # Remove a component of concrete compression force from + # area coincident with the bars in the compression zone + + bforce_collins = [(q*stress_strain_collins_et_all(fc,eu,j)) if i>0 else 0 for i,j,q in zip(bforce,bstrains,ab)] + bforce_desayi = [(q*stress_strain_desayi_krishnan(fc,eu,k,j)) if i>0 else 0 for i,j,q in zip(bforce,bstrains,ab)] + bforce_whitney = [(q*stress_strain_whitney(fc,eu,j)[0]) if i>0 else 0 for i,j,q in zip(bforce,bstrains,ab)] + bforce_pca = [(q*stress_strain_pca(fc,eu,Ec,j)) if i>0 else 0 for i,j,q in zip(bforce,bstrains,ab)] + + #bforce_whitney = [0]*len(ab) + + # Bar Momments - using right hand rule tensile forces below + # the point we are summing momments about should be positive + # therefore use the signed distance from the bar to the + # point of interest + bmomentarm_collins = [j-yc_collins for j in yb] + bmoment_collins = [i*j for i,j in zip(bforce,bmomentarm_collins)] + bmomentarm_desayi = [j-yc_desayi for j in yb] + bmoment_desayi = [i*j for i,j in zip(bforce,bmomentarm_desayi)] + bmomentarm_whitney = [j-yc_whitney for j in yb] + bmoment_whitney = [i*j for i,j in zip(bforce,bmomentarm_whitney)] + bmomentarm_pca = [j-yc_pca for j in yb] + bmoment_pca = [i*j for i,j in zip(bforce,bmomentarm_pca)] + + bnegmoment_collins = [i*j for i,j in zip(bforce_collins,bmomentarm_collins)] + bnegmoment_desayi = [i*j for i,j in zip(bforce_desayi,bmomentarm_desayi)] + bnegmoment_whitney = [i*j for i,j in zip(bforce_whitney,bmomentarm_whitney)] + bnegmoment_pca = [i*j for i,j in zip(bforce_pca,bmomentarm_pca)] + + # Concrete force + # lets get a list of 200 points between the NA + # and the top of the shape + iter_points = 200 + if 0 < na < h: + yce = [0+(na/iter_points*i) for i in range(0,iter_points+1)] + yce.reverse() + else: + yce = [0+(h/iter_points*i) for i in range(0,iter_points+1)] + yce.reverse() + + + # Get the strains at those points + if na < h: + ce = [strain_at_depth(eu,na,j) for j in yce] + else: + ce = [eu]*len(yce) + +# plt.close('all') +# plt.plot(ce, yce) +# plt.show() + + # Get the stress at each strain for the three stress-strain functions + cs_collins = [stress_strain_collins_et_all(fc,eu,i) for i in ce] + cs_desayi = [stress_strain_desayi_krishnan(fc,eu,k,i) for i in ce] + cs_pca = [stress_strain_pca(fc,eu,Ec,i) for i in ce] + + # to be able to easily the area and center of the 2 parabolic distributions + # lets close of there shape + yce.append(yce[-1]) + yce.append(yce[0]) + yce.append(yce[0]) + cs_collins.extend([0,0,cs_collins[0]]) + cs_desayi.extend([0,0,cs_desayi[0]]) + cs_pca.extend([0,0,cs_pca[0]]) + + #plt.close('all') + #plt.plot(yce,cs_collins) + #plt.show() + + # Area=P and center under each curve + p_collins = sum([(yce[i]*cs_collins[i+1])-(yce[i+1]*cs_collins[i]) for i in range(len(yce[:-1]))])/2.0 + if p_collins == 0: + p_collinsy = 0 + else: + p_collinsy = sum([(yce[i]+yce[i+1])*((yce[i]*cs_collins[i+1])-(yce[i+1]*cs_collins[i])) for i in range(len(yce[:-1]))])/(6*p_collins) + + p_desayi = sum([(yce[i]*cs_desayi[i+1])-(yce[i+1]*cs_desayi[i]) for i in range(len(yce[:-1]))])/2.0 + if p_desayi == 0: + p_desayiy = 0 + else: + p_desayiy = sum([(yce[i]+yce[i+1])*((yce[i]*cs_desayi[i+1])-(yce[i+1]*cs_desayi[i])) for i in range(len(yce[:-1]))])/(6*p_desayi) + + p_pca = sum([(yce[i]*cs_pca[i+1])-(yce[i+1]*cs_pca[i]) for i in range(len(yce[:-1]))])/2.0 + if p_pca == 0: + p_pcay = 0 + else: + p_pcay = sum([(yce[i]+yce[i+1])*((yce[i]*cs_pca[i+1])-(yce[i+1]*cs_pca[i])) for i in range(len(yce[:-1]))])/(6*p_pca) + + # note the y values are from the top of the beam down + # convert them back to there normal coordinate + p_collinsy = h-p_collinsy + p_desayiy = h-p_desayiy + p_pcay = h-p_pcay + + collins_momentarm = p_collinsy - yc + desayi_momentarm = p_desayiy - yc + pca_momentarm = p_pcay - yc + + # because the shape is square the surface slice for both Collins and Desayi + # describe the volume for the full width so the total force is the area of the + # surface slice times the width of the colmn **note units used so far + C_collins = p_collins*b + C_desayi = p_desayi*b + C_pca = p_pca*b + + + # since the whitney block is rectangular all we need is beta1 value + # and the peak stress + cs_whitney = stress_strain_whitney(fc,eu,eu) + + # the whitney block applies 0.85F'c over beta1*c + if cs_whitney[1]*na < h: + C_whitney = cs_whitney[0]*cs_whitney[1]*na*b + whitneyy = cs_whitney[1]*(na) / 2.0 + else: + C_whitney = cs_whitney[0]*h*b + whitneyy = (h) / 2 + + whitneyy = h - whitneyy + whitney_momentarm = whitneyy - yc + + #Sum Forces + P_bars = sum(bforce) + p_bars_neg = [sum(bforce_collins),sum(bforce_desayi),sum(bforce_whitney),sum(bforce_pca)] + + Axial_collins = P_bars + C_collins - p_bars_neg[0] + Axial_desayi = P_bars + C_desayi - p_bars_neg[1] + + Axial_whitney = P_bars + C_whitney - p_bars_neg[2] + + Axial_pca = P_bars + C_pca - p_bars_neg[3] + + # Concrete Moments + M_collins = C_collins*collins_momentarm + M_desayi = C_desayi*desayi_momentarm + M_whitney = C_whitney*whitney_momentarm + M_pca = C_pca*pca_momentarm + + m_bars_collins = sum(bmoment_collins) + m_bars_desayi = sum(bmoment_desayi) + m_bars_whitney = sum(bmoment_whitney) + m_bars_pca = sum(bmoment_pca) + + m_bars_neg = [sum(bnegmoment_collins), sum(bnegmoment_desayi), sum(bnegmoment_whitney), sum(bnegmoment_pca)] + + Mx_collins = m_bars_collins + M_collins - m_bars_neg[0] + Mx_desayi = m_bars_desayi + M_desayi - m_bars_neg[1] + Mx_whitney = m_bars_whitney + M_whitney - m_bars_neg[2] + Mx_pca = m_bars_pca + M_pca - m_bars_neg[3] + + # Moments from Eccentricy of Axial applied at geometric center to + # plastic center + Mx_collins += Axial_collins * (yc-yc_collins) + Mx_desayi += Axial_desayi * (yc-yc_desayi) + Mx_whitney += Axial_whitney * (yc-yc_whitney) + Mx_pca += Axial_pca *(yc-yc_pca) + + # Determine the centroid of the eccentricity of the axial load + e_collins = Mx_collins / Axial_collins + e_desayi = Mx_desayi / Axial_desayi + e_whitney = Mx_whitney / Axial_whitney + e_pca = Mx_pca / Axial_pca + + e_checks.append([e_collins,e_desayi,e_whitney,e_pca]) + + P_collins_plot.append(Axial_collins/1000.0) + M_collins_plot.append(Mx_collins/(1000*12.0)) + P_desayi_plot.append(Axial_desayi/1000.0) + M_desayi_plot.append(Mx_desayi/(1000*12.0)) + P_whitney_plot.append(Axial_whitney/1000) + M_whitney_plot.append(Mx_whitney/(1000*12.0)) + P_pca_plot.append(Axial_pca/1000) + M_pca_plot.append(Mx_pca/(1000*12.0)) + + +plt.close('all') + +ax5 = plt.subplot2grid((2, 2), (0, 0), rowspan=2) +ax1 = plt.subplot2grid((2, 2), (0, 1)) +ax2 = plt.subplot2grid((2, 2), (1, 1)) +ax5.plot(M_collins_plot,P_collins_plot,'r--') +ax5.plot([i*j for i,j in zip(M_collins_plot,aci_reduction)],[i*j if i= self.edge_x_in and self.edge_x_in > 0: + self.punch_col_x.append(self.edge_x_in) + else: + self.punch_col_x.append(base_offset) + + for y in self.y: + if y<0: + base_offset = y-offset_column + if base_offset <= self.edge_y_in and self.edge_y_in < 0: + self.punch_col_y.append(self.edge_y_in) + else: + self.punch_col_y.append(base_offset) + else: + base_offset = y+offset_column + if base_offset >= self.edge_y_in and self.edge_y_in > 0: + self.punch_col_y.append(self.edge_y_in) + else: + self.punch_col_y.append(base_offset) + + punch_segments_raw=segments_from_xy(self.punch_col_x, self.punch_col_y) + for segment in punch_segments_raw: + if segment[0][0] == self.edge_x_in and segment[1][0] == self.edge_x_in: + pass + elif segment[0][1] == self.edge_y_in and segment[1][1] == self.edge_y_in: + pass + else: + self.punch_segments.append(segment) + + self.d_segments.append([self.d_in]*(len(self.punch_segments))) + + self.punch_perimeters_calculated = True + + def determine_punching_properties(self): + + self.punch_properties = [] + + d = self.d_segments[0] + segments = self.punch_segments + + self.punch_properties.append(Punch_Perimeter(segments,d)) + + self.punch_properties_calculated = True + + def process_load(self,Vu_kips,Mscx_ftkips,Mscy_ftkips, area_load_in_perimeter=0): + ''' + Parameters + ---------- + Vu_kips : float + Factored Vertical shear, + = up. + Mscx_ftkips : float + Factored slab moment that is resisted by the column at a joint + about the column centroid x-axis. + + = right hand rule thumb pointing left + Mscy_ftkips : float + Factored slab moment that is resisted by the column at a joint + about the column centroid y-axis. + + = right hand rule thumb pointing down + + Returns + ------- + vc_ksi = [[]]. + a list of lists of shear stress values at the vertices of + each punch perimeter + + ''' + + self.vc_ksi_out = [] + + for perimeter in self.punch_properties: + + # Determine additional moment from shear + # eccentricity to punch centroid + if perimeter.center == [0.0,0.0]: + mxv_inkips = 0 + myv_inkips = 0 + + else: + # Vu up produces proper signed Mx moment at the signed distance + # to the punch centroid + mxv_inkips = Vu_kips*perimeter.center[1] + + # Vu up requires the opposite signed x distance + # to the punch centroid for My + myv_inkips = Vu_kips*-1*perimeter.center[0] + + mx_inkips = (mxv_inkips + (12*Mscx_ftkips))*perimeter.gamma_vx + my_inkips = (myv_inkips + (12*Mscy_ftkips))*perimeter.gamma_vy + + # Determine direct shear stress, vug + # vug = Vu/Ac + vug_ksi = Vu_kips/perimeter.ac + + # Align moments to punch principal axis + alpha = perimeter.alpha + s = math.sin(alpha) + c = math.cos(alpha) + mxp_inkips = mx_inkips*c+my_inkips*s + myp_inkips = -1*mx_inkips*s+my_inkips*c + + jcxp = perimeter.jcxp + jcyp = perimeter.jcyp + + # determine jcxp/y for each vertice, anlagous to s = I/y + y = [j[0][1] for j in perimeter.segments] + y.append(perimeter.segments[-1][1][1]) + + jcxp_y = [jcxp/j for j in y] + + # determine jcyp/x for each vertice, anlagous to s = I/x + x = [j[0][0] for j in perimeter.segments] + x.append(perimeter.segments[-1][1][0]) + jcyp_x = [jcyp/j for j in x] + + # determine vertice stresses + vc_ksi = [vug_ksi-(mxp_inkips/i)+(myp_inkips/j) for i,j in zip(jcxp_y,jcyp_x)] + + self.vc_ksi_out.append(vc_ksi) + + return self.vc_ksi_out + +## TESTING ## +InteriorCalc = Corner_Rectangular_Column(24, 18, 12.875, 14, 12, -9) + +InteriorCalc.determine_punching_perimeters() +InteriorCalc.determine_punching_properties() + +test = InteriorCalc.punch_segments +props = InteriorCalc.punch_properties + +vc = InteriorCalc.process_load(24.71,125.6,26.66) + +plt.plot(InteriorCalc.x,InteriorCalc.y,'k') +for segment in InteriorCalc.punch_segments: + x1 = segment[0][0] + y1 = segment[0][1] + x2 = segment[1][0] + y2 = segment[1][1] + plt.plot([x1,x2],[y1,y2],'k--') +plt.show() diff --git a/LICENSE b/LICENSE index 23cb790..99cde70 100644 --- a/LICENSE +++ b/LICENSE @@ -1,339 +1,29 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {description} - Copyright (C) {year} {fullname} - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - {signature of Ty Coon}, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. +BSD 3-Clause License + +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index 9540ccc..be47cf3 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,17 @@ Everything was developed using a standard install of the 2.7.10 version of Pytho This is a collection of various scripts I have been and continue to work on for various day to day calculations. I intend to keep the scripts organized by design topic ie the folder structure presented. The intent is for the scripts to cover simple one off calculations so don't plan on any full building modeling programs. When things develope beyond simple scripts I'll create additional repositories that fit a better organizational structure. +## Frame_2D_GUI.py or Frame_2D_GUI_metric.py +Tkinter GUI based Python Program +Requires the analysis folder and contained py files + +Currently and alpha level program. Load combinations have not been implemented in the back end but do show up in the graphical interface, so all loads input will be currently applied with a load factor of 1. + +Backend solver utilizes moment distribution. By default only the columns down provide vertical suppot and the solver performs a 2-pass moment distribution where after pass 1 the beam reactions are applied to the columns down and the columns are shortened by PL/AE pass 2 determines the fixed end moments created by the column shortening and then performs the distrubtion of those moments. + +In action: +[Frame_2D.gif](images/frame_2d_windows.gif) + ## Strap Beam - strap_beam_gui.py Tkinter GUI based Python Program requires the analysis folder and contained py files and the concrete folder and contained python files. @@ -11,28 +22,30 @@ requires the analysis folder and contained py files and the concrete folder and Currently an alpha level program there are several validation checks not being performed such as number of bars required in the strap actually fitting in the strap, etc. No handling of foundation uplift base assumption of the program is positive bearing. In action: -![Strap Beam gif](images/strap_gif.gif?raw=true "Strap Beam") +[Strap Beam gif](images/strap_gif.gif) ## Concrete T beam - depends on concrete_beam_classes in the same directory +### L and Asymmetric T's give the wrong solution, program does not rotate the neutral axis so the reported capacity has a hidden My component ** Tkinter GUI based Python program. Provides various code defined capacities based on strain compatibility. Currently based on ACI 318-08. Calculates elevation of various steel reinf. layers based on clearance and spacing requirements per ACI 318-08. ## Concrete T Beam Any Steel - depends on concrete_beam_classes in the same directory +### L and Asymmetric T's give the wrong solution, program does not rotate the neutral axis so the reported capacity has a hidden My component ** Tkinter GUI based Python program Provides various code defined capacities based on strain compatibility. Allows for user assigned elevations of steel reinforcement layers. Does not check or provide for min spacing of tension layer bars nor maximum amount of bars that fit in a layer. -## Simple Beam +## Simple Beam - (metric version now available) Tkinter GUI based python program -can solve for shear, moment, slope, and deflection of a simply supported beam with cantilevers at either end. Can apply any combination of point, point moment, uniform line, or trapezoidal loadings. Will automatically generate results curves and has the ability to find values at a specific location. Recently added the ability to solve for redundant interior reactions, simply add the result as a point load to verify deflection returns to 0 at the designated location. Can export an 11x17 pdf plot showing applied loads, reactions, shear, moment, slope, and deflection. +can solve for shear, moment, slope, and deflection of a simply supported beam with cantilevers at either end. Can apply any combination of point, point moment, uniform line, or trapezoidal loadings. Will automatically generate results curves and has the ability to find values at a specific location. Recently added the ability to solve for redundant interior reactions, simply add the result as a point load to verify deflection returns to 0 at the designated location. Can export an html file plot showing reactions, shear, moment, slope, and deflection as well as other useful information such as the central span piecewise functions. Can be used to verify frame or fixed beam FEM results by applying point end moments returned by your 3rd party software, works on basis of superposition. In action: -![Simple Beam gif](images/simple_gif.gif?raw=true "Simple Beam") +[Simple Beam gif](images/simple_gif.gif) ## Three Moment Method ### Reworking to use the pin-pin class file and directly compute slope and deflection rather than rely on approx. integration. Also adding in point moments as a load type. diff --git a/Steel/AISC Shapes Databases/aisc_database_class.py b/Steel/AISC Shapes Databases/aisc_database_class.py index 17934f4..a734b82 100644 --- a/Steel/AISC Shapes Databases/aisc_database_class.py +++ b/Steel/AISC Shapes Databases/aisc_database_class.py @@ -1,22 +1,28 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri May 04 16:09:57 2018 - -@author: DonB -""" -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' diff --git a/Steel/AISC Shapes Databases/aisc_steel_shapes.py b/Steel/AISC Shapes Databases/aisc_steel_shapes.py index 39d4f4e..ec8cded 100644 --- a/Steel/AISC Shapes Databases/aisc_steel_shapes.py +++ b/Steel/AISC Shapes Databases/aisc_steel_shapes.py @@ -1,22 +1,28 @@ -# -*- coding: utf-8 -*- -""" -Created on Wed Apr 26 14:50:25 2017 - -@author: DonB -""" -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' import Tkinter as tk @@ -181,20 +187,20 @@ def __init__(self, master): self.license_display() def license_display(self, *event): - license_string = ("This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n\n" - - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n\n" - - "You should have received a copy of the GNU General Public License along" - "with this program; if not, write to the Free Software Foundation, Inc.," - "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" - "\nA copy of the License can be viewed at:\n https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE") + license_string = ("Copyright (c) 2019, Donald N. Bockoven III\n" + "All rights reserved.\n\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" + " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" + " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" + " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" + " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" + " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" + " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," + " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" + "https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE" + ) tkMessageBox.showerror("License Information",license_string) self.master.focus_force() diff --git a/Steel/AISC Shapes Databases/aisc_steel_shapes.zip b/Steel/AISC Shapes Databases/aisc_steel_shapes.zip deleted file mode 100644 index f711e1e..0000000 Binary files a/Steel/AISC Shapes Databases/aisc_steel_shapes.zip and /dev/null differ diff --git a/Steel/AISC Shapes Databases/aisc_steel_shapes_historic.py b/Steel/AISC Shapes Databases/aisc_steel_shapes_historic.py index 1d4ab84..83a6542 100644 --- a/Steel/AISC Shapes Databases/aisc_steel_shapes_historic.py +++ b/Steel/AISC Shapes Databases/aisc_steel_shapes_historic.py @@ -1,23 +1,28 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu Apr 27 14:28:17 2017 - -@author: DonB -""" - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' import Tkinter as tk import tkFont @@ -224,20 +229,20 @@ def __init__(self, master): self.license_display() def license_display(self, *event): - license_string = ("This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n\n" - - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n\n" - - "You should have received a copy of the GNU General Public License along" - "with this program; if not, write to the Free Software Foundation, Inc.," - "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" - "\nA copy of the License can be viewed at:\n https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE") + license_string = ("Copyright (c) 2019, Donald N. Bockoven III\n" + "All rights reserved.\n\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" + " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" + " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" + " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" + " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" + " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" + " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," + " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" + "https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE" + ) tkMessageBox.showerror("License Information",license_string) self.master.focus_force() diff --git a/Steel/AISC Shapes Databases/aisc_steel_shapes_historic.zip b/Steel/AISC Shapes Databases/aisc_steel_shapes_historic.zip deleted file mode 100644 index eb5706e..0000000 Binary files a/Steel/AISC Shapes Databases/aisc_steel_shapes_historic.zip and /dev/null differ diff --git a/Steel/AISC Shapes Databases/steel_calculator.py b/Steel/AISC Shapes Databases/steel_calculator.py index 5f2fa84..5f279b0 100644 --- a/Steel/AISC Shapes Databases/steel_calculator.py +++ b/Steel/AISC Shapes Databases/steel_calculator.py @@ -1,22 +1,28 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri May 04 14:06:27 2018 - -@author: DonB -""" -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import math @@ -191,20 +197,20 @@ def __init__(self, master): self.license_display() def license_display(self, *event): - license_string = ("This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n\n" - - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n\n" - - "You should have received a copy of the GNU General Public License along" - "with this program; if not, write to the Free Software Foundation, Inc.," - "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" - "\nA copy of the License can be viewed at:\n https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE") + license_string = ("Copyright (c) 2019, Donald N. Bockoven III\n" + "All rights reserved.\n\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" + " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" + " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" + " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" + " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" + " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" + " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," + " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" + "https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE" + ) tkMessageBox.showerror("License Information",license_string) self.master.focus_force() @@ -362,7 +368,7 @@ def shape_calcs(self, *args): flexure_string = flexure_string + 'h/tw = {0}\n'.format(W[35]) shear_string = shear_string + 'h/tw = {0}\n'.format(W[35]) Iy = float(W[42]) - flexure_string = flexure_string + 'Iy = {0}\n'.format(W[35]) + flexure_string = flexure_string + 'Iy = {0}\n'.format(W[42]) zy = float(W[43]) flexure_weak_string = flexure_weak_string + '{1}\nZy = {0}\n'.format(W[43], shape) diff --git a/Steel/bolt_group_istantaneous_center.py b/Steel/bolt_group_istantaneous_center.py index c18b774..7a2d61b 100644 --- a/Steel/bolt_group_istantaneous_center.py +++ b/Steel/bolt_group_istantaneous_center.py @@ -1,23 +1,28 @@ -# -*- coding: utf-8 -*- -""" -Created on Tue Dec 04 11:50:08 2018 - -@author: DonB -""" - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import math as m diff --git a/Steel/bolts_IC_gui.py b/Steel/bolts_IC_gui.py index aaceab4..7fe3b91 100644 --- a/Steel/bolts_IC_gui.py +++ b/Steel/bolts_IC_gui.py @@ -1,18 +1,28 @@ -# -*- coding: utf-8 -*- - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import math as m @@ -299,20 +309,20 @@ def __init__(self, master): def license_display(self, *event): # Function to display license dialog on app start - license_string = ("This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n\n" - - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n\n" - - "You should have received a copy of the GNU General Public License along" - "with this program; if not, write to the Free Software Foundation, Inc.," - "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" - "\nA copy of the License can be viewed at:\n https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE") + license_string = ("Copyright (c) 2019, Donald N. Bockoven III\n" + "All rights reserved.\n\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" + " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" + " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" + " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" + " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" + " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" + " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," + " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" + "https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE" + ) tkMessageBox.showerror("License Information",license_string) self.master.focus_force() @@ -677,7 +687,10 @@ def draw_c_stability(self, *events): vals = self.detailed_out[17][1] - norm_vals = [(float(i)-min(vals))/(max(vals)-min(vals)) for i in vals] + if max(vals)-min(vals) == 0: + norm_vals = [(float(i))/(max(vals)) for i in vals] + else: + norm_vals = [(float(i)-min(vals))/(max(vals)-min(vals)) for i in vals] count = len(vals) diff --git a/Steel/welds_elastic_method.py b/Steel/welds_elastic_method.py index 2285ecb..bd3b9ba 100644 --- a/Steel/welds_elastic_method.py +++ b/Steel/welds_elastic_method.py @@ -1,18 +1,28 @@ -# -*- coding: utf-8 -*- - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import math diff --git a/Steel/welds_gui.py b/Steel/welds_gui.py index 739e0bf..d9f5f77 100644 --- a/Steel/welds_gui.py +++ b/Steel/welds_gui.py @@ -1,25 +1,28 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu Jul 26 17:43:52 2018 - -@author: DonB -""" - -# -*- coding: utf-8 -*- - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import math @@ -89,19 +92,20 @@ def __init__(self, master): self.tab_license = ttk.Frame(self.nb_inputs) self.nb_inputs.add(self.tab_license , text='License') - license_string = ("This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n\n" - - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n\n" - - "You should have received a copy of the GNU General Public License along\n" - "with this program; if not, write to the Free Software Foundation, Inc.,\n" - "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA") + license_string = ("Copyright (c) 2019, Donald N. Bockoven III\n" + "All rights reserved.\n\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" + " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" + " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" + " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" + " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" + " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" + " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," + " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" + "https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE" + ) tk.Label(self.tab_license, text=license_string,font=self.f_type, justify=tk.LEFT).grid(row=0, column=0) diff --git a/Steel/welds_gui.zip b/Steel/welds_gui.zip deleted file mode 100644 index 322f3e7..0000000 Binary files a/Steel/welds_gui.zip and /dev/null differ diff --git a/Wood/e_test.py b/Wood/e_test.py new file mode 100644 index 0000000..5574851 --- /dev/null +++ b/Wood/e_test.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +""" +Created on Fri Jul 26 18:39:51 2019 + +@author: DonB +""" + +from __future__ import division +import wood_classes as wood +import matplotlib.pyplot as plt + +wall = wood.wood_stud_wall(1.5,5.5,10,12,"No. 2",875,150,1150,1400000,510000,565,19,90,0,0, [1,1,1,1,1,1], 0, 48, 0, 0) + +max_e = (5.5/6.0) +step_e = max_e/10.0 + +ecc = [0+(i*step_e) for i in range(11)] + +ecc.extend([1,1.5,2,2.5,3,3.5,4]) + + + +fig, ax1 = plt.subplots() +fig.set_size_inches(17, 11) +ax1.minorticks_on() +ax1.grid(b=True, which='major', color='k', linestyle='-', alpha=0.3) +ax1.grid(b=True, which='minor', color='g', linestyle='-', alpha=0.1) +ax2 = ax1.twinx() +for x in ecc: + w,p,d = wall.wall_pm_diagram_cd_stud(1,x) + if x == max_e: + ax1.plot(w,p, color='r') + ax2.plot(w,d, color='r') + else: + ax1.plot(w,p, color='k') + ax2.plot(w,d, color='k', alpha=0.4) + +ax1.set_ylabel('Axial (lbs)') +ax1.set_xlabel('Moment (in-lbs)') +ax2.set_ylabel('Mid Height Deflection (in)') + +plt.title('2x6 SPF No.2 - 10 ft tall - 12" spacing - variable ecc') +fig.tight_layout() + +plt.savefig('wall_e_test.jpg', dpi=100) + +plt.show() + diff --git a/Wood/ftao.py b/Wood/ftao.py new file mode 100644 index 0000000..cc4c634 --- /dev/null +++ b/Wood/ftao.py @@ -0,0 +1,670 @@ +import math +import os + +def wsp_nail_slip_en(nail, vn, moisture_content, structural1=True): + # SDPWS 2021 Table C4.2.3D + if nail == "6d": + if moisture_content > 19: + en = math.pow(vn / 434, 2.314) + else: + en = math.pow(vn / 456, 3.144) + elif nail == "8d": + if moisture_content > 19: + en = math.pow(vn / 857, 1.869) + else: + en = math.pow(vn / 616, 3.018) + elif nail == "10d": + if moisture_content > 19: + en = math.pow(vn / 977, 1.894) + else: + en = math.pow(vn / 769, 3.276) + else: + en = 10 + + if not structural1: + # SDPWS 2021 Table C4.2.3D - Footnote 1 + # The slip shall be increased by 20 percent when plywood or OSB is not Structural I. + en = 1.20 * en + + return en + + +def four_term_deflection( + V_plf, H_ft, E_psi, A_sqin, b_ft, Gt_lbpin, en_in, holddown_data, additional_end_chord_force_lbs=0 +): + + # Term 1 Bending Deflection - 8 v h^3 / E A b + delta_bending_in = (8 * V_plf * H_ft * H_ft * H_ft) / (E_psi * A_sqin * b_ft) + + # Term 2 - Shear Deflection - v h / Gt + delta_shear_in = (V_plf * H_ft) / Gt_lbpin + + # Term 3 - Fastener Slip - 0.75 h en + delta_fastener_in = 0.75 * H_ft * en_in + + # Term 4 - Hold-Down Deformation - da h/b + da = (holddown_data[1] * ((V_plf * H_ft)+additional_end_chord_force_lbs))/ holddown_data[0] + delta_holddown_in = da * (H_ft / b_ft) + + delta_in = delta_bending_in + delta_shear_in + delta_fastener_in + delta_holddown_in + + return { + "delta": delta_in, + "delta_bending": delta_bending_in, + "delta_shear": delta_shear_in, + "delta_fastener": delta_fastener_in, + "delta_holddown": delta_holddown_in, + } + + +if __name__ == "__main__": + # FTAO Panel Anaysis following APA T555 + errors = [] + warnings = [] + tick_count = 100 + + #### BEGIN INPUTS #### + ###################### + + ''' + ## APA T555 Inputs ## + + V_lbs = 3750 # Shear for force analysis + Vdelta_lbs = 5357 # Shear for Deformation Analysis + Hwall_ft = 8 # Total height of Wall Panel + endchord_above_lbs = 0 # Chord Force from Wall Panel Above Current Panel + + hb_ft = 4 # Sill Height of Openings + ho_ft = 2.67 # Height of Openings + + piers = [4,4,3.5] # List of Pier Widths + openings = [6,2] # List of Opening Widths + + Cd = 4.0 + E_psi = 1600000 # Elastic Modulus of the end posts + A_sqin = 16.5 # Area of the end posts + Gt_lbpin = 83500 # Shear Stiffness through the depth of the sheathing + nail = "8d" # nail size as a string 6d, 8d, or 10d no others supported. + nail_spacing_in = 4 # nail spacing + moisture_content = 19 # moisture content of lumber used for nail slip calc, typically 19 or less + hdcapacity_lbs = 2145 # Hold Down Capacity as provided by the manufacturer + hddelta_in = 0.128 # Hold Down Deformation at capacity as provided by the manufacturer + holddown_data = [hdcapacity_lbs, hddelta_in] # Hold Down Data as List for input into deformation function + Structural1 = False + + ## END APA T555 Inputs ## + ''' + # Inputs For Analysis + V_lbs = 4117.2 # Shear for force analysis + Vdelta_lbs = 4117.2 # Shear for Deformation Analysis + Hwall_ft = 10.67 # Total height of Wall Panel + endchord_above_lbs = 1155 # Chord Force from Wall Panel Above Current Panel + + hb_ft = 1.33 # Sill Height of Openings + ho_ft = 6.32 # Height of Openings + + piers = [5,7.33,5.02] # List of Pier Widths + openings = [7.33,7.33] # List of Opening Widths + + # Inputs for Deflection + Cd = 1.0 + E_psi = 1400000 # Elastic Modulus of the end posts + A_sqin = 16.5 # Area of the end posts + Gt_lbpin = 83500 # Shear Stiffness through the depth of the sheathing + nail = "8d" # nail size as a string 6d, 8d, or 10d no others supported. + nail_spacing_in = 6 # nail spacing + moisture_content = 19 # moisture content of lumber used for nail slip calc, typically 19 or less + hdcapacity_lbs = 3285 # Hold Down Capacity as provided by the manufacturer + hddelta_in = 0.114 # Hold Down Deformation at capacity as provided by the manufacturer + holddown_data = [hdcapacity_lbs, hddelta_in] # Hold Down Data as List for input into deformation function + Structural1 = True + + #### END INPUTS #### + ###################### + + if len(piers) != len(openings) + 1: + errors.append( + f"Pier count not consistent with openings, # piers should be {len(openings)+1} but is {len(piers)}" + ) + + if hb_ft <= 0 : + errors.append(f"Sill height, hb, of {hb_ft} ft must be greater than 0") + if hb_ft+ho_ft >= Hwall_ft-0.5: + errors.append(f"Opening too large") + + # Basic computed values + ha_ft = Hwall_ft - hb_ft - ho_ft # height above opening + Lwall_ft = sum(piers) + sum(openings) # total wall length + basic_unit_shear_plf = V_lbs / Lwall_ft # basic unit shear V/L + + print("-" * tick_count) + print("Inputs and Geometry:") + print(f"Applied Shear, V: {V_lbs:.3f} lbs") + print(f"Applied Shear For Deflection, Vdelta: {Vdelta_lbs:.3f} lbs") + print(f"Chord Force from Above, Habove = {endchord_above_lbs:.3f} lbs") + print(f"Wall Panel Height, Hw: {Hwall_ft:.3f} ft") + print(f"Opening Sill Height, Hb: {hb_ft:.3f} ft") + print(f"Opening Height, Ho: {ho_ft:.3f} ft") + print(f"Height above Opening, Ha: {ha_ft:.3f} ft") + print("Piers:") + for i, j in enumerate(piers): + print(f"Lp{i+1} length: {j:.3f} ft") + + print("Openings:") + for i, j in enumerate(openings): + print(f"Lo{i+1} width: {j:.3f} ft") + print(f"Total Wall Panel Length, L: {Lwall_ft:.3f} ft") + + # Compute aspect ratios + # min pier of 2 ft required + pier_ar = [ho_ft / i for i in piers] + + for i, j in enumerate(pier_ar): + if piers[i] < 2.0: + errors.append(f"Pier {i+1} length < 2.0 ft") + if j > 3.5: + errors.append(f"pier {i+1} aspect ratio of {j} exceeds 3.5:1 maximum.") + + print("-" * tick_count) + print("Pier Aspect Ratios Ho/Lpi:") + for i, j in enumerate(pier_ar): + print(f"P{i+1} aspect ratio = {j:.3f}") + + # Compute pier adjustment factors + # Method 1 = 2 bs/h + method1_af = [ + 2 * j * (1 / ho_ft) if pier_ar[i] > 2 else 1 for i, j in enumerate(piers) + ] + # Method 2 = 1.25 - (0.125 h/bs) + method2_af = [ + 1.25 - (0.125 * (ho_ft / j)) if pier_ar[i] > 2 else 1 + for i, j in enumerate(piers) + ] + + print("-" * tick_count) + print("Pier Adjustment Factors - Method 1 2*Lpi/ho:") + for i, j in enumerate(method1_af): + print(f"P{i+1} method 1 adjustment = {j:.3f}") + + print("Pier Adjustment Factors - Method 2 1.25 - (0.125*ho/Lpi):") + for i, j in enumerate(method2_af): + print(f"P{i+1} method 2 adjustment = {j:.3f}") + + # If no errors continue into the analysis otherwise print the errors + if not errors: + # Compute the Hold Down Force V*H/L + hd_force_lbs = ((V_lbs * Hwall_ft) + (endchord_above_lbs * Lwall_ft)) * ( + 1 / Lwall_ft + ) + print("-" * tick_count) + print(f"Hold Down Force, H: {hd_force_lbs:.3f} lbs") + # Compute vertical unit shears @ section cuts of each window + # assumes unit shear is equivalent in the top and bottom section + # and via statics Sum of Unit shears = hold down force - end chord above force + opening_shears_plf = [ + (hd_force_lbs - endchord_above_lbs) / (ha_ft + hb_ft) for i in openings + ] + + print("-" * tick_count) + print("Opening Unit Shears:") + for i, j in enumerate(opening_shears_plf): + print(f"va{i+1} = vb{i+1} = (H - Habove) / Ha+Hb = {j:.3f} plf") + + # Compute opening boundary forces = opening unit shear * opening width + opening_boundary_force_lbs = [ + opening_shears_plf[i] * j for i, j in enumerate(openings) + ] + + print("-" * tick_count) + print("Opening Boundary Forces above and below opening:") + for i, j in enumerate(opening_boundary_force_lbs): + print(f"O{i+1} = va{i+1}*Lo{i+1} = {j:.3f} lbs") + + # Compute opening corner forces and Tributary Lengths + corner_forces_lbs = [] + opening_tributaries_ft = [] + for i, j in enumerate(openings): + left = piers[i] + right = piers[i + 1] + + fleft = opening_boundary_force_lbs[i] * left * (1 / (left + right)) + fright = opening_boundary_force_lbs[i] * right * (1 / (left + right)) + + corner_forces_lbs.append([fleft, fright]) + + Tleft = j * left * (1 / (left + right)) + Tright = j * right * (1 / (left + right)) + + opening_tributaries_ft.append([Tleft, Tright]) + + print("-" * tick_count) + print("Corner Forces:") + for i, j in enumerate(corner_forces_lbs): + print(f"FO{i+1},left = O{i+1}*L{i+1} / (L{i+1}+L{i+2}) = {j[0]:.3f} lbs") + print(f"FO{i+1},right = O{i+1}*L{i+2} / (L{i+1}+L{i+2}) = {j[1]:.3f} lbs") + + print("-" * tick_count) + print("Opening Tributaries:") + for i, j in enumerate(opening_tributaries_ft): + print(f"T{i+1},left = Lo{i+1}*L{i+1} / (L{i+1}+L{i+2}) = {j[0]:.3f} ft") + print(f"T{i+1},right = Lo{i+1}*L{i+2} / (L{i+1}+L{i+2}) = {j[1]:.3f} ft") + + # Compute pier unit shears adjacent to the openings + pier_shears_plf = [] + for i, j in enumerate(piers): + + # (V/L * (pier length + sum of tributaries))/pier length + effective_length_ft = j + if i == 0: + # first pier only one tributary from left of first opening + effective_length_ft += opening_tributaries_ft[i][0] + elif i == len(piers) - 1: + # last pier only one tributary from right of last opening + effective_length_ft += opening_tributaries_ft[i - 1][1] + else: + # inteiror pier tributaries from right of left opening and left of right opening + effective_length_ft += opening_tributaries_ft[i][0] + effective_length_ft += opening_tributaries_ft[i - 1][1] + + unit_shear_plf = (basic_unit_shear_plf * effective_length_ft) / j + + pier_shears_plf.append(unit_shear_plf) + + print("-" * tick_count) + print("Unit Shear in Pier adjacent to Opening:") + for i, j in enumerate(pier_shears_plf): + print(f"v{i+1} = {j:.3f} plf") + + # Check unit shears equal the applied load + check_pier_shear_lbs = sum( + [j * pier_shears_plf[i] for i, j in enumerate(piers)] + ) + print(f"check that pier shears match applied load:") + print(f"Sum of Pier Shears = {check_pier_shear_lbs:.3f} lbs") + print(f"V = {V_lbs:.3f} lbs") + print(f"Validated: {math.isclose(check_pier_shear_lbs,V_lbs)}") + + if not math.isclose(check_pier_shear_lbs, V_lbs): + errors.append( + f"Sum of Pier Shears, {check_pier_shear_lbs:.3f} lbs does not match applied load {V_lbs:.3f} lbs" + ) + + # Resistance to Corner Forces + resisting_forces_lbs = [j * pier_shears_plf[i] for i, j in enumerate(piers)] + + print("-" * tick_count) + print("Pier Force Resisting Corner Forces:") + for i, j in enumerate(resisting_forces_lbs): + print(f"R{i+1} = {j:.3f} lbs") + + # Delta of force at corners and Corner Zone Unit Shears + corner_force_delta_lbs = [] + corner_unit_shears_plf = [] + + for i, j in enumerate(piers): + + force_lbs = resisting_forces_lbs[i] + + if i == 0: + # first pier only one force from left of first opening + force_lbs -= corner_forces_lbs[i][0] + elif i == len(piers) - 1: + # last pier only one force from right of last opening + force_lbs -= corner_forces_lbs[i - 1][1] + else: + # inteiror pier forces from right of left opening and left of right opening + force_lbs -= corner_forces_lbs[i][0] + force_lbs -= corner_forces_lbs[i - 1][1] + + corner_force_delta_lbs.append(force_lbs) + corner_unit_shears_plf.append(force_lbs / j) + + print("-" * tick_count) + print("Difference in Corner Force:") + for i, j in enumerate(corner_force_delta_lbs): + print(f"Fc{i+1} = {j:.3f} lbs") + print("-" * tick_count) + print("Pier Corner Unit Shears:") + for i, j in enumerate(corner_unit_shears_plf): + print(f"vc{i+1} = {j:.3f} plf") + + # Check Vertical Shear at each end of piers + check_vertical_shears_lbs = [] + for i, j in enumerate(piers): + fleft = 0 + fright = 0 + if i == 0: + fleft += corner_unit_shears_plf[i] * (ha_ft + hb_ft) + fleft += pier_shears_plf[i] * ho_ft + fleft += endchord_above_lbs + + fright += opening_shears_plf[i] * (ha_ft + hb_ft) + fright -= corner_unit_shears_plf[i] * (ha_ft + hb_ft) + fright -= pier_shears_plf[i] * (ho_ft) + + elif i == len(piers) - 1: + fright += corner_unit_shears_plf[i] * (ha_ft + hb_ft) + fright += pier_shears_plf[i] * ho_ft + fright += endchord_above_lbs + + fleft += opening_shears_plf[i - 1] * (ha_ft + hb_ft) + fleft -= corner_unit_shears_plf[i] * (ha_ft + hb_ft) + fleft -= pier_shears_plf[i] * (ho_ft) + + else: + fleft += corner_unit_shears_plf[i] * (ha_ft + hb_ft) + fleft += pier_shears_plf[i] * ho_ft + fleft -= opening_shears_plf[i - 1] * (ha_ft + hb_ft) + + fright += opening_shears_plf[i] * (ha_ft + hb_ft) + fright -= corner_unit_shears_plf[i] * (ha_ft + hb_ft) + fright -= pier_shears_plf[i] * (ho_ft) + + check_vertical_shears_lbs.extend([fleft, fright]) + + print("-" * tick_count) + print("Check of Vertical Shear Lines") + for i, j in enumerate(check_vertical_shears_lbs): + if i != 0 and j != check_vertical_shears_lbs[-1]: + print(f"Line {i} sums to {j:.3f} lbs = 0 lbs: {math.isclose(j+1, 1)}") + if not math.isclose(j + 1, 1): + errors.append( + f"Check of Vertical Shear Line {i} Failes, Line {i} sums to {j:.3f} lbs but should be 0 lbs" + ) + else: + print( + f"Line {i} sums to {j:.3f} lbs = hold down force of {hd_force_lbs:.3f} lbs: {math.isclose(j, hd_force_lbs)}" + ) + + if not math.isclose(j, hd_force_lbs): + errors.append( + f"Check of Vertical Shear Line {i} Failed, Line {i} sums to {j:.3f} lbs but should be hold down force of {hd_force_lbs:.3f} lbs" + ) + + # Required shear capacity + unadjusted_required_unit_shear_plf = max( + max(opening_shears_plf), + max([abs(i) for i in corner_unit_shears_plf]), + max([i for i in pier_shears_plf]), + ) + + method1_required_unit_shear_plf = max( + max(opening_shears_plf), + max([abs(i) for i in corner_unit_shears_plf]), + max([j / method1_af[i] for i, j in enumerate(pier_shears_plf)]), + ) + + method2_required_unit_shear_plf = max( + max(opening_shears_plf), + max([abs(i) for i in corner_unit_shears_plf]), + max([j / method2_af[i] for i, j in enumerate(pier_shears_plf)]), + ) + + print("-" * tick_count) + print( + f"Required Sheathing Capacity with no adjustment: {unadjusted_required_unit_shear_plf:.3f} plf" + ) + print( + f"Required Sheathing Capacity for Method 1 Adjustment: {method1_required_unit_shear_plf:.3f} plf" + ) + print( + f"Required Sheathing Capacity for Method 2 Adjustment: {method2_required_unit_shear_plf:.3f} plf" + ) + + # Required Strap Force + required_strap_force_lbs = max( + max([i[0] for i in corner_forces_lbs]), + max([i[1] for i in corner_forces_lbs]), + ) + print(f"Required Strap Force: {required_strap_force_lbs:.3f} lbs") + + print(f"Required Hold Down Force: {hd_force_lbs:.3f} lbs") + print(f"Required Wall Anchorage Unit Shear: {basic_unit_shear_plf:.3f} plf") + + # 4 Term Deflection + print("-" * tick_count) + print("4-Term Deflection Analysis: ") + + pier_deflections_four_term = [] + + unit_shear_delta_plf = Vdelta_lbs / Lwall_ft + + # Effective Height of Piers away from end is the height + # above the window sill. The bottom panel assumed to act rigidly + # up to the end pier. + heff_ft = Hwall_ft - hb_ft + + # Deflection to the Right + for i, j in enumerate(piers): + + if i == 0: + Leff = j + opening_tributaries_ft[i][0] + hd_add = endchord_above_lbs + elif i == len(piers) - 1: + Leff = j + opening_tributaries_ft[i - 1][1] + heff_ft += hb_ft # For load from left last pier should be full height + hd_add = 0 + else: + Leff = ( + j + opening_tributaries_ft[i][0] + opening_tributaries_ft[i - 1][1] + ) + hd_add = 0 + + Leff = Leff / j + v_pier = unit_shear_delta_plf * Leff + v_nail = (nail_spacing_in / 12) * v_pier + en_in = wsp_nail_slip_en(nail, v_nail, moisture_content, Structural1) + delta = four_term_deflection( + v_pier, heff_ft, E_psi, A_sqin, j, Gt_lbpin, en_in, holddown_data, hd_add + ) + + pier_deflections_four_term.append(delta.get("delta")) + + print("-" * tick_count) + print(f"Pier{i+1} Right Deflection Contribution:") + print(f"v,pier{i+1} = {v_pier:.3f} plf") + print(f"H,eff{i+1} = {heff_ft:.3f} ft") + print(f"v,nail{i+1} = {v_nail:.3f} plf") + print(f"en{i+1} = {en_in:.3f} in") + print(f"delta - bending term = {delta.get('delta_bending'):.3f} in") + print(f"delta - shear term = {delta.get('delta_shear'):.3f} in") + print(f"delta - nail slip term = {delta.get('delta_fastener'):.3f} in") + print(f"delta - hold down term = {delta.get('delta_holddown'):.3f} in") + print(f"delta{i+1} = {delta.get('delta'):.3f} in") + + # Reset Heff + # For deflection to the left first pier should be full height + # In the following the loop the first pier will calcute first so + # adjust Heff after the first cycle + heff_ft = Hwall_ft + + # Deflection to the Left + for i, j in enumerate(piers): + + if i == 0: + Leff = j + opening_tributaries_ft[i][0] + hd_add = 0 + elif i == len(piers) - 1: + Leff = j + opening_tributaries_ft[i - 1][1] + hd_add = endchord_above_lbs + else: + if i == 1: + heff_ft -= ( + hb_ft # reduce pier height after first pier but not again + ) + Leff = ( + j + opening_tributaries_ft[i][0] + opening_tributaries_ft[i - 1][1] + ) + hd_add = 0 + + Leff = Leff / j + v_pier = unit_shear_delta_plf * Leff + v_nail = (nail_spacing_in / 12) * v_pier + en_in = wsp_nail_slip_en(nail, v_nail, moisture_content, Structural1) + delta = four_term_deflection( + v_pier, heff_ft, E_psi, A_sqin, j, Gt_lbpin, en_in, holddown_data, hd_add + ) + + pier_deflections_four_term.append(delta.get("delta")) + + print("-" * tick_count) + print(f"Pier{i+1} Left Deflection Contribution:") + print(f"v,pier{i+1} = {v_pier:.3f} plf") + print(f"H,eff{i+1} = {heff_ft:.3f} ft") + print(f"v,nail{i+1} = {v_nail:.3f} plf") + print(f"en{i+1} = {en_in:.3f} in") + print(f"delta - bending term = {delta.get('delta_bending'):.3f} in") + print(f"delta - shear term = {delta.get('delta_shear'):.3f} in") + print(f"delta - nail slip term = {delta.get('delta_fastener'):.3f} in") + print(f"delta - hold down term = {delta.get('delta_holddown'):.3f} in") + print(f"delta{i+1} = {delta.get('delta'):.3f} in") + + percent_drift = (Cd*sum(pier_deflections_four_term)/len(pier_deflections_four_term))/(Hwall_ft*12) + delta_h_over = 1/percent_drift + print("-" * tick_count) + print( + f"Average of 4-Term Deflections = {sum(pier_deflections_four_term)/len(pier_deflections_four_term):.3f} in" + ) + print(f"% Drift = (Cd * Delta) / (Hwall * 12): {percent_drift:.4f} %") + print(f"Drift Ratio = (Hwall * 12) / (Cd * Delta) = H/{delta_h_over:.1f}") + print("*" * tick_count) + + if not errors: + print("***") + print("*** ---- Summary Results ----") + print( + f"*** Required Sheathing Capacity with no adjustment: {unadjusted_required_unit_shear_plf:.3f} plf" + ) + print( + f"*** Required Sheathing Capacity for Method 1 [2*Lpi/ho] Adjustment: {method1_required_unit_shear_plf:.3f} plf" + ) + print( + f"*** Required Sheathing Capacity for Method 2 [1.25 - (0.125*ho/Lpi)] Adjustment: {method2_required_unit_shear_plf:.3f} plf" + ) + print(f"*** Required Strap Force: {required_strap_force_lbs:.3f} lbs") + + print(f"*** Required Hold Down Force: {hd_force_lbs:.3f} lbs") + print( + f"*** Required Wall Anchorage Unit Shear: {basic_unit_shear_plf:.3f} plf" + ) + print( + f"*** Average of 4-Term Deflections = {sum(pier_deflections_four_term)/len(pier_deflections_four_term):.3f} in" + ) + print(f"*** % Drift = (Cd * Delta) / (Hwall * 12): {percent_drift:.4f} %") + print(f"*** Drift Ratio = (Hwall * 12) / (Cd * Delta) = H/{delta_h_over:.1f}") + print("***") + print("*" * tick_count) + + # SVG Generation + svg_x = 1024 + svg_y = 768 + panel_color = "darkkhaki" + svg_string = [f''] + # Transformation matrix for svg to reorient axis and scale to fit + svg_string.append('') + + svg_dx = Lwall_ft + 3 + svg_dy = Hwall_ft + 4 + + scalex = (svg_x - 20)/svg_dx + scaley = (svg_y - 20)/svg_dy + svg_scale = min(scalex,scaley) + + svg_tx = 10 + svg_ty = 10 + (svg_dy*svg_scale) + + tmatrix = f'' + + svg_string.append(tmatrix) + # Applied Load + svg_string.append(f'') + svg_string.append(f' V: {V_lbs:.1f} lbs ') + svg_string.append(f' V,delta: {Vdelta_lbs:.1f} lbs ') + + if endchord_above_lbs != 0: + svg_string.append(f'') + svg_string.append(f' HD,above: {endchord_above_lbs:.1f} lbs ') + svg_string.append(f'') + svg_string.append(f' HD,above: {endchord_above_lbs:.1f} lbs ') + + svg_string.append(f'') + svg_string.append(f' HD: {hd_force_lbs:.1f} lbs ') + svg_string.append(f'') + svg_string.append(f' HD: {hd_force_lbs:.1f} lbs ') + + svg_string.append(f'') + svg_string.append(f' Required Wall Anchorage Unit Shear: {basic_unit_shear_plf:.3f} plf ') + svg_string.append(f' Average of 4-Term Deflections = {sum(pier_deflections_four_term)/len(pier_deflections_four_term):.3f} in - H/{delta_h_over:.1f} or {percent_drift:.4f}%') + + # Piers + for i,j in enumerate(piers): + # pier x + if i == 0: + px = 0 + 3 + else: + px = sum(piers[:i])+sum(openings[:i]) + 3 + + text_x = px+(j/2) + text_y = hb_ft + (ho_ft/2) + svg_string.append(f'') + svg_string.append(f'') + svg_string.append(f'') + svg_string.append(f' Analysis: {pier_shears_plf[i]:.1f} plf ') + svg_string.append(f' Method 1: {pier_shears_plf[i]/method1_af[i]:.1f} plf ') + svg_string.append(f' Method 2: {pier_shears_plf[i]/method2_af[i]:.1f} plf ') + text_y = hb_ft/2 + svg_string.append(f' {corner_unit_shears_plf[i]:.1f} plf ') + text_y = hb_ft + ho_ft + (ha_ft/2) + svg_string.append(f' {corner_unit_shears_plf[i]:.1f} plf ') + # Openings + for i,j in enumerate(openings): + + ox = sum(piers[:i]) + piers[i] + sum(openings[:i])+3 + + # Bottom Panel + svg_string.append(f'') + # Top Panel + svg_string.append(f'') + + text_x = ox + (j/2) + text_y = hb_ft/2 + svg_string.append(f' {opening_shears_plf[i]:.1f} plf ') + text_y = hb_ft + ho_ft + (ha_ft/2) + svg_string.append(f' {opening_shears_plf[i]:.1f} plf ') + + force_left_text = corner_forces_lbs[i][0] + force_right_text = corner_forces_lbs[i][1] + text_x = ox - 0.125 + text_y = hb_ft + (3/16) + svg_string.append(f' {force_left_text:.1f} lbs ') + text_x = ox - 0.125 + text_y = hb_ft + ho_ft - (3/16) + svg_string.append(f' {force_left_text:.1f} lbs ') + text_x = ox + j + 0.125 + text_y = hb_ft + (3/16) + svg_string.append(f' {force_right_text:.1f} lbs ') + text_x = ox + j + 0.125 + text_y = hb_ft + ho_ft - (3/16) + svg_string.append(f' {force_right_text:.1f} lbs ') + + svg_string.append("") + svg_string.append("") + + svg_file = open(os.path.join(os.path.dirname(os.path.realpath(__file__)),"ftao.svg"), "w") + for i in svg_string: + svg_file.write(i+"\n") + + svg_file.close() + + + else: + print("----BEGIN ERRORS-----") + for error in errors: + print(error) + print("----END ERRORS-----") + + else: + print("----BEGIN ERRORS-----") + for error in errors: + print(error) + print("----END ERRORS-----") diff --git a/Wood/nds2018_table4a_reference_values.csv b/Wood/nds2018_table4a_reference_values.csv new file mode 100644 index 0000000..11b2711 --- /dev/null +++ b/Wood/nds2018_table4a_reference_values.csv @@ -0,0 +1,263 @@ +Species,Grade,Size Classification,Fb_psi,Ft_psi,Fv_psi,Fcp_psi,Fc_psi,E_psi,Emin_psi,G,Agency +Alaska Cedar,Select Structural,"2"" & wider",1150,626,165,525,1000,1400000,510000,0.47,WCLIB +Alaska Cedar,No. 1,"2"" & wider",975,525,165,525,900,1300000,470000,0.47,WCLIB +Alaska Cedar,No. 2,"2"" & wider",800,425,165,525,750,1200000,440000,0.47,WCLIB +Alaska Cedar,No. 3,"2"" & wider",450,250,165,525,425,1100000,400000,0.47,WCLIB +Alaska Cedar,Stud,"2"" & wider",625,350,165,525,475,1100000,400000,0.47,WCLIB +Alaska Cedar,Construction,"2"" - 4"" wide",900,500,165,525,950,1200000,440000,0.47,WCLIB +Alaska Cedar,Standard,"2"" - 4"" wide",500,275,165,525,775,1100000,400000,0.47,WCLIB +Alaska Cedar,Utility,"2"" - 4"" wide",250,125,165,525,500,1000000,370000,0.47,WCLIB +Alaska Hemlock,Select Structural,"2"" & wider",1300,825,185,440,1200,1700000,620000,0.49,WWPA +Alaska Hemlock,No. 1,"2"" & wider",900,550,185,440,1100,1600000,580000,0.49,WWPA +Alaska Hemlock,No. 2,"2"" & wider",825,475,185,440,1050,1500000,550000,0.49,WWPA +Alaska Hemlock,No. 3,"2"" & wider",475,275,185,440,600,1400000,510000,0.49,WWPA +Alaska Hemlock,Stud,"2"" & wider",650,375,185,440,650,1400000,510000,0.49,WWPA +Alaska Hemlock,Construction,"2"" - 4"" wide",950,550,185,440,1250,1400000,510000,0.49,WWPA +Alaska Hemlock,Standard,"2"" - 4"" wide",525,300,185,440,1050,1300000,470000,0.49,WWPA +Alaska Hemlock,Utility,"2"" - 4"" wide",250,150,185,440,700,1200000,440000,0.49,WWPA +Alaska Spruce,Select Structural,"2"" & wider",1400,900,160,330,1200,1600000,580000,0.41,WWPA +Alaska Spruce,No. 1,"2"" & wider",950,600,160,330,1100,1500000,550000,0.41,WWPA +Alaska Spruce,No. 2,"2"" & wider",875,500,160,330,1050,1400000,510000,0.41,WWPA +Alaska Spruce,No. 3,"2"" & wider",500,300,160,330,600,1300000,470000,0.41,WWPA +Alaska Spruce,Stud,"2"" & wider",675,400,160,330,675,1300000,470000,0.41,WWPA +Alaska Spruce,Construction,"2"" - 4"" wide",1000,575,160,330,1250,1300000,470000,0.41,WWPA +Alaska Spruce,Standard,"2"" - 4"" wide",550,325,160,330,1050,1200000,440000,0.41,WWPA +Alaska Spruce,Utility,"2"" - 4"" wide",275,150,160,330,700,1100000,400000,0.41,WWPA +Alaska Yellow Cedar,Select Structural,"2"" & wider",1350,800,225,510,1200,1500000,550000,0.46,WCLIB-WWPA +Alaska Yellow Cedar,No. 1,"2"" & wider",900,525,225,510,1050,1400000,510000,0.46,WCLIB-WWPA +Alaska Yellow Cedar,No. 2,"2"" & wider",800,450,225,510,1000,1300000,470000,0.46,WCLIB-WWPA +Alaska Yellow Cedar,No. 3,"2"" & wider",475,250,225,510,575,1200000,440000,0.46,WCLIB-WWPA +Alaska Yellow Cedar,Stud,"2"" & wider",625,350,225,510,625,1200000,440000,0.46,WCLIB-WWPA +Alaska Yellow Cedar,Construction,"2"" - 4"" wide",925,500,225,510,1250,1300000,470000,0.46,WCLIB-WWPA +Alaska Yellow Cedar,Standard,"2"" - 4"" wide",500,275,225,510,1050,1100000,400000,0.46,WCLIB-WWPA +Alaska Yellow Cedar,Utility,"2"" - 4"" wide",250,125,225,510,675,1100000,400000,0.46,WCLIB-WWPA +Aspen,Select Structural,"2"" & wider",875,500,120,265,725,1100000,400000,0.39,NELMA-WWPA +Aspen,No. 1,"2"" & wider",625,375,120,265,600,1100000,400000,0.39,NELMA-WWPA +Aspen,No. 2,"2"" & wider",600,350,120,265,450,1000000,370000,0.39,NELMA-WWPA +Aspen,No. 3,"2"" & wider",350,200,120,265,275,900000,330000,0.39,NELMA-WWPA +Aspen,Stud,"2"" & wider",475,275,120,265,300,900000,330000,0.39,NELMA-WWPA +Aspen,Construction,"2"" - 4"" wide",700,400,120,265,625,900000,330000,0.39,NELMA-WWPA +Aspen,Standard,"2"" - 4"" wide",375,225,120,265,475,900000,330000,0.39,NELMA-WWPA +Aspen,Utility,"2"" - 4"" wide",175,100,120,265,300,800000,290000,0.39,NELMA-WWPA +Baldcypress,Select Structural,"2"" & wider",1200,650,160,615,1200,1400000,510000,0.47,SPIB +Baldcypress,No. 1,"2"" & wider",1000,550,160,615,1050,1400000,510000,0.47,SPIB +Baldcypress,No. 2,"2"" & wider",25,450,160,615,900,1300000,470000,0.47,SPIB +Baldcypress,No. 3,"2"" & wider",475,250,160,615,525,1200000,440000,0.47,SPIB +Baldcypress,Stud,"2"" & wider",650,350,160,615,575,1200000,440000,0.47,SPIB +Baldcypress,Construction,"2"" - 4"" wide",925,500,160,615,1100,1200000,440000,0.47,SPIB +Baldcypress,Standard,"2"" - 4"" wide",525,275,160,615,925,1100000,400000,0.47,SPIB +Baldcypress,Utility,"2"" - 4"" wide",250,125,160,615,600,1000000,370000,0.47,SPIB +Beech-Birch-Hickory,Select Structural,"2"" & wider",1450,850,195,715,1200,1700000,620000,0.71,NELMA +Beech-Birch-Hickory,No. 1,"2"" & wider",1050,600,195,715,950,1600000,580000,0.71,NELMA +Beech-Birch-Hickory,No. 2,"2"" & wider",1000,600,195,715,750,1500000,550000,0.71,NELMA +Beech-Birch-Hickory,No. 3,"2"" & wider",575,350,195,715,425,1300000,470000,0.71,NELMA +Beech-Birch-Hickory,Stud,"2"" & wider",775,450,195,715,475,1300000,470000,0.71,NELMA +Beech-Birch-Hickory,Construction,"2"" - 4"" wide",1150,675,195,715,1000,1400000,510000,0.71,NELMA +Beech-Birch-Hickory,Standard,"2"" - 4"" wide",650,375,195,715,775,1300000,470000,0.71,NELMA +Beech-Birch-Hickory,Utility,"2"" - 4"" wide",300,175,195,715,500,1200000,440000,0.71,NELMA +Coast Sitka Spruce,Select Structural,"2"" & wider",1300,950,125,455,1200,1700000,620000,0.43,NLGA +Coast Sitka Spruce,No. 1 / No. 2,"2"" & wider",925,550,125,455,1100,1500000,550000,0.43,NLGA +Coast Sitka Spruce,No. 3,"2"" & wider",525,325,125,455,625,1400000,510000,0.43,NLGA +Coast Sitka Spruce,Stud,"2"" & wider",725,450,125,455,675,1400000,510000,0.43,NLGA +Coast Sitka Spruce,Construction,"2"" - 4"" wide",1050,650,125,455,1300,1400000,510000,0.43,NLGA +Coast Sitka Spruce,Standard,"2"" - 4"" wide",600,350,125,455,1100,1300000,470000,0.43,NLGA +Coast Sitka Spruce,Utility,"2"" - 4"" wide",275,175,125,455,725,1200000,440000,0.43,NLGA +Cottonwood,Select Structural,"2"" & wider",875,525,125,320,775,1200000,440000,0.41,NELMA +Cottonwood,No. 1,"2"" & wider",625,375,125,320,625,1200000,440000,0.41,NELMA +Cottonwood,No. 2,"2"" & wider",625,350,125,320,475,1100000,400000,0.41,NELMA +Cottonwood,No. 3,"2"" & wider",350,200,125,320,275,1000000,370000,0.41,NELMA +Cottonwood,Stud,"2"" & wider",475,275,125,320,300,1000000,370000,0.41,NELMA +Cottonwood,Construction,"2"" - 4"" wide",700,400,125,320,650,1000000,370000,0.41,NELMA +Cottonwood,Standard,"2"" - 4"" wide",400,225,125,320,500,900000,330000,0.41,NELMA +Cottonwood,Utility,"2"" - 4"" wide",175,100,125,320,325,900000,330000,0.41,NELMA +Douglas Fir-Larch,Select Structural,"2"" & wider",1500,1000,180,625,1700,1900000,690000,0.5,WCLIB-WWPA +Douglas Fir-Larch,No. 1 & Btr,"2"" & wider",1200,800,180,625,1550,1800000,660000,0.5,WCLIB-WWPA +Douglas Fir-Larch,No. 1,"2"" & wider",1000,675,180,625,1500,1700000,620000,0.5,WCLIB-WWPA +Douglas Fir-Larch,No. 2,"2"" & wider",900,575,180,625,1350,1600000,580000,0.5,WCLIB-WWPA +Douglas Fir-Larch,No. 3,"2"" & wider",525,325,180,625,775,1400000,510000,0.5,WCLIB-WWPA +Douglas Fir-Larch,Stud,"2"" & wider",700,450,180,625,850,1400000,510000,0.5,WCLIB-WWPA +Douglas Fir-Larch,Construction,"2"" - 4"" wide",1000,650,180,625,1650,1500000,550000,0.5,WCLIB-WWPA +Douglas Fir-Larch,Standard,"2"" - 4"" wide",575,375,180,625,1400,1400000,510000,0.5,WCLIB-WWPA +Douglas Fir-Larch,Utility,"2"" - 4"" wide",275,175,180,625,900,1300000,470000,0.5,WCLIB-WWPA +Douglas Fir-Larch (North),Select Structural,"2"" & wider",1350,825,180,625,1900,1900000,690000,0.49,NLGA +Douglas Fir-Larch (North),No. 1 & Btr,"2"" & wider",1150,750,180,625,1800,1800000,660000,0.49,NLGA +Douglas Fir-Larch (North),No. 1 / No. 2,"2"" & wider",850,500,180,625,1400,1600000,580000,0.49,NLGA +Douglas Fir-Larch (North),No. 3,"2"" & wider",475,300,180,625,825,1400000,510000,0.49,NLGA +Douglas Fir-Larch (North),Stud,"2"" & wider",650,400,180,625,900,1400000,510000,0.49,NLGA +Douglas Fir-Larch (North),Construction,"2"" - 4"" wide",950,575,180,625,1800,1500000,550000,0.49,NLGA +Douglas Fir-Larch (North),Standard,"2"" - 4"" wide",525,325,180,625,1450,1400000,510000,0.49,NLGA +Douglas Fir-Larch (North),Utility,"2"" - 4"" wide",250,150,180,625,950,1300000,470000,0.49,NLGA +Douglas Fir-South,Select Structural,"2"" & wider",1350,900,180,520,1600,1400000,510000,0.46,WWPA +Douglas Fir-South,No. 1,"2"" & wider",925,600,180,520,1450,1300000,470000,0.46,WWPA +Douglas Fir-South,No. 2,"2"" & wider",850,525,180,520,1350,1200000,440000,0.46,WWPA +Douglas Fir-South,No. 3,"2"" & wider",500,300,180,520,775,1100000,400000,0.46,WWPA +Douglas Fir-South,Stud,"2"" & wider",675,425,180,520,850,1100000,400000,0.46,WWPA +Douglas Fir-South,Construction,"2"" - 4"" wide",975,600,180,520,1650,1200000,440000,0.46,WWPA +Douglas Fir-South,Standard,"2"" - 4"" wide",550,350,180,520,1400,1100000,400000,0.46,WWPA +Douglas Fir-South,Utility,"2"" - 4"" wide",250,150,180,520,900,1000000,370000,0.46,WWPA +Eastern Hemlock-Balsam Fir,Select Structural,"2"" & wider",1250,575,140,335,1200,1200000,440000,0.36,NELMA +Eastern Hemlock-Balsam Fir,No. 1,"2"" & wider",775,350,140,335,1000,1100000,400000,0.36,NELMA +Eastern Hemlock-Balsam Fir,No. 2,"2"" & wider",575,275,140,335,825,1100000,400000,0.36,NELMA +Eastern Hemlock-Balsam Fir,No. 3,"2"" & wider",350,150,140,335,475,900000,330000,0.36,NELMA +Eastern Hemlock-Balsam Fir,Stud,"2"" & wider",450,200,140,335,525,900000,330000,0.36,NELMA +Eastern Hemlock-Balsam Fir,Construction,"2"" - 4"" wide",675,300,140,335,1050,1000000,370000,0.36,NELMA +Eastern Hemlock-Balsam Fir,Standard,"2"" - 4"" wide",375,175,140,335,850,900000,330000,0.36,NELMA +Eastern Hemlock-Balsam Fir,Utility,"2"" - 4"" wide",175,75,140,335,550,800000,290000,0.36,NELMA +Eastern Hemlock-Tamarack,Select Structural,"2"" & wider",1250,575,170,555,1200,1200000,440000,0.41,NELMA +Eastern Hemlock-Tamarack,No. 1,"2"" & wider",775,350,170,555,1000,1100000,400000,0.41,NELMA +Eastern Hemlock-Tamarack,No. 2,"2"" & wider",575,275,170,555,825,1100000,400000,0.41,NELMA +Eastern Hemlock-Tamarack,No. 3,"2"" & wider",350,150,170,555,475,900000,330000,0.41,NELMA +Eastern Hemlock-Tamarack,Stud,"2"" & wider",450,200,170,555,525,900000,330000,0.41,NELMA +Eastern Hemlock-Tamarack,Construction,"2"" - 4"" wide",675,300,170,555,1050,1000000,370000,0.41,NELMA +Eastern Hemlock-Tamarack,Standard,"2"" - 4"" wide",375,175,170,555,850,900000,330000,0.41,NELMA +Eastern Hemlock-Tamarack,Utility,"2"" - 4"" wide",1750,75,170,555,550,800000,290000,0.41,NELMA +Eastern Softwoods,Select Structural,"2"" & wider",1250,575,140,335,1200,1200000,440000,0.36,NELMA +Eastern Softwoods,No. 1,"2"" & wider",775,350,140,335,1000,1100000,400000,0.36,NELMA +Eastern Softwoods,No. 2,"2"" & wider",575,275,140,335,825,1100000,400000,0.36,NELMA +Eastern Softwoods,No. 3,"2"" & wider",350,150,140,335,475,900000,330000,0.36,NELMA +Eastern Softwoods,Stud,"2"" & wider",450,200,140,335,525,900000,330000,0.36,NELMA +Eastern Softwoods,Construction,"2"" - 4"" wide",675,300,140,335,1050,1000000,370000,0.36,NELMA +Eastern Softwoods,Standard,"2"" - 4"" wide",375,175,140,335,850,900000,330000,0.36,NELMA +Eastern Softwoods,Utility,"2"" - 4"" wide",175,75,140,335,550,800000,290000,0.36,NELMA +Eastern White Pine,Select Structural,"2"" & wider",1250,575,135,350,1200,1200000,440000,0.36,NELMA +Eastern White Pine,No. 1,"2"" & wider",775,350,135,350,1000,1100000,400000,0.36,NELMA +Eastern White Pine,No. 2,"2"" & wider",575,275,135,350,825,1100000,400000,0.36,NELMA +Eastern White Pine,No. 3,"2"" & wider",350,150,135,350,475,900000,330000,0.36,NELMA +Eastern White Pine,Stud,"2"" & wider",450,200,135,350,525,900000,330000,0.36,NELMA +Eastern White Pine,Construction,"2"" - 4"" wide",675,300,135,350,1050,1000000,370000,0.36,NELMA +Eastern White Pine,Standard,"2"" - 4"" wide",375,175,135,350,850,900000,330000,0.36,NELMA +Eastern White Pine,Utility,"2"" - 4"" wide",175,75,135,350,550,800000,290000,0.36,NELMA +Hem-Fir,Select Structural,"2"" & wider",1400,925,150,405,1500,1600000,580000,0.43,WCLIB-WWPA +Hem-Fir,No. 1 & Btr,"2"" & wider",1100,725,150,405,1350,1500000,550000,0.43,WCLIB-WWPA +Hem-Fir,No. 1,"2"" & wider",975,625,150,405,1350,1500000,550000,0.43,WCLIB-WWPA +Hem-Fir,No. 2,"2"" & wider",850,525,150,405,1300,1300000,470000,0.43,WCLIB-WWPA +Hem-Fir,No. 3,"2"" & wider",500,300,150,405,725,1200000,440000,0.43,WCLIB-WWPA +Hem-Fir,Stud,"2"" & wider",675,400,150,405,800,1200000,440000,0.43,WCLIB-WWPA +Hem-Fir,Construction,"2"" - 4"" wide",975,600,150,405,1550,1300000,470000,0.43,WCLIB-WWPA +Hem-Fir,Standard,"2"" - 4"" wide",550,325,150,405,1300,1200000,440000,0.43,WCLIB-WWPA +Hem-Fir,Utility,"2"" - 4"" wide",250,150,150,405,850,1100000,400000,0.43,WCLIB-WWPA +Hem-Fir (North),Select Structural,"2"" & wider",1300,775,145,405,1700,1700000,620000,0.46,NLGA +Hem-Fir (North),No. 1 & Btr,"2"" & wider",1200,725,145,405,1550,1700000,620000,0.46,NLGA +Hem-Fir (North),No. 1 / No. 2,"2"" & wider",1000,575,145,405,1450,1600000,580000,0.46,NLGA +Hem-Fir (North),No. 3,"2"" & wider",575,325,145,405,850,1400000,510000,0.46,NLGA +Hem-Fir (North),Stud,"2"" & wider",775,450,145,405,925,1400000,510000,0.46,NLGA +Hem-Fir (North),Construction,"2"" - 4"" wide",1150,650,145,405,1750,1500000,550000,0.46,NLGA +Hem-Fir (North),Standard,"2"" - 4"" wide",650,350,145,405,1500,1400000,510000,0.46,NLGA +Hem-Fir (North),Utility,"2"" - 4"" wide",300,175,145,405,975,1300000,470000,0.46,NLGA +Mixed Maple,Select Structural,"2"" & wider",1000,600,195,620,875,1300000,470000,0.55,NELMA +Mixed Maple,No. 1,"2"" & wider",725,425,195,620,700,1200000,440000,0.55,NELMA +Mixed Maple,No. 2,"2"" & wider",700,425,195,620,550,1100000,400000,0.55,NELMA +Mixed Maple,No. 3,"2"" & wider",400,250,195,620,325,1000000,370000,0.55,NELMA +Mixed Maple,Stud,"2"" & wider",550,325,195,620,350,1000000,370000,0.55,NELMA +Mixed Maple,Construction,"2"" - 4"" wide",800,475,195,620,725,1100000,400000,0.55,NELMA +Mixed Maple,Standard,"2"" - 4"" wide",450,275,195,620,575,1000000,370000,0.55,NELMA +Mixed Maple,Utility,"2"" - 4"" wide",225,125,195,620,375,900000,330000,0.55,NELMA +Mixed Oak,Select Structural,"2"" & wider",1150,675,170,800,1000,1100000,400000,0.68,NELMA +Mixed Oak,No. 1,"2"" & wider",825,500,170,800,825,1000000,370000,0.68,NELMA +Mixed Oak,No. 2,"2"" & wider",800,475,170,800,625,900000,330000,0.68,NELMA +Mixed Oak,No. 3,"2"" & wider",475,275,170,800,375,800000,290000,0.68,NELMA +Mixed Oak,Stud,"2"" & wider",625,375,170,800,400,800000,290000,0.68,NELMA +Mixed Oak,Construction,"2"" - 4"" wide",925,550,170,800,850,900000,330000,0.68,NELMA +Mixed Oak,Standard,"2"" - 4"" wide",525,300,170,800,650,800000,290000,0.68,NELMA +Mixed Oak,Utility,"2"" - 4"" wide",250,150,170,800,425,800000,290000,0.68,NELMA +Northern Red Oak,Select Structural,"2"" & wider",1400,800,220,885,1150,1400000,510000,0.68,NELMA +Northern Red Oak,No. 1,"2"" & wider",1000,575,220,885,925,1400000,510000,0.68,NELMA +Northern Red Oak,No. 2,"2"" & wider",975,575,220,885,725,1300000,470000,0.68,NELMA +Northern Red Oak,No. 3,"2"" & wider",550,325,220,885,425,1200000,440000,0.68,NELMA +Northern Red Oak,Stud,"2"" & wider",750,450,220,885,450,1200000,440000,0.68,NELMA +Northern Red Oak,Construction,"2"" - 4"" wide",1100,650,220,885,975,1200000,440000,0.68,NELMA +Northern Red Oak,Standard,"2"" - 4"" wide",625,350,220,885,750,1100000,400000,0.68,NELMA +Northern Red Oak,Utility,"2"" - 4"" wide",300,175,220,885,500,1000000,370000,0.68,NELMA +Northern Species,Select Structural,"2"" & wider",975,425,110,350,1100,1100000,400000,0.35,NLGA +Northern Species,No. 1 / No. 2,"2"" & wider",625,275,110,350,850,1100000,400000,0.35,NLGA +Northern Species,No. 3,"2"" & wider",350,150,110,350,500,1000000,370000,0.35,NLGA +Northern Species,Stud,"2"" & wider",475,225,110,350,550,1000000,370000,0.35,NLGA +Northern Species,Construction,"2"" - 4"" wide",700,325,110,350,1050,1000000,370000,0.35,NLGA +Northern Species,Standard,"2"" - 4"" wide",400,175,110,350,875,900000,330000,0.35,NLGA +Northern Species,Utility,"2"" - 4"" wide",175,75,110,350,575,900000,330000,0.35,NLGA +Northern White Cedar,Select Structural,"2"" & wider",775,450,120,370,750,800000,290000,0.31,NELMA +Northern White Cedar,No. 1,"2"" & wider",575,325,120,370,600,700000,260000,0.31,NELMA +Northern White Cedar,No. 2,"2"" & wider",550,325,120,370,475,700000,260000,0.31,NELMA +Northern White Cedar,No. 3,"2"" & wider",325,175,120,370,275,600000,220000,0.31,NELMA +Northern White Cedar,Stud,"2"" & wider",425,250,120,370,300,600000,220000,0.31,NELMA +Northern White Cedar,Construction,"2"" - 4"" wide",625,375,120,370,625,700000,260000,0.31,NELMA +Northern White Cedar,Standard,"2"" - 4"" wide",350,200,120,370,475,600000,220000,0.31,NELMA +Northern White Cedar,Utility,"2"" - 4"" wide",175,100,120,370,325,600000,220000,0.31,NELMA +Red Maple,Select Structural,"2"" & wider",1300,750,210,615,1100,1700000,620000,0.58,NELMA +Red Maple,No. 1,"2"" & wider",925,550,210,615,900,1600000,580000,0.58,NELMA +Red Maple,No. 2,"2"" & wider",900,525,210,615,700,1500000,550000,0.58,NELMA +Red Maple,No. 3,"2"" & wider",525,300,210,615,400,1300000,470000,0.58,NELMA +Red Maple,Stud,"2"" & wider",700,425,210,615,450,1300000,470000,0.58,NELMA +Red Maple,Construction,"2"" - 4"" wide",1050,600,210,615,925,1400000,510000,0.58,NELMA +Red Maple,Standard,"2"" - 4"" wide",575,325,210,615,725,1300000,470000,0.58,NELMA +Red Maple,Utility,"2"" - 4"" wide",275,150,210,615,475,1200000,440000,0.58,NELMA +Red Oak,Select Structural,"2"" & wider",1150,675,170,820,1000,1400000,510000,0.67,NELMA +Red Oak,No. 1,"2"" & wider",825,500,170,820,825,1300000,470000,0.67,NELMA +Red Oak,No. 2,"2"" & wider",800,475,170,820,625,1200000,440000,0.67,NELMA +Red Oak,No. 3,"2"" & wider",475,275,170,820,375,1100000,400000,0.67,NELMA +Red Oak,Stud,"2"" & wider",625,375,170,820,400,1100000,400000,0.67,NELMA +Red Oak,Construction,"2"" - 4"" wide",925,550,170,820,850,1200000,440000,0.67,NELMA +Red Oak,Standard,"2"" - 4"" wide",525,300,170,820,650,1100000,400000,0.67,NELMA +Red Oak,Utility,"2"" - 4"" wide",250,150,170,820,425,1000000,370000,0.67,NELMA +Redwood,Select Structural,"2"" & wider",1100,625,160,425,1100,1100000,400000,0.37,RIS +Redwood,No. 1,"2"" & wider",775,450,160,425,900,1100000,400000,0.37,RIS +Redwood,No. 2,"2"" & wider",725,425,160,425,700,1000000,370000,0.37,RIS +Redwood,No. 3,"2"" & wider",425,250,160,425,400,900000,370000,0.37,RIS +Redwood,Stud,"2"" & wider",575,325,160,425,450,900000,370000,0.37,RIS +Redwood,Construction,"2"" - 4"" wide",825,475,160,425,925,900000,370000,0.37,RIS +Redwood,Standard,"2"" - 4"" wide",450,275,160,425,725,900000,370000,0.37,RIS +Redwood,Utility,"2"" - 4"" wide",225,125,160,425,475,800000,290000,0.37,RIS +Spruce-Pine-Fir,Select Structural,"2"" & wider",1250,700,135,425,1400,1500000,550000,0.42,NLGA +Spruce-Pine-Fir,No. 1 / No. 2,"2"" & wider",875,450,135,425,1150,1400000,510000,0.42,NLGA +Spruce-Pine-Fir,No. 3,"2"" & wider",500,250,135,425,650,1200000,440000,0.42,NLGA +Spruce-Pine-Fir,Stud,"2"" & wider",675,350,135,425,725,1200000,440000,0.42,NLGA +Spruce-Pine-Fir,Construction,"2"" - 4"" wide",1000,500,135,425,1400,1300000,470000,0.42,NLGA +Spruce-Pine-Fir,Standard,"2"" - 4"" wide",550,275,135,425,1150,1200000,440000,0.42,NLGA +Spruce-Pine-Fir,Utility,"2"" - 4"" wide",275,125,135,425,750,1100000,400000,0.42,NLGA +Spruce-Pine-Fir (South),Select Structural,"2"" & wider",1300,575,135,335,1200,1300000,470000,0.36,NELMA-WCLIB-WWPA +Spruce-Pine-Fir (South),No. 1,"2"" & wider",875,400,135,335,1050,1200000,440000,0.36,NELMA-WCLIB-WWPA +Spruce-Pine-Fir (South),No. 2,"2"" & wider",775,350,135,335,1000,1100000,400000,0.36,NELMA-WCLIB-WWPA +Spruce-Pine-Fir (South),No. 3,"2"" & wider",450,200,135,335,575,1000000,370000,0.36,NELMA-WCLIB-WWPA +Spruce-Pine-Fir (South),Stud,"2"" & wider",600,275,135,335,625,1000000,370000,0.36,NELMA-WCLIB-WWPA +Spruce-Pine-Fir (South),Construction,"2"" - 4"" wide",875,400,135,335,1200,1000000,370000,0.36,NELMA-WCLIB-WWPA +Spruce-Pine-Fir (South),Standard,"2"" - 4"" wide",500,225,135,335,1000,900000,330000,0.36,NELMA-WCLIB-WWPA +Spruce-Pine-Fir (South),Utility,"2"" - 4"" wide",225,100,135,335,875,900000,330000,0.36,NELMA-WCLIB-WWPA +Western Cedars,Select Structural,"2"" & wider",1000,600,155,425,1000,1100000,400000,0.36,WCLIB-WWPA +Western Cedars,No. 1,"2"" & wider",725,425,155,425,825,1000000,370000,0.36,WCLIB-WWPA +Western Cedars,No. 2,"2"" & wider",700,425,155,425,650,1000000,370000,0.36,WCLIB-WWPA +Western Cedars,No. 3,"2"" & wider",400,250,155,425,375,900000,330000,0.36,WCLIB-WWPA +Western Cedars,Stud,"2"" & wider",550,325,155,425,400,900000,330000,0.36,WCLIB-WWPA +Western Cedars,Construction,"2"" - 4"" wide",800,475,155,425,850,900000,330000,0.36,WCLIB-WWPA +Western Cedars,Standard,"2"" - 4"" wide",450,275,155,425,650,800000,290000,0.36,WCLIB-WWPA +Western Cedars,Utility,"2"" - 4"" wide",225,125,155,425,425,800000,290000,0.36,WCLIB-WWPA +Western Woods,Select Structural,"2"" & wider",900,400,135,335,1050,1200000,440000,0.36,WCLIB-WWPA +Western Woods,No. 1,"2"" & wider",675,300,135,335,950,1100000,400000,0.36,WCLIB-WWPA +Western Woods,No. 2,"2"" & wider",675,300,135,335,900,1000000,370000,0.36,WCLIB-WWPA +Western Woods,No. 3,"2"" & wider",375,175,135,335,525,900000,330000,0.36,WCLIB-WWPA +Western Woods,Stud,"2"" & wider",525,225,135,335,575,900000,330000,0.36,WCLIB-WWPA +Western Woods,Construction,"2"" - 4"" wide",775,350,135,335,1100,1000000,370000,0.36,WCLIB-WWPA +Western Woods,Standard,"2"" - 4"" wide",425,200,135,335,925,900000,330000,0.36,WCLIB-WWPA +Western Woods,Utility,"2"" - 4"" wide",200,100,135,335,600,800000,290000,0.36,WCLIB-WWPA +White Oak,Select Structural,"2"" & wider",1200,700,220,800,1100,1100000,400000,0.73,NELMA +White Oak,No. 1,"2"" & wider",875,500,220,800,900,1000000,370000,0.73,NELMA +White Oak,No. 2,"2"" & wider",850,500,220,800,700,900000,330000,0.73,NELMA +White Oak,No. 3,"2"" & wider",475,275,220,800,400,800000,290000,0.73,NELMA +White Oak,Stud,"2"" & wider",650,375,220,800,450,800000,290000,0.73,NELMA +White Oak,Construction,"2"" - 4"" wide",950,550,220,800,925,900000,330000,0.73,NELMA +White Oak,Standard,"2"" - 4"" wide",525,325,220,800,725,800000,290000,0.73,NELMA +White Oak,Utility,"2"" - 4"" wide",250,150,220,800,475,800000,290000,0.73,NELMA +Yellow Cedar,Select Structural,"2"" & wider",1200,725,175,540,1200,1600000,580000,0.46,NLGA +Yellow Cedar,No. 1 / No. 2,"2"" & wider",800,475,175,540,1000,1400000,510000,0.46,NLGA +Yellow Cedar,No. 3,"2"" & wider",475,275,175,540,575,1200000,440000,0.46,NLGA +Yellow Cedar,Stud,"2"" & wider",625,375,175,540,650,1200000,440000,0.46,NLGA +Yellow Cedar,Construction,"2"" - 4"" wide",925,550,175,540,1200,1300000,470000,0.46,NLGA +Yellow Cedar,Standard,"2"" - 4"" wide",525,300,175,540,1050,1200000,440000,0.46,NLGA +Yellow Cedar,Utility,"2"" - 4"" wide",250,150,175,540,675,1100000,400000,0.46,NLGA +Yellow Poplar,Select Structural,"2"" & wider",1000,575,145,420,900,1500000,550000,0.43,NELMA +Yellow Poplar,No. 1,"2"" & wider",725,425,145,420,725,1400000,510000,0.43,NELMA +Yellow Poplar,No. 2,"2"" & wider",700,400,145,420,575,1300000,470000,0.43,NELMA +Yellow Poplar,No. 3,"2"" & wider",400,225,145,420,325,1200000,440000,0.43,NELMA +Yellow Poplar,Stud,"2"" & wider",550,325,145,420,350,1200000,440000,0.43,NELMA +Yellow Poplar,Construction,"2"" - 4"" wide",800,475,145,420,750,1300000,470000,0.43,NELMA +Yellow Poplar,Standard,"2"" - 4"" wide",450,250,145,420,575,1100000,400000,0.43,NELMA +Yellow Poplar,Utility,"2"" - 4"" wide",200,125,145,420,375,1100000,400000,0.43,NELMA diff --git a/Wood/wood_classes.py b/Wood/wood_classes.py index 5f2596e..d866a1f 100644 --- a/Wood/wood_classes.py +++ b/Wood/wood_classes.py @@ -1,29 +1,34 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Feb 16 09:37:43 2018 - -@author: DonB -""" - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division #import matplotlib.pyplot as plt class wood_stud_wall: - def __init__(self,b_in=1.5,d_in=3.5,height_ft=10, spacing_in=12, grade="No.2", fb_psi=875, fv_psi= 150, fc_psi=1150, E_psi=1400000, Emin_psi=510000, fc_perp_pl_psi=565, moisture_percent = 19, temp = 90, incised = 0, num_plates = 0, c_frt=[1,1,1,1,1,1], compression_face=1, blocking_ft=0, no_sheathing=0): + def __init__(self,b_in=1.5,d_in=3.5,height_ft=10, spacing_in=12, grade="No.2", fb_psi=875, fv_psi= 150, fc_psi=1150, E_psi=1400000, Emin_psi=510000, fc_perp_pl_psi=565, moisture_percent = 19, temp = 90, incised = 0, num_plates = 0, c_frt=[1,1,1,1,1,1], compression_face=1, blocking_ft=0, no_sheathing=0, is_syp=0): self.b_in = b_in self.d_in = d_in @@ -70,91 +75,96 @@ def __init__(self,b_in=1.5,d_in=3.5,height_ft=10, spacing_in=12, grade="No.2", f #Size Factor, Cf #NDS 2005 section 4.3.6 and Table 4A #NOTE ASSUMES STUDS ARE VISUALLY GRADED DIMENSION LUMBER 2"-4" AND NOT SOUTHERN PINE AND NORTH AMERICAN SPECIES - self.assumptions = self.assumptions + 'Size Factor_Cf - Wall Studs are visually graded dimensional lumber 2" to 4" North American Species and not Southern Pine\n' - if grade == "Stud": - #Per NDS 2005 Table 4A for stud grade depth >8" use No.3 size factors - if self.d_in>11.25: - self.cf_fc = 0.9 - if self.b_in>2.5: - self.cf_fb = 1.0 - else: - self.cf_fb = 0.9 - elif self.d_in>9.25: - self.cf_fc = 1.0 - if self.b_in>2.5: - self.cf_fb = 1.1 - else: + if is_syp == 0: + self.assumptions = self.assumptions + 'Size Factor_Cf - Wall Studs are visually graded dimensional lumber 2" to 4" North American Species and not Southern Pine\n' + if grade == "Stud": + #Per NDS 2005 Table 4A for stud grade depth >8" use No.3 size factors + if self.d_in>11.25: + self.cf_fc = 0.9 + if self.b_in>2.5: + self.cf_fb = 1.0 + else: + self.cf_fb = 0.9 + elif self.d_in>9.25: + self.cf_fc = 1.0 + if self.b_in>2.5: + self.cf_fb = 1.1 + else: + self.cf_fb = 1.0 + elif self.d_in>7.25: + self.cf_fc = 1.0 + if self.b_in>2.5: + self.cf_fb = 1.2 + else: + self.cf_fb = 1.1 + elif self.d_in>5.5: + self.cf_fc = 1.05 + if self.b_in>2.5: + self.cf_fb = 1.3 + else: + self.cf_fb = 1.2 + elif self.d_in > 3.5: self.cf_fb = 1.0 - elif self.d_in>7.25: - self.cf_fc = 1.0 - if self.b_in>2.5: - self.cf_fb = 1.2 + self.cf_fc = 1.0 else: + self.cf_fc = 1.05 self.cf_fb = 1.1 - elif self.d_in>5.5: - self.cf_fc = 1.05 - if self.b_in>2.5: - self.cf_fb = 1.3 - else: - self.cf_fb = 1.2 - elif self.d_in > 3.5: - self.cf_fb = 1.0 - self.cf_fc = 1.0 - else: - self.cf_fc = 1.05 - self.cf_fb = 1.1 - elif grade == "Construction": - self.cf_fb = 1.0 - self.cf_fc = 1.0 - elif grade == "Utility": - if self.d_in > 2.5: + elif grade == "Construction": self.cf_fb = 1.0 self.cf_fc = 1.0 - else: - self.cf_fc = 0.6 - if self.b_in>2.5: - self.cf_fb = 1.0 - else: - self.cf_fb = 0.4 - else: - if self.d_in>11.25: - self.cf_fc = 0.9 - if self.b_in>2.5: - self.cf_fb = 1.0 - else: - self.cf_fb = 0.9 - elif self.d_in>9.25: - self.cf_fc = 1.0 - if self.b_in>2.5: - self.cf_fb = 1.1 - else: + elif grade == "Utility": + if self.d_in > 2.5: self.cf_fb = 1.0 - elif self.d_in>7.25: - self.cf_fc = 1.0 - if self.b_in>2.5: - self.cf_fb = 1.2 + self.cf_fc = 1.0 else: - self.cf_fb = 1.1 - elif self.d_in>5.5: - self.cf_fc = 1.05 - if self.b_in>2.5: + self.cf_fc = 0.6 + if self.b_in>2.5: + self.cf_fb = 1.0 + else: + self.cf_fb = 0.4 + else: + if self.d_in>11.25: + self.cf_fc = 0.9 + if self.b_in>2.5: + self.cf_fb = 1.0 + else: + self.cf_fb = 0.9 + elif self.d_in>9.25: + self.cf_fc = 1.0 + if self.b_in>2.5: + self.cf_fb = 1.1 + else: + self.cf_fb = 1.0 + elif self.d_in>7.25: + self.cf_fc = 1.0 + if self.b_in>2.5: + self.cf_fb = 1.2 + else: + self.cf_fb = 1.1 + elif self.d_in>5.5: + self.cf_fc = 1.05 + if self.b_in>2.5: + self.cf_fb = 1.3 + else: + self.cf_fb = 1.2 + elif self.d_in>4.5: + self.cf_fc = 1.1 self.cf_fb = 1.3 + elif self.d_in>3.5: + self.cf_fc = 1.1 + self.cf_fb = 1.4 else: - self.cf_fb = 1.2 - elif self.d_in>4.5: - self.cf_fc = 1.1 - self.cf_fb = 1.3 - elif self.d_in>3.5: - self.cf_fc = 1.1 - self.cf_fb = 1.4 - else: - self.cf_fc = 1.15 - self.cf_fb = 1.5 - + self.cf_fc = 1.15 + self.cf_fb = 1.5 + else: + self.assumptions = self.assumptions + 'Size Factor_Cf - Wall Studs are Southern Pine and stud is less than 4" thick and 12" wide. Cf = 1.0\n' + self.cf_fc = 1.0 + self.cf_fb = 1.0 + #Wet Service Factor, Cm #NDS 2005 section 4.3.3 and Table 4A #NOTE ASSUMES STUDS ARE VISUALLY GRADED DIMENSION LUMBER 2"-4" AND NOT SOUTHERN PINE AND NORTH AMERICAN SPECIES - self.assumptions = self.assumptions + 'Wet Service Factor_Cm - Wall Studs are visually graded dimensional lumber 2" to 4" North American Species and not Southern Pine\n' + self.assumptions = self.assumptions + 'Wet Service Factor_Cm - Wall Studs are visually graded dimensional lumber 2" to 4" North American Species or Southern Pine\n' if moisture_percent > 19: self.cm_fc_perp = 0.67 self.cm_E = 0.9 diff --git a/Wood/wood_stud_wall_gui.py b/Wood/wood_stud_wall_gui.py index 53f3ecc..f0210e7 100644 --- a/Wood/wood_stud_wall_gui.py +++ b/Wood/wood_stud_wall_gui.py @@ -1,18 +1,28 @@ -# -*- coding: utf-8 -*- - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' import Tkinter as tk import tkMessageBox @@ -40,6 +50,10 @@ def __init__(self, master): self.menubar.add_cascade(label = "File", menu=self.menu) self.menu.add_command(label="Open", command=self.file_open) self.menu.add_separator() + self.menu.add_command(label="Calc", command=self.run) + self.menu.add_command(label="Build P-lateral Pressure", command=self.generate_interaction_graph) + self.menu.add_command(label="Build P-M Chart", command=self.generate_pm_graph) + self.menu.add_separator() self.menu.add_command(label="Quit", command=self.quit_app) try: self.master.config(menu=self.menubar) @@ -60,71 +74,73 @@ def __init__(self, master): self.nb.add(self.page1, text='Wall and Stud Information and Inputs - Find Axial Capacity Per Stud') self.pg1_frame = tk.Frame(self.page1, bd=2, relief='sunken', padx=1,pady=1) - self.pg1_frame.pack(fill=tk.BOTH,expand=1, padx=5, pady=5) + self.pg1_frame.pack(fill=tk.BOTH,expand=1, padx=2, pady=2) #user input frame - self.input_frame = tk.LabelFrame(self.pg1_frame, text="Inputs", bd=2, relief='sunken', padx=5, pady=5) + self.input_frame = tk.LabelFrame(self.pg1_frame, text="Inputs", bd=2, relief='sunken', padx=2, pady=2, font=helv) #Wall Geometry Frame - self.geo_frame = tk.LabelFrame(self.input_frame, text="Wall Stud Geometry: ", bd=2, relief='sunken', padx=5, pady=5) + self.geo_frame = tk.LabelFrame(self.input_frame, text="Wall Stud Geometry: ", bd=2, relief='sunken', padx=2, pady=2, font=helv) #stud dimensions - nominal - tk.Label(self.geo_frame, text='Nominal Stud Size:').grid(row=1,column=1) + tk.Label(self.geo_frame, text='Nominal Stud Size:', font=helv).grid(row=1,column=1) self.b_nom = tk.StringVar() self.b_nom.set('2') self.b_nom_selection = tk.OptionMenu(self.geo_frame, self.b_nom, '2','3','4','(2)2','(3)2', command=self.actual_stud_size) self.b_nom_selection.grid(row=2,column=1) - tk.Label(self.geo_frame, text='x').grid(row=2,column=2) + tk.Label(self.geo_frame, text='x', font=helv).grid(row=2,column=2) self.d_nom = tk.StringVar() self.d_nom.set('6') self.d_nom_selection = tk.OptionMenu(self.geo_frame, self.d_nom, '3','4','5','6','8','10','12','14','16', command=self.actual_stud_size) self.d_nom_selection.grid(row=2,column=3) #stud dimensions - actual - tk.Label(self.geo_frame, text='Actual Stud Size:').grid(row=1,column=4) - self.b_actual_label = tk.Label(self.geo_frame, text='1.5') + tk.Label(self.geo_frame, text='Actual Stud Size:', font=helv).grid(row=1,column=4) + self.b_actual_label = tk.Label(self.geo_frame, text='1.5', font=helv) self.b_actual_label.grid(row=2,column=4) - tk.Label(self.geo_frame, text='x').grid(row=2,column=5) - self.d_actual_label = tk.Label(self.geo_frame, text='5.5') + tk.Label(self.geo_frame, text='x', font=helv).grid(row=2,column=5) + self.d_actual_label = tk.Label(self.geo_frame, text='5.5', font=helv) self.d_actual_label.grid(row=2,column=6) #stud Spacing - self.spacing_label = tk.Label(self.geo_frame, text='Stud Spacing: ') + self.spacing_label = tk.Label(self.geo_frame, text='Stud Spacing: ', font=helv) self.spacing_label.grid(row=3,column=1, sticky=tk.E) self.stud_spacing = tk.StringVar() - self.spacing_entry = tk.Entry(self.geo_frame, textvariable=self.stud_spacing, width=10) + self.stud_spacing.set('16') + self.spacing_entry = tk.Entry(self.geo_frame, textvariable=self.stud_spacing, width=10, font=helv) self.spacing_entry.grid(row=3,column=2, sticky=tk.W) - tk.Label(self.geo_frame, text='in').grid(row=3,column=3) + tk.Label(self.geo_frame, text='in', font=helv).grid(row=3,column=3) #Wall Height - self.height_label = tk.Label(self.geo_frame, text='Wall Height: ') + self.height_label = tk.Label(self.geo_frame, text='Wall Height: ', font=helv) self.height_label.grid(row=4,column=1, sticky=tk.E) self.wall_height = tk.StringVar() - self.height_entry = tk.Entry(self.geo_frame, textvariable=self.wall_height, width=10) + self.wall_height.set('10') + self.height_entry = tk.Entry(self.geo_frame, textvariable=self.wall_height, width=10, font=helv) self.height_entry.grid(row=4,column=2, sticky=tk.W) - tk.Label(self.geo_frame, text='ft').grid(row=4,column=3) + tk.Label(self.geo_frame, text='ft', font=helv).grid(row=4,column=3) #subtract wall plates from height self.sub_plates = tk.IntVar() - tk.Checkbutton(self.geo_frame, text=': Subtract Wall Plates from Height (y/n)', variable=self.sub_plates).grid(row=3, column=4, sticky=tk.W) - self.plates_label = tk.Label(self.geo_frame, text='# of 1.5" Plates to subtract: ') + tk.Checkbutton(self.geo_frame, text=': Subtract Wall Plates from Height (y/n)', variable=self.sub_plates, font=helv).grid(row=3, column=4, sticky=tk.W) + self.plates_label = tk.Label(self.geo_frame, text='# of 1.5" Plates to subtract: ', font=helv) self.plates_label.grid(row=4,column=4, sticky=tk.E) self.num_plates = tk.StringVar() self.num_plates.set(0) - self.num_plates_entry = tk.Entry(self.geo_frame, textvariable=self.num_plates, width=5) + self.num_plates_entry = tk.Entry(self.geo_frame, textvariable=self.num_plates, width=5, font=helv) self.num_plates_entry.grid(row=4,column=5, sticky=tk.W) #Consider plate crushing for common capacities self.consider_crushing = tk.IntVar() - tk.Checkbutton(self.geo_frame, text=': Consider plate crushing for common capacities (y/n)', variable=self.consider_crushing).grid(row=5, column=4, sticky=tk.W) + tk.Checkbutton(self.geo_frame, text=': Consider plate crushing for common capacities (y/n)', variable=self.consider_crushing, font=helv).grid(row=5, column=4, sticky=tk.W) - self.geo_frame.pack(fill=tk.X, padx=5, pady=5) + self.geo_frame.pack(fill=tk.X, padx=2, pady=2) #Reference Stud Design Values - Frame - self.ref_stud_properties_frame = tk.LabelFrame(self.input_frame, text="Reference Stud Design Values : ", bd=2, relief='sunken', padx=5, pady=5) + self.ref_stud_properties_frame = tk.LabelFrame(self.input_frame, text="Reference Stud Design Values : ", bd=2, relief='sunken', padx=2, pady=2, font=helv) #Wall Stud Grade - self.grade_label = tk.Label(self.ref_stud_properties_frame,text = 'Grade :') + self.grade_label = tk.Label(self.ref_stud_properties_frame,text = 'Grade :', font=helv) self.grade_label.grid(row=1, column=1, sticky=tk.E) self.grade = tk.StringVar() self.grade.set('No.1/No.2') @@ -133,144 +149,147 @@ def __init__(self, master): self.grade_selection.grid(row=1,column=2) #Fb - self.fb_label = tk.Label(self.ref_stud_properties_frame,text = 'Fb :') + self.fb_label = tk.Label(self.ref_stud_properties_frame,text = 'Fb :', font=helv) self.fb_label.grid(row=2, column=1, sticky=tk.E) self.fb_psi = tk.StringVar() self.fb_psi.set(875) - self.fb_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.fb_psi, width=10) + self.fb_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.fb_psi, width=10, font=helv) self.fb_entry.grid(row=2, column=2, sticky=tk.W) - tk.Label(self.ref_stud_properties_frame, text='psi').grid(row=2,column=3, sticky=tk.W) + tk.Label(self.ref_stud_properties_frame, text='psi', font=helv).grid(row=2,column=3, sticky=tk.W) #Fv - self.fv_label = tk.Label(self.ref_stud_properties_frame,text = 'Fv :') + self.fv_label = tk.Label(self.ref_stud_properties_frame,text = 'Fv :', font=helv) self.fv_label.grid(row=3, column=1, sticky=tk.E) self.fv_psi = tk.StringVar() self.fv_psi.set(135) - self.fv_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.fv_psi, width=10) + self.fv_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.fv_psi, width=10, font=helv) self.fv_entry.grid(row=3, column=2, sticky=tk.W) - tk.Label(self.ref_stud_properties_frame, text='psi').grid(row=3,column=3, sticky=tk.W) + tk.Label(self.ref_stud_properties_frame, text='psi', font=helv).grid(row=3,column=3, sticky=tk.W) #Fc - self.fc_label = tk.Label(self.ref_stud_properties_frame,text = 'Fc :') + self.fc_label = tk.Label(self.ref_stud_properties_frame,text = 'Fc :', font=helv) self.fc_label.grid(row=4, column=1, sticky=tk.E) self.fc_psi = tk.StringVar() self.fc_psi.set(1150) - self.fc_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.fc_psi, width=10) + self.fc_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.fc_psi, width=10, font=helv) self.fc_entry.grid(row=4, column=2, sticky=tk.W) - tk.Label(self.ref_stud_properties_frame, text='psi').grid(row=4,column=3, sticky=tk.W) + tk.Label(self.ref_stud_properties_frame, text='psi', font=helv).grid(row=4,column=3, sticky=tk.W) #E - self.E_label = tk.Label(self.ref_stud_properties_frame,text = 'E :') + self.E_label = tk.Label(self.ref_stud_properties_frame,text = 'E :', font=helv) self.E_label.grid(row=5, column=1, sticky=tk.E) self.E_psi = tk.StringVar() self.E_psi.set(1400000) - self.E_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.E_psi, width=15) + self.E_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.E_psi, width=15, font=helv) self.E_entry.grid(row=5, column=2, sticky=tk.W) - tk.Label(self.ref_stud_properties_frame, text='psi').grid(row=5,column=3, sticky=tk.W) + tk.Label(self.ref_stud_properties_frame, text='psi', font=helv).grid(row=5,column=3, sticky=tk.W) #Emin - self.Emin_label = tk.Label(self.ref_stud_properties_frame,text = 'Emin :') + self.Emin_label = tk.Label(self.ref_stud_properties_frame,text = 'Emin :', font=helv) self.Emin_label.grid(row=6, column=1, sticky=tk.E) self.Emin_psi = tk.StringVar() self.Emin_psi.set(510000) - self.Emin_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.Emin_psi, width=15) + self.Emin_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.Emin_psi, width=15, font=helv) self.Emin_entry.grid(row=6, column=2, sticky=tk.W) - tk.Label(self.ref_stud_properties_frame, text='psi').grid(row=6,column=3, sticky=tk.W) + tk.Label(self.ref_stud_properties_frame, text='psi', font=helv).grid(row=6,column=3, sticky=tk.W) #Fc_perp_pl - self.fc_perp_label = tk.Label(self.ref_stud_properties_frame,text = 'Fc_perp,bottom pl :') + self.fc_perp_label = tk.Label(self.ref_stud_properties_frame,text = 'Fc_perp,bottom pl :', font=helv) self.fc_perp_label.grid(row=7, column=1, sticky=tk.E) self.fc_perp_psi = tk.StringVar() self.fc_perp_psi.set(425) - self.fc_perp_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.fc_perp_psi, width=10) + self.fc_perp_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.fc_perp_psi, width=10, font=helv) self.fc_perp_entry.grid(row=7, column=2, sticky=tk.W) - tk.Label(self.ref_stud_properties_frame, text='psi').grid(row=7,column=3, sticky=tk.W) + tk.Label(self.ref_stud_properties_frame, text='psi', font=helv).grid(row=7,column=3, sticky=tk.W) #FRT? self.frt_yn = tk.IntVar() - tk.Checkbutton(self.ref_stud_properties_frame, text=': FRT (y/n)', variable=self.frt_yn).grid(row=1, column=4) - self.frt_fb_label = tk.Label(self.ref_stud_properties_frame,text = 'Cfrt,fb :') + tk.Checkbutton(self.ref_stud_properties_frame, text=': FRT (y/n)', variable=self.frt_yn, font=helv).grid(row=1, column=4) + self.frt_fb_label = tk.Label(self.ref_stud_properties_frame,text = 'Cfrt,fb :', font=helv) self.frt_fb_label.grid(row=2,column=4, sticky=tk.E) self.frt_fb = tk.StringVar() self.frt_fb.set(0.88) - self.frt_fb_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.frt_fb, width=10) + self.frt_fb_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.frt_fb, width=10, font=helv) self.frt_fb_entry.grid(row=2,column=5, sticky=tk.W) - self.frt_fv_label = tk.Label(self.ref_stud_properties_frame,text = 'Cfrt,fv :') + self.frt_fv_label = tk.Label(self.ref_stud_properties_frame,text = 'Cfrt,fv :', font=helv) self.frt_fv_label.grid(row=3,column=4, sticky=tk.E) self.frt_fv = tk.StringVar() self.frt_fv.set(0.93) - self.frt_fv_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.frt_fv, width=10) + self.frt_fv_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.frt_fv, width=10, font=helv) self.frt_fv_entry.grid(row=3,column=5, sticky=tk.W) - self.frt_fc_label = tk.Label(self.ref_stud_properties_frame,text = 'Cfrt,fc :') + self.frt_fc_label = tk.Label(self.ref_stud_properties_frame,text = 'Cfrt,fc :', font=helv) self.frt_fc_label.grid(row=4,column=4, sticky=tk.E) self.frt_fc = tk.StringVar() self.frt_fc.set(0.94) - self.frt_fc_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.frt_fc, width=10) + self.frt_fc_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.frt_fc, width=10, font=helv) self.frt_fc_entry.grid(row=4,column=5, sticky=tk.W) - self.frt_fc_perp_label = tk.Label(self.ref_stud_properties_frame,text = 'Cfrt,fc_perp :') + self.frt_fc_perp_label = tk.Label(self.ref_stud_properties_frame,text = 'Cfrt,fc_perp :', font=helv) self.frt_fc_perp_label.grid(row=5,column=4, sticky=tk.E) self.frt_fc_perp = tk.StringVar() self.frt_fc_perp.set(0.95) - self.frt_fc_perp_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.frt_fc_perp, width=10) + self.frt_fc_perp_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.frt_fc_perp, width=10, font=helv) self.frt_fc_perp_entry.grid(row=5,column=5, sticky=tk.W) - self.frt_E_label = tk.Label(self.ref_stud_properties_frame,text = 'Cfrt,E :') + self.frt_E_label = tk.Label(self.ref_stud_properties_frame,text = 'Cfrt,E :', font=helv) self.frt_E_label.grid(row=6,column=4, sticky=tk.E) self.frt_E = tk.StringVar() self.frt_E.set(0.94) - self.frt_E_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.frt_E, width=10) + self.frt_E_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.frt_E, width=10, font=helv) self.frt_E_entry.grid(row=6,column=5, sticky=tk.W) - self.frt_Emin_label = tk.Label(self.ref_stud_properties_frame,text = 'Cfrt,Emin :') + self.frt_Emin_label = tk.Label(self.ref_stud_properties_frame,text = 'Cfrt,Emin :', font=helv) self.frt_Emin_label.grid(row=7,column=4, sticky=tk.E) self.frt_Emin = tk.StringVar() self.frt_Emin.set(0.94) - self.frt_Emin_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.frt_Emin, width=10) + self.frt_Emin_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.frt_Emin, width=10, font=helv) self.frt_Emin_entry.grid(row=7,column=5, sticky=tk.W) - self.species_label = tk.Label(self.ref_stud_properties_frame,text = 'Species :') + self.species_label = tk.Label(self.ref_stud_properties_frame,text = 'Species :', font=helv) self.species_label.grid(row=8,column=1, sticky=tk.E) self.species = tk.StringVar() self.species.set('Spruce-Pine-Fur') - self.species_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.species, width=50) + self.species_entry = tk.Entry(self.ref_stud_properties_frame, textvariable=self.species, width=50, font=helv) self.species_entry.grid(row=8,column=2,columnspan=3) - self.ref_stud_properties_frame.pack(fill=tk.X, padx=5, pady=5) + self.is_syp = tk.IntVar() + tk.Checkbutton(self.ref_stud_properties_frame, text=': Southern Pine (y/n)', variable=self.is_syp, font=helv).grid(row=8, column=5) + + self.ref_stud_properties_frame.pack(fill=tk.X, padx=2, pady=2) - self.enviro_treatment_frame = tk.LabelFrame(self.input_frame, text="Enviroment and Treatment : ", bd=2, relief='sunken', padx=5, pady=5) + self.enviro_treatment_frame = tk.LabelFrame(self.input_frame, text="Enviroment and Treatment : ", bd=2, relief='sunken', padx=2, pady=2, font=helv) #Moisture % - self.moisture_label = tk.Label(self.enviro_treatment_frame,text = 'Moisture % :') + self.moisture_label = tk.Label(self.enviro_treatment_frame,text = 'Moisture % :', font=helv) self.moisture_label.grid(row=1,column=1, sticky=tk.E) self.moisture = tk.StringVar() self.moisture.set(19.0) - self.moisture_entry = tk.Entry(self.enviro_treatment_frame, textvariable=self.moisture, width=10) + self.moisture_entry = tk.Entry(self.enviro_treatment_frame, textvariable=self.moisture, width=10, font=helv) self.moisture_entry.grid(row=1,column=2, sticky=tk.W) #Temp F - self.temp_label = tk.Label(self.enviro_treatment_frame,text = 'Temperature (F) - <= 150 :') + self.temp_label = tk.Label(self.enviro_treatment_frame,text = 'Temperature (F) - <= 150 :', font=helv) self.temp_label.grid(row=2,column=1, sticky=tk.E) self.temp = tk.StringVar() self.temp.set(90.0) - self.temp_entry = tk.Entry(self.enviro_treatment_frame, textvariable=self.temp, width=10) + self.temp_entry = tk.Entry(self.enviro_treatment_frame, textvariable=self.temp, width=10, font=helv) self.temp_entry.grid(row=2,column=2, sticky=tk.W) #Incised? self.incised_yn = tk.IntVar() - tk.Checkbutton(self.enviro_treatment_frame, text=': Incised (y/n)', variable=self.incised_yn).grid(row=3, column=1, sticky=tk.W) + tk.Checkbutton(self.enviro_treatment_frame, text=': Incised (y/n)', variable=self.incised_yn, font=helv).grid(row=3, column=1, sticky=tk.W) - self.enviro_treatment_frame.pack(fill=tk.X, padx=5, pady=5) + self.enviro_treatment_frame.pack(fill=tk.X, padx=2, pady=2) - self.lateral_frame = tk.LabelFrame(self.input_frame, text="Lateral Pressure : ", bd=2, relief='sunken', padx=5, pady=5) + self.lateral_frame = tk.LabelFrame(self.input_frame, text="Lateral Pressure : ", bd=2, relief='sunken', padx=2, pady=2, font=helv) #Pressure - self.pressure_label = tk.Label(self.lateral_frame,text = 'Pressure (psf) :') + self.pressure_label = tk.Label(self.lateral_frame,text = 'Pressure (psf) :', font=helv) self.pressure_label.grid(row=1,column=1, sticky=tk.E) self.pressure = tk.StringVar() self.pressure.set("5.0") - self.pressure_entry = tk.Entry(self.lateral_frame, textvariable=self.pressure, width=10) + self.pressure_entry = tk.Entry(self.lateral_frame, textvariable=self.pressure, width=10, font=helv) self.pressure_entry.grid(row=1,column=2, sticky=tk.W) #Cd - self.cd_label = tk.Label(self.lateral_frame,text = 'Cd :') + self.cd_label = tk.Label(self.lateral_frame,text = 'Cd :', font=helv) self.cd_label.grid(row=2,column=1, sticky=tk.E) self.cd = tk.StringVar() self.cd.set('1.0') @@ -280,21 +299,21 @@ def __init__(self, master): #Min Eccentricity? self.min_ecc_yn = tk.IntVar() - tk.Checkbutton(self.lateral_frame, text=': Min. Eccentricty of d/6 (y/n)', variable=self.min_ecc_yn).grid(row=3, column=1, sticky=tk.W) + tk.Checkbutton(self.lateral_frame, text=': Min. Eccentricty of d/6 (y/n)', variable=self.min_ecc_yn, font=helv).grid(row=3, column=1, sticky=tk.W) #Stud Lateral Braced on Compression Face self.com_lat_brace_yn = tk.IntVar() self.com_lat_brace_yn.set(1) - tk.Checkbutton(self.lateral_frame, text=': Stud laterally braced on compression face (y/n)', variable=self.com_lat_brace_yn, command=self.com_lat_brace_func).grid(row=4, column=1, sticky=tk.W) + tk.Checkbutton(self.lateral_frame, text=': Stud laterally braced on compression face (y/n)', variable=self.com_lat_brace_yn, command=self.com_lat_brace_func, font=helv).grid(row=4, column=1, sticky=tk.W) self.no_sheathing_yn = tk.IntVar() self.no_sheathing_yn.set(0) - tk.Checkbutton(self.lateral_frame, text=': No Sheathing (y/n)', variable=self.no_sheathing_yn, command=self.no_sheating_func).grid(row=5, column=1, sticky=tk.W) - self.blocking_label = tk.Label(self.lateral_frame, text = 'Blocking (ft):').grid(row=6, column=1, sticky=tk.E) + tk.Checkbutton(self.lateral_frame, text=': No Sheathing (y/n)', variable=self.no_sheathing_yn, command=self.no_sheating_func, font=helv).grid(row=5, column=1, sticky=tk.W) + self.blocking_label = tk.Label(self.lateral_frame, text = 'Blocking (ft):', font=helv).grid(row=6, column=1, sticky=tk.E) self.blocking_ft = tk.StringVar() self.blocking_ft.set("4.0") - self.blocking_entry = tk.Entry(self.lateral_frame, textvariable = self.blocking_ft, width=10) + self.blocking_entry = tk.Entry(self.lateral_frame, textvariable = self.blocking_ft, width=10, font=helv) self.blocking_entry.grid(row=6, column=2) - self.lateral_frame.pack(fill=tk.X, padx=5, pady=5) + self.lateral_frame.pack(fill=tk.X, padx=2, pady=2) self.b_run = tk.Button(self.input_frame,text="Calc", command=self.run, font=helv) self.b_run.pack(side=tk.RIGHT) @@ -303,11 +322,11 @@ def __init__(self, master): self.b_build_pm = tk.Button(self.input_frame,text="Build P-M Chart", command=self.generate_pm_graph, font=helv, state = tk.DISABLED) self.b_build_pm.pack(side=tk.RIGHT) - self.input_frame.pack(side=tk.LEFT, padx=5, pady=5) + self.input_frame.pack(side=tk.LEFT, padx=2, pady=2) #results frame - self.results_frame = tk.LabelFrame(self.pg1_frame, text="Results", bd=2, relief='sunken', padx=5, pady=5) - self.nds_table_frame = tk.LabelFrame(self.results_frame, text="NDS 2005 - Table 4.3.1", bd=2, relief='sunken', padx=5, pady=5) + self.results_frame = tk.LabelFrame(self.pg1_frame, text="Results", bd=2, relief='sunken', padx=2, pady=2) + self.nds_table_frame = tk.LabelFrame(self.results_frame, text="NDS 2005 - Table 4.3.1", bd=2, relief='sunken', padx=2, pady=2) self.res_labels = [] self.res_nds_table_output = [] for y in range(0,7): @@ -342,13 +361,18 @@ def __init__(self, master): self.res_labels[i].configure(text='psi') self.res_nds_table_output[i] = 'psi\n' i+=16 - self.nds_table_frame.pack(side=tk.TOP, padx=5, pady=5) + self.nds_table_frame.pack(side=tk.TOP, padx=2, pady=2) ## Text Results Frame self.text_results_frame = tk.LabelFrame(self.results_frame, text="Calculation Results: ", bd=2, relief='sunken', padx=2, pady=2, font=helv) self.results_text_box = tk.Text(self.text_results_frame, height = 10, width = 10, bg= "grey90", font= tkFont.Font(family='Helvetica',size=8, weight='normal'), wrap=tk.WORD) - self.results_text_box.pack(side=tk.TOP, fill=tk.BOTH, expand=True) + self.results_text_box.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + + self.restxt_scroll = tk.Scrollbar(self.text_results_frame, command=self.results_text_box.yview) + self.restxt_scroll.pack(side=tk.LEFT, fill=tk.Y) + + self.results_text_box['yscrollcommand'] = self.restxt_scroll.set self.text_results_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True) self.b_output_res= tk.Button(self.results_frame,text="Export Results", command=self.write_text_results_to_file, font=helv, state = tk.DISABLED) @@ -357,16 +381,16 @@ def __init__(self, master): self.b_output_pp.pack(side=tk.RIGHT) self.b_output_pm= tk.Button(self.results_frame,text="Export P-M Curves", command=self.print_pm_graph_common, font=helv, state = tk.DISABLED) self.b_output_pm.pack(side=tk.RIGHT) - self.results_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5) + self.results_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=2, pady=2) #Tab 2 -P vs Pressure Curve self.page2 = ttk.Frame(self.nb) self.nb.add(self.page2, text='P-Lateral Pressure Diagram', state = tk.DISABLED) self.pg2_frame = tk.Frame(self.page2, bd=2, relief='sunken', padx=1,pady=1) - self.pg2_frame.pack(fill=tk.BOTH,expand=1, padx=5, pady=5) + self.pg2_frame.pack(fill=tk.BOTH,expand=1, padx=2, pady=2) - self.chart_frame = tk.Frame(self.pg2_frame, padx=5, pady=5) + self.chart_frame = tk.Frame(self.pg2_frame, padx=2, pady=2) self.Fig = matplotlib.figure.Figure(figsize=(12,6),dpi=96) self.ax1 = self.Fig.add_subplot(111) @@ -417,9 +441,9 @@ def __init__(self, master): self.nb.add(self.page3, text='P-M Diagram', state = tk.DISABLED) self.pg3_frame = tk.Frame(self.page3, bd=2, relief='sunken', padx=1,pady=1) - self.pg3_frame.pack(fill=tk.BOTH,expand=1, padx=5, pady=5) + self.pg3_frame.pack(fill=tk.BOTH,expand=1, padx=2, pady=2) - self.chart_frameB = tk.Frame(self.pg3_frame, padx=5, pady=5) + self.chart_frameB = tk.Frame(self.pg3_frame, padx=2, pady=2) self.FigB = matplotlib.figure.Figure(figsize=(12,6),dpi=96) self.ax1B = self.FigB.add_subplot(111) @@ -471,9 +495,9 @@ def __init__(self, master): self.nb.add(self.page4, text='P-M Diagram - Stud', state = tk.DISABLED) self.pg4_frame = tk.Frame(self.page4, bd=2, relief='sunken', padx=1,pady=1) - self.pg4_frame.pack(fill=tk.BOTH,expand=1, padx=5, pady=5) + self.pg4_frame.pack(fill=tk.BOTH,expand=1, padx=2, pady=2) - self.chart_frameD = tk.Frame(self.pg4_frame, padx=5, pady=5) + self.chart_frameD = tk.Frame(self.pg4_frame, padx=2, pady=2) self.FigD = matplotlib.figure.Figure(figsize=(12,6),dpi=96) self.ax1D = self.FigD.add_subplot(111) @@ -528,11 +552,11 @@ def __init__(self, master): self.nb.add(self.page5, text='User Loads', state = tk.DISABLED) self.pg5_frame = tk.Frame(self.page5, bd=2, relief='sunken', padx=1,pady=1) - self.pg5_frame.pack(fill=tk.BOTH,expand=1, padx=5, pady=5) + self.pg5_frame.pack(fill=tk.BOTH,expand=1, padx=2, pady=2) #user Loads input frame self.user_ins_top_frame = tk.Frame(self.pg5_frame) - self.input_frame_loads = tk.LabelFrame(self.user_ins_top_frame, text="Loads Inputs (IBC 2012):", bd=2, relief='sunken', padx=5, pady=5) + self.input_frame_loads = tk.LabelFrame(self.user_ins_top_frame, text="Loads Inputs (IBC 2012):", bd=2, relief='sunken', padx=2, pady=2) #Vertical Loads - [DL,LL,Lr,S,R] tk.Label(self.input_frame_loads, text='Vertical Loads: ').grid(column=1, row=1) self.user_vert_load_labels = ['D: ','L: ','Lr: ','S: ','R: '] @@ -582,10 +606,10 @@ def __init__(self, master): tk.Entry(self.input_frame_loads, textvariable=load, width=15).grid(column=8, row=i+1) i+=1 - self.input_frame_loads.pack(side=tk.LEFT, padx=5, pady=5) + self.input_frame_loads.pack(side=tk.LEFT, padx=2, pady=2) #user Loads input frame - self.input_frame_user_wall = tk.LabelFrame(self.user_ins_top_frame, text="Wall Information:", bd=2, relief='sunken', padx=5, pady=5) + self.input_frame_user_wall = tk.LabelFrame(self.user_ins_top_frame, text="Wall Information:", bd=2, relief='sunken', padx=2, pady=2) tk.Label(self.input_frame_user_wall, text='Wall Height: ').grid(column=1, row=1) self.user_calc_wall_ht_ft = tk.Label(self.input_frame_user_wall, text='--') self.user_calc_wall_ht_ft.grid(column=2, row=1) @@ -605,10 +629,10 @@ def __init__(self, master): self.b_user_export = tk.Button(self.input_frame_user_wall,text="Export User Load Results", command=self.export_user_load_results, font=helv) self.b_user_export.grid(column=4, row = 3, padx=10) - self.input_frame_user_wall.pack(side=tk.LEFT, padx=5, pady=5) + self.input_frame_user_wall.pack(side=tk.LEFT, padx=2, pady=2) self.user_ins_top_frame.pack(side=tk.TOP) - self.user_res_bottom_frame = tk.LabelFrame(self.pg5_frame, text="Results (IBC 2012 - ASD):", bd=2, relief='sunken', padx=5, pady=5) + self.user_res_bottom_frame = tk.LabelFrame(self.pg5_frame, text="Results (IBC 2012 - ASD):", bd=2, relief='sunken', padx=2, pady=2) res_headings = ['Combo:','Cd','P (lbs)', 'fc (psi)','Ke Le_d/d','FcE (psi)','c','Cp',"Fc' (psi)","fc/Fc'",'M_lat (in-lbs)','fb_lat (psi)',"Fb' (psi)","fb/Fb'",'V (lbs)','fv (psi)',"Fv' (psi)","fv/Fv'",'Ratio','D (H/--)','Status'] self.load_combos = [['D',0.9,1,0,0,0,0,0], ['D+L',1,1,1,0,0,0,0], @@ -702,20 +726,20 @@ def __init__(self, master): self.license_display() def license_display(self, *event): - license_string = ("This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n\n" - - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n\n" - - "You should have received a copy of the GNU General Public License along" - "with this program; if not, write to the Free Software Foundation, Inc.," - "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" - "\nA copy of the License can be viewed at:\n https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE") + license_string = ("Copyright (c) 2019, Donald N. Bockoven III\n" + "All rights reserved.\n\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" + " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" + " IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" + " DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" + " FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" + " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" + " SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" + " CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," + " OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + " OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n" + "https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE" + ) tkMessageBox.showerror("License Information",license_string) self.master.focus_force() @@ -806,7 +830,7 @@ def run(self, *event): self.e_in = 0 e_string ='' - self.wall = wood.wood_stud_wall(b,d,height,spacing,grade,fb,fv,fc,E,Emin,fc_perp,moisture,temp,incise,num_pl, cfrt, self.com_lat_brace_yn.get(), float(self.blocking_ft.get()), self.no_sheathing_yn.get()) + self.wall = wood.wood_stud_wall(b,d,height,spacing,grade,fb,fv,fc,E,Emin,fc_perp,moisture,temp,incise,num_pl, cfrt, self.com_lat_brace_yn.get(), float(self.blocking_ft.get()), self.no_sheathing_yn.get(),self.is_syp.get()) pressure_psf = float(self.pressure.get()) @@ -2016,7 +2040,7 @@ def main(): root = tk.Tk() root.title("Wood Stud Wall - 2-4x Studs - North American Species (Not Southern Pine) - V0.9 BETA") Master_window(root) - root.minsize(1024,768) + root.minsize(1024,700) root.mainloop() if __name__ == '__main__': diff --git a/images/frame_2d.gif b/images/frame_2d.gif new file mode 100644 index 0000000..10654aa Binary files /dev/null and b/images/frame_2d.gif differ diff --git a/images/frame_2d.webm b/images/frame_2d.webm new file mode 100644 index 0000000..0ff51d4 Binary files /dev/null and b/images/frame_2d.webm differ diff --git a/images/frame_2d_windows.gif b/images/frame_2d_windows.gif new file mode 100644 index 0000000..7ea6458 Binary files /dev/null and b/images/frame_2d_windows.gif differ diff --git a/strap_beam_gui.py b/strap_beam_gui.py index 0f1ec23..6bc814f 100644 --- a/strap_beam_gui.py +++ b/strap_beam_gui.py @@ -1,23 +1,28 @@ -# -*- coding: utf-8 -*- -""" -Created on Wed May 30 23:36:44 2018 - -@author: donnieb -""" - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +''' +BSD 3-Clause License +Copyright (c) 2019, Donald N. Bockoven III +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +''' from __future__ import division import math as m @@ -25,11 +30,11 @@ import Concrete.concrete_beam_classes as concbeam from numpy import zeros import numpy as np -import Tkinter as tk -import tkMessageBox -import ttk -import tkFont -import tkFileDialog +import tkinter as tk +import tkinter.ttk as ttk +import tkinter.font as tkFont +import tkinter.messagebox as tkMessageBox +import tkinter.filedialog as tkFileDialog class main_window: @@ -355,20 +360,21 @@ def __init__(self, master): self.license_display() def license_display(self, *event): - license_string = ("This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n\n" - - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n\n" - - "You should have received a copy of the GNU General Public License along" - "with this program; if not, write to the Free Software Foundation, Inc.," - "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" - "\nA copy of the License can be viewed at:\n https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE") + license_string = ( +"""Copyright (c) 2019, Donald N. Bockoven III\n +All rights reserved.\n\n +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n +https://github.com/buddyd16/Structural-Engineering/blob/master/LICENSE""" +) tkMessageBox.showerror("License Information",license_string) self.master.focus_force()