diff --git a/docs/source/conf.py b/docs/source/conf.py index 01b2ea3d..2009e4bf 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -10,7 +10,7 @@ import locale -locale.setlocale(locale.LC_ALL, '') +locale.setlocale(locale.LC_ALL, "") # -- Path setup -------------------------------------------------------------- @@ -50,10 +50,10 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.mathjax', - 'sphinx.ext.viewcode', - 'sphinx_gallery.gen_gallery', + "sphinx.ext.autodoc", + "sphinx.ext.mathjax", + "sphinx.ext.viewcode", + "sphinx_gallery.gen_gallery", ] # Add any paths that contain templates here, relative to this directory. @@ -181,23 +181,23 @@ sphinx_gallery_conf = { # convert rst to md for ipynb - 'pypandoc': False, + "pypandoc": False, # path to your examples scripts - 'examples_dirs': ['../../examples/'], + "examples_dirs": ["../../examples/"], # path where to save gallery generated examples - 'gallery_dirs': ['sphinx_gallery_examples'], + "gallery_dirs": ["sphinx_gallery_examples"], # Patter to search for example files - 'filename_pattern': r'\.py', + "filename_pattern": r"\.py", # Remove the 'Download all examples' button from the top level gallery - 'download_all_examples': False, + "download_all_examples": False, # Sort gallery example by file name instead of number of lines (default) - 'within_subsection_order': FileNameSortKey, + "within_subsection_order": FileNameSortKey, # directory where function granular galleries are stored - 'backreferences_dir': None, + "backreferences_dir": None, # Modules for which function level galleries are created. In - 'doc_module': 'sectionproperties', - 'image_scrapers': ('matplotlib',), - 'first_notebook_cell': ('%matplotlib inline\n'), + "doc_module": "sectionproperties", + "image_scrapers": ("matplotlib",), + "first_notebook_cell": ("%matplotlib inline\n"), } # sphinx_gallery_conf = { diff --git a/docs/source/images/sections/concrete_circular_section_geometry.png b/docs/source/images/sections/concrete_circular_section_geometry.png new file mode 100644 index 00000000..68a8c2bd Binary files /dev/null and b/docs/source/images/sections/concrete_circular_section_geometry.png differ diff --git a/docs/source/images/sections/concrete_circular_section_mesh.png b/docs/source/images/sections/concrete_circular_section_mesh.png new file mode 100644 index 00000000..5822226c Binary files /dev/null and b/docs/source/images/sections/concrete_circular_section_mesh.png differ diff --git a/docs/source/images/sections/concrete_rectangular_section_geometry.png b/docs/source/images/sections/concrete_rectangular_section_geometry.png new file mode 100644 index 00000000..911bf328 Binary files /dev/null and b/docs/source/images/sections/concrete_rectangular_section_geometry.png differ diff --git a/docs/source/images/sections/concrete_rectangular_section_mesh.png b/docs/source/images/sections/concrete_rectangular_section_mesh.png new file mode 100644 index 00000000..9e133bd0 Binary files /dev/null and b/docs/source/images/sections/concrete_rectangular_section_mesh.png differ diff --git a/docs/source/images/sections/concrete_tee_section_geometry.png b/docs/source/images/sections/concrete_tee_section_geometry.png new file mode 100644 index 00000000..d86f310c Binary files /dev/null and b/docs/source/images/sections/concrete_tee_section_geometry.png differ diff --git a/docs/source/images/sections/concrete_tee_section_mesh.png b/docs/source/images/sections/concrete_tee_section_mesh.png new file mode 100644 index 00000000..35ba3504 Binary files /dev/null and b/docs/source/images/sections/concrete_tee_section_mesh.png differ diff --git a/docs/source/index.rst b/docs/source/index.rst index a781e588..8833b12d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -27,6 +27,7 @@ can be found in the README file on github. rst/installation rst/structure rst/geom_mesh + rst/section_library rst/advanced_geom rst/analysis rst/post @@ -36,14 +37,14 @@ can be found in the README file on github. Here's a quick example that harnesses some of the power of *sectionproperties* and shows its simplicity:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.steel_sections as steel_sections from sectionproperties.analysis.cross_section import Section # create geometry of the cross-section - geometry = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8) + geometry = steel_sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8) # generate a finite element mesh - geometry.create_mesh(mesh_sizes=[2.5]) + geometry.create_mesh(mesh_sizes=[10]) # create a Section object for analysis section = Section(geometry) @@ -58,9 +59,9 @@ Here's a quick example that harnesses some of the power of *sectionproperties* a print(section.get_ic()) # second moments of area about the centroidal axis >>>(23544664.29, 3063383.07, 0.00) print(section.get_j()) # torsion constant - >>>62907.79 + >>>62954.43 print(section.get_As()) # shear areas in the x & y directions - >>>(1842.17, 1120.18) + >>>(1842.24, 1120.19) Support ------- diff --git a/docs/source/rst/advanced_geom.rst b/docs/source/rst/advanced_geom.rst index 8f017f45..b9338c3b 100644 --- a/docs/source/rst/advanced_geom.rst +++ b/docs/source/rst/advanced_geom.rst @@ -24,10 +24,10 @@ Creating Merged Sections For this example, we will create a custom section out of two similar "I" sections:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.steel_sections as steel_sections import sectionproperties.analysis.cross_section as cross_section - i_sec1 = sections.i_section(d=250, b=150, t_f=13, t_w=10, r=12, n_r=12) + i_sec1 = steel_sections.i_section(d=250, b=150, t_f=13, t_w=10, r=12, n_r=12) i_sec2 = i_sec1.rotate_section(45) .. figure:: ../images/examples/i_sec1.png @@ -159,11 +159,11 @@ Another example Here, we will simply combine two squares with the default material:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.standard_sections as standard_sections from sectionproperties.analysis.cross_section import Section - s1 = sections.rectangular_section(1,1) - s2 = sections.rectangular_section(0.5,0.5).shift_section(1,0.25) + s1 = standard_sections.rectangular_section(1,1) + s2 = standard_sections.rectangular_section(0.5,0.5).shift_section(1,0.25) geometry = s1 + s2 geometry diff --git a/docs/source/rst/api.rst b/docs/source/rst/api.rst index 0ddb04d3..3c91530b 100644 --- a/docs/source/rst/api.rst +++ b/docs/source/rst/api.rst @@ -18,117 +18,186 @@ CompoundGeometry Class """""""""""""""""""""" .. autoclass:: sectionproperties.pre.sections.CompoundGeometry :show-inheritance: - -*sections* Functions -^^^^^^^^^^^^^^^^^^^^^ + +load_dxf +"""""""" +.. autofunction:: sectionproperties.pre.sections.load_dxf + +create_facets +""""""""""""" +.. autofunction:: sectionproperties.pre.sections.create_facets + +create_exterior_points +"""""""""""""""""""""" +.. autofunction:: sectionproperties.pre.sections.create_exterior_points + +create_interior_points +"""""""""""""""""""""" +.. autofunction:: sectionproperties.pre.sections.create_interior_points + +create_points_and_facets +"""""""""""""""""""""""" +.. autofunction:: sectionproperties.pre.sections.create_points_and_facets + + +*pre* Module +^^^^^^^^^^^^ + +Material Class +"""""""""""""" + + .. autoclass:: sectionproperties.pre.pre.Material + :show-inheritance: + :members: + +create_mesh +""""""""""" +.. autofunction:: sectionproperties.pre.pre.create_mesh + + +*rhino* Module +^^^^^^^^^^^^^^ + +load_3dm +"""""""" +.. autofunction:: sectionproperties.pre.rhino.load_3dm + +load_brep_encoding +"""""""""""""""""" +.. autofunction:: sectionproperties.pre.rhino.load_brep_encoding + + +*bisect_section* Module +^^^^^^^^^^^^^^^^^^^^^^^ + +create_line_segment +""""""""""""""""""" +.. autofunction:: sectionproperties.pre.bisect_section.create_line_segment + +group_top_and_bottom_polys +"""""""""""""""""""""""""" +.. autofunction:: sectionproperties.pre.bisect_section.group_top_and_bottom_polys + +line_mx_plus_b +"""""""""""""" +.. autofunction:: sectionproperties.pre.bisect_section.line_mx_plus_b + +perp_mx_plus_b +"""""""""""""" +.. autofunction:: sectionproperties.pre.bisect_section.perp_mx_plus_b + +line_intersection +""""""""""""""""" +.. autofunction:: sectionproperties.pre.bisect_section.line_intersection + +sum_poly_areas +"""""""""""""" +.. autofunction:: sectionproperties.pre.bisect_section.sum_poly_areas + + +*standard_sections* Module +^^^^^^^^^^^^^^^^^^^^^^^^^^ rectangular_section """"""""""""""""""" -.. autofunction:: sectionproperties.pre.sections.rectangular_section - :noindex: +.. autofunction:: sectionproperties.pre.library.standard_sections.rectangular_section circular_section """""""""""""""" -.. autofunction:: sectionproperties.pre.sections.circular_section - :noindex: - -circular_hollow_section -""""""""""""""""""""""" -.. autofunction:: sectionproperties.pre.sections.circular_hollow_section - :noindex: +.. autofunction:: sectionproperties.pre.library.standard_sections.circular_section elliptical_section """""""""""""""""" -.. autofunction:: sectionproperties.pre.sections.elliptical_section - :noindex: +.. autofunction:: sectionproperties.pre.library.standard_sections.elliptical_section + +cruciform_section +"""""""""""""""""" + .. autofunction:: sectionproperties.pre.library.standard_sections.cruciform_section + + +*steel_sections* Module +^^^^^^^^^^^^^^^^^^^^^^^ + +circular_hollow_section +""""""""""""""""""""""" +.. autofunction:: sectionproperties.pre.library.steel_sections.circular_hollow_section elliptical_hollow_section """"""""""""""""""""""""" -.. autofunction:: sectionproperties.pre.sections.elliptical_hollow_section - :noindex: +.. autofunction:: sectionproperties.pre.library.steel_sections.elliptical_hollow_section rectangular_hollow_section """""""""""""""""""""""""" -.. autofunction:: sectionproperties.pre.sections.rectangular_hollow_section - :noindex: +.. autofunction:: sectionproperties.pre.library.steel_sections.rectangular_hollow_section + +polygon_hollow_section +""""""""""""""""""""""" + .. autofunction:: sectionproperties.pre.library.steel_sections.polygon_hollow_section i_section """"""""" - .. autofunction:: sectionproperties.pre.sections.i_section - :noindex: + .. autofunction:: sectionproperties.pre.library.steel_sections.i_section mono_i_section """""""""""""" - .. autofunction:: sectionproperties.pre.sections.mono_i_section - :noindex: + .. autofunction:: sectionproperties.pre.library.steel_sections.mono_i_section tapered_flange_i_section """""""""""""""""""""""" - .. autofunction:: sectionproperties.pre.sections.tapered_flange_i_section - :noindex: + .. autofunction:: sectionproperties.pre.library.steel_sections.tapered_flange_i_section channel_section """"""""""""""" - .. autofunction:: sectionproperties.pre.sections.channel_section - :noindex: + .. autofunction:: sectionproperties.pre.library.steel_sections.channel_section tapered_flange_channel """""""""""""""""""""" - .. autofunction:: sectionproperties.pre.sections.tapered_flange_channel - :noindex: + .. autofunction:: sectionproperties.pre.library.steel_sections.tapered_flange_channel tee_section """"""""""" - .. autofunction:: sectionproperties.pre.sections.tee_section - :noindex: + .. autofunction:: sectionproperties.pre.library.steel_sections.tee_section angle_section """""""""""""" - .. autofunction:: sectionproperties.pre.sections.angle_section - :noindex: + .. autofunction:: sectionproperties.pre.library.steel_sections.angle_section cee_section """""""""""" - .. autofunction:: sectionproperties.pre.sections.cee_section - :noindex: + .. autofunction:: sectionproperties.pre.library.steel_sections.cee_section zed_section """"""""""" - .. autofunction:: sectionproperties.pre.sections.zed_section - :noindex: - -cruciform_section -"""""""""""""""""" - .. autofunction:: sectionproperties.pre.sections.cruciform_section - :noindex: - -polygon_hollow_section -""""""""""""""""""""""" - .. autofunction:: sectionproperties.pre.sections.polygon_hollow_section - :noindex: + .. autofunction:: sectionproperties.pre.library.steel_sections.zed_section box_girder_section """"""""""""""""""" - .. autofunction:: sectionproperties.pre.sections.box_girder_section - :noindex: + .. autofunction:: sectionproperties.pre.library.steel_sections.box_girder_section -*pre* Module -^^^^^^^^^^^^ -Material Class -"""""""""""""" +*concrete_sections* Module +^^^^^^^^^^^^^^^^^^^^^^^^^^ - .. autoclass:: sectionproperties.pre.pre.Material - :show-inheritance: - :members: +concrete_rectangular_section +"""""""""""""""""""""""""""" +.. autofunction:: sectionproperties.pre.library.concrete_sections.concrete_rectangular_section -pre Functions -""""""""""""" +concrete_tee_section +"""""""""""""""""""" +.. autofunction:: sectionproperties.pre.library.concrete_sections.concrete_tee_section + +concrete_circular_section +""""""""""""""""""""""""" +.. autofunction:: sectionproperties.pre.library.concrete_sections.concrete_circular_section -create_mesh -"""""""""""" -.. autofunction:: sectionproperties.pre.pre.create_mesh +*bridge_sections* Module +^^^^^^^^^^^^^^^^^^^^^^^^ + +TBC + + +.. _label-nastran-sections: *nastran_sections* Module ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,127 +205,103 @@ This module contains sections as defined by Nastran and Nastran-based programs, such as MYSTRAN and ASTROS. nastran_bar -"""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_bar - :noindex: +""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_bar nastran_box -"""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_box - :noindex: +""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_box nastran_box1 -""""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_box1 - :noindex: +"""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_box1 nastran_chan -""""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_chan - :noindex: +"""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_chan nastran_chan1 -"""""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_chan1 - :noindex: +""""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_chan1 nastran_chan2 -"""""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_chan2 - :noindex: +""""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_chan2 nastran_cross -""""""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_cross - :noindex: +""""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_cross nastran_dbox -""""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_dbox - :noindex: +"""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_dbox nastran_fcross -""""""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_fcross - :noindex: +"""""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_fcross nastran_gbox -""""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_gbox - :noindex: +"""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_gbox nastran_h """""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_h - :noindex: +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_h nastran_hat -"""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_hat - :noindex: +""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_hat nastran_hat1 -""""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_hat1 - :noindex: +"""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_hat1 nastran_hexa -""""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_hexa - :noindex: +"""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_hexa nastran_i -""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_i - :noindex: +""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_i nastran_i1 -""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_i1 - :noindex: +"""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_i1 nastran_l -"""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_l - :noindex: +""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_l nastran_rod -"""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_rod - :noindex: +""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_rod nastran_tee -"""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_tee - :noindex: +""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_tee nastran_tee1 -""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_tee1 - :noindex: +"""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_tee1 nastran_tee2 -""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_tee2 - :noindex: +"""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_tee2 nastran_tube -""""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_tube - :noindex: +"""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_tube nastran_tube2 -"""""""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_tube2 - :noindex: +""""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_tube2 nastran_zed -"""""""""""""" -.. autofunction:: sectionproperties.pre.nastran_sections.nastran_zed - :noindex: +""""""""""" +.. autofunction:: sectionproperties.pre.library.nastran_sections.nastran_zed -References -"""""""""" +Nastran References +"""""""""""""""""" .. [1] MSC Nastran Quick Reference Guide 2012, PBEAML - Simple Beam Cross-Section Property, pp. 2890-2894 https://simcompanion.mscsoftware.com/infocenter/index?page=content&id=DOC10351 @@ -273,6 +318,7 @@ References Section 5.1.3.2, pp. 56 https://apps.dtic.mil/dtic/tr/fulltext/u2/a308134.pdf + Analysis Package ---------------- @@ -280,7 +326,7 @@ Analysis Package ^^^^^^^^^^^^^^^^^^^^^^ Section Class -"""""""""""""""""" +""""""""""""" .. autoclass:: sectionproperties.analysis.cross_section.Section :show-inheritance: @@ -331,38 +377,73 @@ Tri6 Class :show-inheritance: :members: -fea Functions -""""""""""""" - +gauss_points +"""""""""""" .. autofunction:: sectionproperties.analysis.fea.gauss_points + +shape_function +"""""""""""""" .. autofunction:: sectionproperties.analysis.fea.shape_function + +extrapolate_to_nodes +"""""""""""""""""""" .. autofunction:: sectionproperties.analysis.fea.extrapolate_to_nodes + +principal_coordinate +"""""""""""""""""""" .. autofunction:: sectionproperties.analysis.fea.principal_coordinate + +global_coordinate +""""""""""""""""" .. autofunction:: sectionproperties.analysis.fea.global_coordinate + +point_above_line +"""""""""""""""" .. autofunction:: sectionproperties.analysis.fea.point_above_line + *solver* Module ^^^^^^^^^^^^^^^ -solver Functions -"""""""""""""""" - +solve_cgs +""""""""" .. autofunction:: sectionproperties.analysis.solver.solve_cgs + +solve_cgs_lagrange +"""""""""""""""""" .. autofunction:: sectionproperties.analysis.solver.solve_cgs_lagrange + +solve_direct +"""""""""""" .. autofunction:: sectionproperties.analysis.solver.solve_direct + +solve_direct_lagrange +""""""""""""""""""""" .. autofunction:: sectionproperties.analysis.solver.solve_direct_lagrange + +function_timer +"""""""""""""" .. autofunction:: sectionproperties.analysis.solver.function_timer + Post-Processor Package ---------------------- *post* Module ^^^^^^^^^^^^^ -post Functions -"""""""""""""" - +setup_plot +"""""""""" .. autofunction:: sectionproperties.post.post.setup_plot + +finish_plot +""""""""""" .. autofunction:: sectionproperties.post.post.finish_plot + +draw_principal_axis +""""""""""""""""""" .. autofunction:: sectionproperties.post.post.draw_principal_axis + +print_results +""""""""""""" .. autofunction:: sectionproperties.post.post.print_results diff --git a/docs/source/rst/geom_mesh.rst b/docs/source/rst/geom_mesh.rst index 3e422b33..5c4a370d 100644 --- a/docs/source/rst/geom_mesh.rst +++ b/docs/source/rst/geom_mesh.rst @@ -20,6 +20,7 @@ Section Geometry * The :class:`~sectionproperties.pre.sections.CompoundGeometry` class, comprised of two or more `Geometry` objects + Geometry Class -------------- @@ -36,6 +37,7 @@ A :class:`~sectionproperties.pre.sections.Geometry` is instantiated with two arg assigned to the ``Geometry.material`` attribute. The default material has an elastic modulus of 1, a Poisson's ratio of 0 and a yield strength of 1. + CompoundGeometry Class ---------------------- @@ -88,12 +90,12 @@ In addition to creating geometries directly from :class:`shapely.geometry.Polygo analysis: #. From lists of points, facets, hole regions, and control regions -#. From *sectionproperties*'s "factory functions" of common shapes #. From ``.dxf`` files #. From ``.3dm`` files #. From Rhino encodings #. Using transformation methods on existing geometries and/or by applying set operations (e.g. `|`, `+`, `-`, `&`, `^`) +#. From *sectionproperties*'s section library For the first two approaches, an optional ``.material`` parameter can be passed containing a :class:`~sectionproperties.pre.pre.Material` (or list of `Material` objects) to associate with the @@ -102,6 +104,8 @@ newly created geometry(ies). The material attribute can be altered afterward in different :class:`~sectionproperties.pre.pre.Material` to the ``.material`` attribute. +.. _label-from-points: + Geometry from points, facets, holes, and control_points ------------------------------------------------------- @@ -139,6 +143,7 @@ file (i.e. the number of contiguous regions). .. autofunction:: sectionproperties.pre.sections.CompoundGeometry.from_dxf :noindex: + Geometry from Rhino ------------------- @@ -178,104 +183,6 @@ These can be accessed by :attr:`sectionproperties.pre.rhino.load_3dm()` and :noindex: -Creating Common Structural Geometries -------------------------------------- - -In order to make your life easier, there are a number of built-in functions that generate typical -structural cross-sections, resulting in :class:`~sectionproperties.pre.sections.Geometry` objects. - - -Rectangular Section -^^^^^^^^^^^^^^^^^^^ -.. autofunction:: sectionproperties.pre.sections.rectangular_section - :noindex: - -Circular Section -^^^^^^^^^^^^^^^^ -.. autofunction:: sectionproperties.pre.sections.circular_section - :noindex: - -Circular Hollow Section (CHS) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. autofunction:: sectionproperties.pre.sections.circular_hollow_section - :noindex: - -Elliptical Section -^^^^^^^^^^^^^^^^^^ -.. autofunction:: sectionproperties.pre.sections.elliptical_section - :noindex: - -Elliptical Hollow Section (EHS) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. autofunction:: sectionproperties.pre.sections.elliptical_hollow_section - :noindex: - -Rectangular Hollow Section (RHS) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. autofunction:: sectionproperties.pre.sections.rectangular_hollow_section - :noindex: - -I-Section -^^^^^^^^^ - .. autofunction:: sectionproperties.pre.sections.i_section - :noindex: - -Monosymmetric I-Section -^^^^^^^^^^^^^^^^^^^^^^^ - .. autofunction:: sectionproperties.pre.sections.mono_i_section - :noindex: - -Tapered Flange I-Section -^^^^^^^^^^^^^^^^^^^^^^^^ - .. autofunction:: sectionproperties.pre.sections.tapered_flange_i_section - :noindex: - -Parallel Flange Channel (PFC) Section -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - .. autofunction:: sectionproperties.pre.sections.channel_section - :noindex: - -Tapered Flange Channel Section -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - .. autofunction:: sectionproperties.pre.sections.tapered_flange_channel - :noindex: - -Tee Section -^^^^^^^^^^^ - .. autofunction:: sectionproperties.pre.sections.tee_section - :noindex: - -Angle Section -^^^^^^^^^^^^^ - .. autofunction:: sectionproperties.pre.sections.angle_section - :noindex: - -Cee Section -^^^^^^^^^^^ - .. autofunction:: sectionproperties.pre.sections.cee_section - :noindex: - -Zed Section -^^^^^^^^^^^ - .. autofunction:: sectionproperties.pre.sections.zed_section - :noindex: - -Cruciform Section -^^^^^^^^^^^^^^^^^ - .. autofunction:: sectionproperties.pre.sections.cruciform_section - :noindex: - -Polygon Hollow Section -^^^^^^^^^^^^^^^^^^^^^^ - .. autofunction:: sectionproperties.pre.sections.polygon_hollow_section - :noindex: - -Box Girder Section -^^^^^^^^^^^^^^^^^^ - .. autofunction:: sectionproperties.pre.sections.box_girder_section - :noindex: - - Combining Geometries Using Set Operations ----------------------------------------- @@ -293,6 +200,12 @@ Both `Geometry` and `CompoundGeometry` objects can be manipulated using Python's See :ref:`label-advanced_geom` for an example using set operations. +*sectionproperties* Section Library +----------------------------------- + +See :ref:`label-section-library`. + + Manipulating Geometries ======================= @@ -316,18 +229,21 @@ Aligning .. autofunction:: sectionproperties.pre.sections.Geometry.align_to :noindex: + Mirroring --------- .. autofunction:: sectionproperties.pre.sections.Geometry.mirror_section :noindex: + Rotating -------- .. autofunction:: sectionproperties.pre.sections.Geometry.rotate_section :noindex: + Shifting -------- @@ -337,12 +253,14 @@ Shifting .. autofunction:: sectionproperties.pre.sections.Geometry.shift_section :noindex: + Splitting --------- .. autofunction:: sectionproperties.pre.sections.Geometry.split_section :noindex: + Offsetting the Perimeter ------------------------ diff --git a/docs/source/rst/post.rst b/docs/source/rst/post.rst index 68d036dc..cd8eeaa1 100644 --- a/docs/source/rst/post.rst +++ b/docs/source/rst/post.rst @@ -291,10 +291,10 @@ The examples shown in the methods below are performed on a 150x90x12 UA (unequal angle) section. The :class:`~sectionproperties.analysis.cross_section.Section` object is created below:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.steel_sections as steel_sections from sectionproperties.analysis.cross_section import Section - geometry = sections.AngleSection(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.AngleSection(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) mesh = geometry.create_mesh(mesh_sizes=[2.5]) section = Section(geometry, mesh) diff --git a/docs/source/rst/section_library.rst b/docs/source/rst/section_library.rst new file mode 100644 index 00000000..1c123936 --- /dev/null +++ b/docs/source/rst/section_library.rst @@ -0,0 +1,137 @@ +.. _label-section-library: + +==================================================== +Creating Section Geometries from the Section Library +==================================================== + +In order to make your life easier, there are a number of built-in functions that generate typical +structural cross-sections, resulting in :class:`~sectionproperties.pre.sections.Geometry` objects. +These typical cross-sections reside in the ``sectionproperties.pre.library`` module. + +Standard Sections Library +========================= + +Rectangular Section +------------------- +.. autofunction:: sectionproperties.pre.library.standard_sections.rectangular_section + :noindex: + +Circular Section +---------------- +.. autofunction:: sectionproperties.pre.library.standard_sections.circular_section + :noindex: + +Elliptical Section +------------------ +.. autofunction:: sectionproperties.pre.library.standard_sections.elliptical_section + :noindex: + +Cruciform Section +----------------- + .. autofunction:: sectionproperties.pre.library.standard_sections.cruciform_section + :noindex: + + +Steel Sections Library +====================== + +Circular Hollow Section (CHS) +----------------------------- +.. autofunction:: sectionproperties.pre.library.steel_sections.circular_hollow_section + :noindex: + +Elliptical Hollow Section (EHS) +------------------------------- +.. autofunction:: sectionproperties.pre.library.steel_sections.elliptical_hollow_section + :noindex: + +Rectangular Hollow Section (RHS) +-------------------------------- +.. autofunction:: sectionproperties.pre.library.steel_sections.rectangular_hollow_section + :noindex: + +Polygon Hollow Section +---------------------- + .. autofunction:: sectionproperties.pre.library.steel_sections.polygon_hollow_section + :noindex: + +I-Section +--------- + .. autofunction:: sectionproperties.pre.library.steel_sections.i_section + :noindex: + +Monosymmetric I-Section +----------------------- + .. autofunction:: sectionproperties.pre.library.steel_sections.mono_i_section + :noindex: + +Tapered Flange I-Section +------------------------ + .. autofunction:: sectionproperties.pre.library.steel_sections.tapered_flange_i_section + :noindex: + +Parallel Flange Channel (PFC) Section +------------------------------------- + .. autofunction:: sectionproperties.pre.library.steel_sections.channel_section + :noindex: + +Tapered Flange Channel Section +------------------------------ + .. autofunction:: sectionproperties.pre.library.steel_sections.tapered_flange_channel + :noindex: + +Tee Section +----------- + .. autofunction:: sectionproperties.pre.library.steel_sections.tee_section + :noindex: + +Angle Section +------------- + .. autofunction:: sectionproperties.pre.library.steel_sections.angle_section + :noindex: + +Cee Section +----------- + .. autofunction:: sectionproperties.pre.library.steel_sections.cee_section + :noindex: + +Zed Section +----------- + .. autofunction:: sectionproperties.pre.library.steel_sections.zed_section + :noindex: + +Box Girder Section +------------------ + .. autofunction:: sectionproperties.pre.library.steel_sections.box_girder_section + :noindex: + + +Concrete Sections Library +========================= + +Concrete Rectangular Section +---------------------------- +.. autofunction:: sectionproperties.pre.library.concrete_sections.concrete_rectangular_section + :noindex: + +Concrete Tee Section +-------------------- +.. autofunction:: sectionproperties.pre.library.concrete_sections.concrete_tee_section + :noindex: + +Concrete Circular Section +------------------------- +.. autofunction:: sectionproperties.pre.library.concrete_sections.concrete_circular_section + :noindex: + + +Bridge Sections Library +======================= + +TBC + + +Nastran Sections Library +======================== + +See :ref:`label-nastran-sections`. diff --git a/docs/source/rst/structure.rst b/docs/source/rst/structure.rst index cf8c3622..aaef56d8 100644 --- a/docs/source/rst/structure.rst +++ b/docs/source/rst/structure.rst @@ -12,14 +12,15 @@ Creating a Geometry and Mesh ---------------------------- The dimensions and shape of the cross-section to be analysed define the *geometry* -of the cross-section. The :ref:`label-sections-module` provides a number of functions -to easily generate either commonly used structural sections or an arbitrary -cross-section, defined by an ordered list of points. +of the cross-section. The :ref:`Section Library` provides a number of +functions to easily generate either commonly used structural sections. Alternatively, +arbitrary cross-sections can be built from a list of user-defined points, see +:ref:`label-from-points`. The final stage in the pre-processor involves generating a finite element mesh of the *geometry* that the solver can use to calculate the cross-section properties. -This can easily be performed using the :func:`~sectionproperties.pre.sections.Geometry.create_mesh` -method that all :class:`~sectionproperties.pre.sections.Geometry` objects have +This can easily be performed using the :func:`~sectionproperties.pre.geometry.Geometry.create_mesh` +method that all :class:`~sectionproperties.pre.geometry.Geometry` objects have access to. The following example creates a geometry object with a circular cross-section. @@ -27,9 +28,9 @@ The diameter of the circle is 50 and 64 points are used to discretise the circum of the circle. A finite element mesh is generated with a maximum triangular area of 2.5:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.standard_sections as standard_sections - geometry = sections.circular_section(d=50, n=64) + geometry = standard_sections.circular_section(d=50, n=64) geometry.create_mesh(mesh_sizes=[2.5]) .. figure:: ../images/sections/circle_mesh.png @@ -71,14 +72,14 @@ The following example performs a geometric and warping analysis on the circular cross-section defined in the previous section with steel used as the material property:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.standard_sections as standard_sections from sectionproperties.analysis.cross_section import Section from sectionproperties.pre.pre import Material steel = Material(name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, density=7.85e-6, yield_strength=500, color='grey') - geometry = sections.circular_section(d=50, n=64, material=steel) + geometry = standard_sections.circular_section(d=50, n=64, material=steel) geometry.create_mesh(mesh_sizes=[2.5]) # Adds the mesh to the geometry section = Section(geometry) @@ -99,10 +100,10 @@ displayed and the cross-section stresses visualised in a contour plot. The following example analyses a 200 PFC section. The cross-section properties are printed to the terminal and a plot of the centroids is displayed:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.steel_sections as steel_sections from sectionproperties.analysis.cross_section import Section - geometry = sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8) + geometry = steel_sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8) geometry.create_mesh(mesh_sizes=[2.5]) # Adds the mesh to the geometry section = Section(geometry) @@ -188,5 +189,4 @@ method:: SF_22+ = 1.802381e+00 SF_22- = 8.688337e-01 -Refer to :ref:`label-post` for a more detailed explanation of the post-processing -stage. +Refer to :ref:`label-post` for a more detailed explanation of the post-processing stage. diff --git a/examples/00-basic/01_simple.py b/examples/00-basic/01_simple.py index 73b4f8b8..4a48ec24 100644 --- a/examples/00-basic/01_simple.py +++ b/examples/00-basic/01_simple.py @@ -21,8 +21,8 @@ # sphinx_gallery_thumbnail_number = 1 -import sectionproperties.pre.sections as sections -from sectionproperties.analysis.cross_section import Section +import sectionproperties.pre.library.standard_sections as sections +from sectionproperties.analysis.section import Section # %% # Create a 50 diameter circle discretised by 64 points @@ -35,7 +35,7 @@ section = Section(geometry, time_info=True) section.display_mesh_info() -section.plot_mesh() +section.plot_mesh() # %% # perform a geometric, warping and plastic analysis, displaying the time info diff --git a/examples/00-basic/02_nastran_section.py b/examples/00-basic/02_nastran_section.py index 8c9a1814..67b1d8f1 100644 --- a/examples/00-basic/02_nastran_section.py +++ b/examples/00-basic/02_nastran_section.py @@ -23,8 +23,8 @@ # sphinx_gallery_thumbnail_number = 1 from typing import get_origin -import sectionproperties.pre.nastran_sections as nsections -from sectionproperties.analysis.cross_section import Section +import sectionproperties.pre.library.nastran_sections as nsections +from sectionproperties.analysis.section import Section # %% # Create a HAT1 section diff --git a/examples/00-basic/03_custom.py b/examples/00-basic/03_custom.py index 10c3780e..c9ef6e56 100644 --- a/examples/00-basic/03_custom.py +++ b/examples/00-basic/03_custom.py @@ -22,8 +22,8 @@ # sphinx_gallery_thumbnail_number = 2 -import sectionproperties.pre.sections as sections -from sectionproperties.analysis.cross_section import Section +from sectionproperties.pre.geometry import CompoundGeometry +from sectionproperties.analysis.section import Section # %% # Define parameters for the angle section @@ -33,18 +33,37 @@ # %% # Build the lists of points, facets, holes and control points -points = [[-t/2, -2*a], [t/2, -2*a], [t/2, -t/2], [a, -t/2], [a, t/2], - [-t/2, t/2], [-b/2, -2*a], [b/2, -2*a], [b/2, -2*a-t], - [-b/2, -2*a-t]] -facets = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 0], [6, 7], [7, 8], - [8, 9], [9, 6]] +points = [ + [-t / 2, -2 * a], + [t / 2, -2 * a], + [t / 2, -t / 2], + [a, -t / 2], + [a, t / 2], + [-t / 2, t / 2], + [-b / 2, -2 * a], + [b / 2, -2 * a], + [b / 2, -2 * a - t], + [-b / 2, -2 * a - t], +] +facets = [ + [0, 1], + [1, 2], + [2, 3], + [3, 4], + [4, 5], + [5, 0], + [6, 7], + [7, 8], + [8, 9], + [9, 6], +] holes = [] control_points = [[0, 0], [0, -2 * a - t / 2]] # %% # Because we have two separate geometry regions (as indicated by our control_points) # we create a CompoundGeometry from points -geometry = sections.CompoundGeometry.from_points(points, facets, control_points, holes) +geometry = CompoundGeometry.from_points(points, facets, control_points, holes) # %% # Create the mesh and section. For the mesh, use a smaller refinement for the angle region. diff --git a/examples/00-basic/04_merged.py b/examples/00-basic/04_merged.py index 73b724fe..d5c67cad 100644 --- a/examples/00-basic/04_merged.py +++ b/examples/00-basic/04_merged.py @@ -24,24 +24,25 @@ # sphinx_gallery_thumbnail_number = 1 -import sectionproperties.pre.sections as sections -from sectionproperties.analysis.cross_section import Section +import sectionproperties.pre.library.steel_sections as steel_sections +from sectionproperties.pre.geometry import Geometry +from sectionproperties.analysis.section import Section # %% # Create a 150x100x6 RHS -rhs = sections.rectangular_hollow_section(d=150, b=100, t=6, r_out=15, n_r=8) +rhs = steel_sections.rectangular_hollow_section(d=150, b=100, t=6, r_out=15, n_r=8) # %% # Create a triangular section from points, facets, and control points points = [[0, 0], [50, 0], [25, 50]] facets = [[0, 1], [1, 2], [2, 0]] -control_points = [[25,25]] -triangle = sections.Geometry.from_points(points, facets, control_points) +control_points = [[25, 25]] +triangle = Geometry.from_points(points, facets, control_points) triangle = triangle.align_center(rhs).align_to(rhs, on="top") # %% # Create a 100x100x6 angle and position it on the right of the RHS -angle = sections.angle_section(d=100, b=100, t=6, r_r=8, r_t=5, n_r=8) +angle = steel_sections.angle_section(d=100, b=100, t=6, r_r=8, r_t=5, n_r=8) angle = angle.shift_section(x_offset=100, y_offset=25) # %% @@ -50,7 +51,7 @@ geometry.plot_geometry() # plot the geometry # %% -# Create a mesh and section. For the mesh, use a mesh size of 2.5 for +# Create a mesh and section. For the mesh, use a mesh size of 2.5 for # the RHS, 5 for the triangle and 3 for the angle. geometry.create_mesh(mesh_sizes=[2.5, 5, 3]) diff --git a/examples/00-basic/05_mirr_rot.py b/examples/00-basic/05_mirr_rot.py index fda8ee79..c76d3f76 100644 --- a/examples/00-basic/05_mirr_rot.py +++ b/examples/00-basic/05_mirr_rot.py @@ -23,18 +23,19 @@ # sphinx_gallery_thumbnail_number = 1 -import sectionproperties.pre.sections as sections -from sectionproperties.analysis.cross_section import Section +import sectionproperties.pre.library.steel_sections as steel_sections +from sectionproperties.analysis.section import Section # %% # Create a 200PFC and a 150PFC -pfc1 = sections.channel_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8) -pfc2 = sections.channel_section( - d=150, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8).shift_section(0, 26.5) +pfc1 = steel_sections.channel_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8) +pfc2 = steel_sections.channel_section( + d=150, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8 +).shift_section(0, 26.5) # %% # Mirror the 200 PFC about the y-axis -pfc1 = pfc1.mirror_section(axis='y', mirror_point=[0, 0]) +pfc1 = pfc1.mirror_section(axis="y", mirror_point=[0, 0]) # %% # Merge the pfc sections @@ -43,7 +44,7 @@ # %% # Rotate the geometry counter-clockwise by 30 degrees geometry = geometry.rotate_section(angle=30) -geometry.plot_geometry() +geometry.plot_geometry() # %% # Create a mesh and section. For the mesh, use a mesh size of 5 for the 200PFC diff --git a/examples/00-basic/06_stress.py b/examples/00-basic/06_stress.py index b41a7cd0..7270296a 100644 --- a/examples/00-basic/06_stress.py +++ b/examples/00-basic/06_stress.py @@ -18,12 +18,12 @@ # sphinx_gallery_thumbnail_number = 1 -import sectionproperties.pre.sections as sections -from sectionproperties.analysis.cross_section import Section +import sectionproperties.pre.library.steel_sections as steel_sections +from sectionproperties.analysis.section import Section # %% # Create a 150x100x6 RHS on its side -geometry = sections.rectangular_hollow_section(d=100, b=150, t=6, r_out=15, n_r=8) +geometry = steel_sections.rectangular_hollow_section(d=100, b=150, t=6, r_out=15, n_r=8) # %% # Create a mesh and section object. For the mesh, use a maximum area of 2 diff --git a/examples/00-basic/07_composite.py b/examples/00-basic/07_composite.py index 6cb8cb11..e9e25857 100644 --- a/examples/00-basic/07_composite.py +++ b/examples/00-basic/07_composite.py @@ -19,20 +19,36 @@ # sphinx_gallery_thumbnail_number = 2 -import sectionproperties.pre.sections as sections +import sectionproperties.pre.library.standard_sections as sections +import sectionproperties.pre.library.steel_sections as steel_sections +from sectionproperties.pre.geometry import CompoundGeometry from sectionproperties.pre.pre import Material -from sectionproperties.analysis.cross_section import Section +from sectionproperties.analysis.section import Section # %% # Create material properties -steel = Material(name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, - yield_strength=500, density=8.05e-6 ,color='grey') -timber = Material(name='Timber', elastic_modulus=8e3, poissons_ratio=0.35, - yield_strength=20, density=0.78e-6, color='burlywood') +steel = Material( + name="Steel", + elastic_modulus=200e3, + poissons_ratio=0.3, + yield_strength=500, + density=8.05e-6, + color="grey", +) +timber = Material( + name="Timber", + elastic_modulus=8e3, + poissons_ratio=0.35, + yield_strength=20, + density=0.78e-6, + color="burlywood", +) # %% # Create 310UB40.4 -ub = sections.i_section(d=304, b=165, t_f=10.2, t_w=6.1, r=11.4, n_r=8, material=steel) +ub = steel_sections.i_section( + d=304, b=165, t_f=10.2, t_w=6.1, r=11.4, n_r=8, material=steel +) # %% # Create timber panel on top of the UB @@ -41,36 +57,36 @@ # %% # Merge the two sections into one geometry object -geometry = sections.CompoundGeometry([ub, panel]) +section_geometry = sections.CompoundGeometry([ub, panel]) # %% # Create a mesh and a Section object. For the mesh use a mesh size of 5 for # the UB, 20 for the panel -geometry.create_mesh(mesh_sizes=[5, 20]) -section = Section(geometry, time_info=True) -section.display_mesh_info() # display the mesh information +section_geometry.create_mesh(mesh_sizes=[5, 20]) +comp_section = Section(section_geometry, time_info=True) +comp_section.display_mesh_info() # display the mesh information # %% # Plot the mesh with coloured materials and a line transparency of 0.6 -section.plot_mesh(materials=True, alpha=0.6) +comp_section.plot_mesh(materials=True, alpha=0.6) # %% # Perform a geometric, warping and plastic analysis -section.calculate_geometric_properties() -section.calculate_warping_properties() -section.calculate_plastic_properties(verbose=True) +comp_section.calculate_geometric_properties() +comp_section.calculate_warping_properties() +comp_section.calculate_plastic_properties(verbose=True) # %% # Perform a stress analysis with N = 100 kN, Mxx = 120 kN.m and Vy = 75 kN -stress_post = section.calculate_stress(N=-100e3, Mxx=-120e6, Vy=-75e3) +stress_post = comp_section.calculate_stress(N=-100e3, Mxx=-120e6, Vy=-75e3) # %% # Print the results to the terminal -section.display_results() +comp_section.display_results() # %% # Plot the centroids -section.plot_centroids() +comp_section.plot_centroids() # %% # Plot the axial stress @@ -82,4 +98,4 @@ # %% # Plot the shear stress -stress_post.plot_stress_v_zxy() \ No newline at end of file +stress_post.plot_stress_v_zxy() diff --git a/examples/00-basic/08_frame.py b/examples/00-basic/08_frame.py index 9ea1d690..7e5d0d1d 100644 --- a/examples/00-basic/08_frame.py +++ b/examples/00-basic/08_frame.py @@ -19,8 +19,8 @@ import time import numpy as np import matplotlib.pyplot as plt -import sectionproperties.pre.sections as sections -from sectionproperties.analysis.cross_section import Section +import sectionproperties.pre.library.standard_sections as sections +from sectionproperties.analysis.section import Section # %% # Create a rectangular section diff --git a/examples/01-advanced/01-torsion_constant.py b/examples/01-advanced/01-torsion_constant.py index cee94d82..61518918 100644 --- a/examples/01-advanced/01-torsion_constant.py +++ b/examples/01-advanced/01-torsion_constant.py @@ -15,8 +15,8 @@ import numpy as np import matplotlib.pyplot as plt -import sectionproperties.pre.sections as sections -from sectionproperties.analysis.cross_section import Section +import sectionproperties.pre.library.standard_sections as sections +from sectionproperties.analysis.section import Section # %% # Rectangle dimensions @@ -47,7 +47,7 @@ # get the torsion constant j = section.get_j() - print("d/b = {0:.3f}; J = {1:.5e}".format(d/b, j)) + print("d/b = {0:.3f}; J = {1:.5e}".format(d / b, j)) j_list.append(j) # %% diff --git a/examples/01-advanced/02-mesh_refinement.py b/examples/01-advanced/02-mesh_refinement.py index 8d6eea0d..af43991c 100644 --- a/examples/01-advanced/02-mesh_refinement.py +++ b/examples/01-advanced/02-mesh_refinement.py @@ -16,8 +16,8 @@ import numpy as np import matplotlib.pyplot as plt -import sectionproperties.pre.sections as sections -from sectionproperties.analysis.cross_section import Section +import sectionproperties.pre.library.steel_sections as steel_sections +from sectionproperties.analysis.section import Section # %% # Define mesh sizes @@ -33,7 +33,7 @@ # %% # Calculate reference solution -geometry = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=64) +geometry = steel_sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=64) geometry.create_mesh(mesh_sizes=[0.5]) # create mesh section = Section(geometry) # create a Section object section.calculate_geometric_properties() @@ -43,7 +43,7 @@ # %% # Run through mesh_sizes with n_r = 16 for mesh_size in mesh_size_list: - geometry = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=16) + geometry = steel_sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=16) geometry.create_mesh(mesh_sizes=[mesh_size]) # create mesh section = Section(geometry) # create a Section object section.calculate_geometric_properties() @@ -55,7 +55,7 @@ # %% # Run through n_r with mesh_size = 3 for n_r in nr_list: - geometry = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=n_r) + geometry = steel_sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=n_r) geometry.create_mesh(mesh_sizes=[3]) # create mesh section = Section(geometry) # create a Section object section.calculate_geometric_properties() @@ -74,10 +74,10 @@ # %% # Plot the results (fig, ax) = plt.subplots() -ax.loglog(mesh_elements, mesh_error_vals, 'kx-', label='Mesh Size Refinement') -ax.loglog(nr_elements, nr_error_vals, 'rx-', label='Root Radius Refinement') +ax.loglog(mesh_elements, mesh_error_vals, "kx-", label="Mesh Size Refinement") +ax.loglog(nr_elements, nr_error_vals, "rx-", label="Root Radius Refinement") plt.xlabel("Number of Elements") plt.ylabel("Torsion Constant Error [%]") -plt.legend(loc='center left', bbox_to_anchor=(1, 0.5)) +plt.legend(loc="center left", bbox_to_anchor=(1, 0.5)) plt.tight_layout() plt.show() diff --git a/sectionproperties/analysis/cross_section.py b/sectionproperties/analysis/section.py similarity index 92% rename from sectionproperties/analysis/cross_section.py rename to sectionproperties/analysis/section.py index 13736df0..3d4718b5 100644 --- a/sectionproperties/analysis/cross_section.py +++ b/sectionproperties/analysis/section.py @@ -14,7 +14,7 @@ from scipy.sparse import csc_matrix, coo_matrix, linalg from scipy.optimize import brentq import sectionproperties.pre.pre as pre -import sectionproperties.pre.sections as sections +import sectionproperties.pre.geometry as section_geometry import sectionproperties.analysis.fea as fea import sectionproperties.analysis.solver as solver import sectionproperties.post.post as post @@ -31,17 +31,17 @@ class Section: corresponding Tri6 finite element objects. :param geometry: Cross-section geometry object used to generate the mesh - :type geometry: :class:`~sectionproperties.pre.sections.Geometry` + :type geometry: :class:`~sectionproperties.pre.geometry.Geometry` :param bool time_info: If set to True, a detailed description of the computation and the time cost is printed to the terminal for every computation performed. - The following example creates a :class:`~sectionproperties.analysis.cross_section.Section` + The following example creates a :class:`~sectionproperties.analysis.section.Section` object of a 100D x 50W rectangle using a mesh size of 5:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.standard_sections as standard_sections + from sectionproperties.analysis.section import Section - geometry = sections.rectangular_section(d=100, b=50) + geometry = standard_sections.rectangular_section(d=100, b=50) geometry.create_mesh(mesh_sizes=[5]) section = Section(geometry) @@ -49,7 +49,7 @@ class Section: :vartype elements: list[:class:`~sectionproperties.analysis.fea.Tri6`] :cvar int num_nodes: Number of nodes in the finite element mesh :cvar geometry: Cross-section geometry object used to generate the mesh - :vartype geometry: :class:`~sectionproperties.pre.sections.Geometry` + :vartype geometry: :class:`~sectionproperties.pre.geometry.Geometry` :cvar mesh: Mesh dict returned by triangle :vartype mesh: dict(mesh) :cvar mesh_nodes: Array of node coordinates from the mesh @@ -63,7 +63,7 @@ class Section: :cvar material_groups: List of objects containing the elements in each defined material :type material_groups: list[:class:`~sectionproperties.pre.pre.MaterialGroup`] :cvar section_props: Class to store calculated section properties - :vartype section_props: :class:`~sectionproperties.analysis.cross_section.SectionProperties` + :vartype section_props: :class:`~sectionproperties.analysis.section.SectionProperties` :raises AssertionError: If the number of materials does not equal the number of regions :raises ValueError: If geometry does not contain a mesh @@ -71,7 +71,7 @@ class Section: def __init__( self, - geometry: Union[sections.Geometry, sections.CompoundGeometry], + geometry: Union[section_geometry.Geometry, section_geometry.CompoundGeometry], time_info: bool = False, ): """Inits the Section class.""" @@ -89,7 +89,7 @@ def __init__( mesh = self.mesh def init(): - if isinstance(self.geometry, sections.CompoundGeometry): + if isinstance(self.geometry, section_geometry.CompoundGeometry): self.materials = [geom.material for geom in self.geometry.geoms] else: self.materials = [self.geometry.material] @@ -190,7 +190,7 @@ def init(): def calculate_geometric_properties(self): """Calculates the geometric properties of the cross-section and stores them in the - :class:`~sectionproperties.analysis.cross_section.SectionProperties` object contained in + :class:`~sectionproperties.analysis.section.SectionProperties` object contained in the ``section_props`` class variable. The following geometric section properties are calculated: @@ -272,7 +272,7 @@ def calculate_geom(): def calculate_warping_properties(self, solver_type="direct"): """Calculates all the warping properties of the cross-section and stores them in the - :class:`~sectionproperties.analysis.cross_section.SectionProperties` object contained in + :class:`~sectionproperties.analysis.section.SectionProperties` object contained in the ``section_props`` class variable. :param string solver_type: Solver used for solving systems of linear equations, either @@ -657,7 +657,7 @@ def calculate_monosymmetry_integrals(): def calculate_frame_properties(self, solver_type="direct"): """Calculates and returns the properties required for a frame analysis. The properties are - also stored in the :class:`~sectionproperties.analysis.cross_section.SectionProperties` + also stored in the :class:`~sectionproperties.analysis.section.SectionProperties` object contained in the ``section_props`` class variable. :param string solver_type: Solver used for solving systems of linear equations, either @@ -794,7 +794,7 @@ def calculate_frame(): def calculate_plastic_properties(self, verbose=False, debug=False): """Calculates the plastic properties of the cross-section and stores the, in the - :class:`~sectionproperties.analysis.cross_section.SectionProperties` object contained in + :class:`~sectionproperties.analysis.section.SectionProperties` object contained in the ``section_props`` class variable. :param bool verbose: If set to True, the number of iterations required for each plastic @@ -838,7 +838,7 @@ def calc_plastic(): def calculate_stress(self, N=0, Vx=0, Vy=0, Mxx=0, Myy=0, M11=0, M22=0, Mzz=0): """Calculates the cross-section stress resulting from design actions and returns a - :class:`~sectionproperties.analysis.cross_section.StressPost` object allowing + :class:`~sectionproperties.analysis.section.StressPost` object allowing post-processing of the stress results. :param float N: Axial force @@ -850,7 +850,7 @@ def calculate_stress(self, N=0, Vx=0, Vy=0, Mxx=0, Myy=0, M11=0, M22=0, Mzz=0): :param float M22: Bending moment about the centroidal 22-axis :param float Mzz: Torsion moment about the centroidal zz-axis :return: Object for post-processing cross-section stresses - :rtype: :class:`~sectionproperties.analysis.cross_section.StressPost` + :rtype: :class:`~sectionproperties.analysis.section.StressPost` Note that a geometric and warping analysis must be performed before a stress analysis is carried out:: @@ -1089,7 +1089,7 @@ def plot_mesh( If set to false, the script continues immediately after the window is rendered. :param float alpha: Transparency of the mesh outlines: :math:`0 \leq \\alpha \leq 1` :param bool materials: If set to true and material properties have been provided to the - :class:`~sectionproperties.analysis.cross_section.Section` object, shades the + :class:`~sectionproperties.analysis.section.Section` object, shades the elements with the specified material colours :param mask: Mask array, of length ``num_nodes``, to mask out triangles :type mask: list[bool] @@ -1098,12 +1098,12 @@ def plot_mesh( :rtype: (:class:`matplotlib.figure.Figure`, :class:`matplotlib.axes`) The following example plots the mesh generated for the second example - listed under the :class:`~sectionproperties.analysis.cross_section.Section` object + listed under the :class:`~sectionproperties.analysis.section.Section` object definition:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.standard_sections as standard_sections from sectionproperties.pre.pre import Material - from sectionproperties.analysis.cross_section import Section + from sectionproperties.analysis.section import Section steel = Material( name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, density=7.85e-6, @@ -1114,8 +1114,8 @@ def plot_mesh( yield_strength=20, color='burlywood' ) - geom_steel = sections.rectangular_section(d=50, b=50, material=steel) - geom_timber = sections.rectangular_section(d=50, b=50, material=timber) + geom_steel = standard_sections.rectangular_section(d=50, b=50, material=steel) + geom_timber = standard_sections.rectangular_section(d=50, b=50, material=timber) geometry = geom_timber.align_to(geom_steel, on="right") + geom_steel geometry.create_mesh(mesh_sizes=[10, 5]) @@ -1202,10 +1202,10 @@ def plot_centroids(self, pause=True, size=500, dpi=96): The following example analyses a 200 PFC section and displays a plot of the centroids:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8) + geometry = steel_sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -1224,10 +1224,10 @@ def plot_centroids(self, pause=True, size=500, dpi=96): The following example analyses a 150x90x12 UA section and displays a plot of the centroids:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -1311,11 +1311,11 @@ def display_mesh_info(self): The following example displays the mesh statistics for a Tee section merged from two rectangles:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.standard_sections as standard_sections + from sectionproperties.analysis.section import Section - rec1 = sections.rectangular_section(d=100, b=25) - rec2 = sections.rectangular_section(d=25, b=100) + rec1 = standard_sections.rectangular_section(d=100, b=25) + rec2 = standard_sections.rectangular_section(d=25, b=100) rec1 = rec1.shift_section(x_offset=-12.5) rec2 = rec2.shift_section(x_offset=-50, y_offset=100) @@ -1352,10 +1352,10 @@ def display_results(self, fmt="8.6e"): The following example displays the geometric section properties for a 100D x 50W rectangle with three digits after the decimal point:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.standard_sections as standard_sections + from sectionproperties.analysis.section import Section - geometry = sections.rectangular_section(d=100, b=50) + geometry = standard_sections.rectangular_section(d=100, b=50) geometry.create_mesh(mesh_sizes=[5]) section = Section(geometry) @@ -1927,13 +1927,13 @@ class PlasticSection: plastic section properties. :param section: Section object - :type section: :class:`~sectionproperties.analysis.cross_section.Section` + :type section: :class:`~sectionproperties.analysis.section.Section` :param bool debug: If set to True, the geometry is plotted each time a new mesh is generated by the plastic centroid algorithm. :cvar geometry: Deep copy of the Section geometry object provided to the constructor - :vartype geometry: :class:`~sectionproperties.pre.sections.Geometry` + :vartype geometry: :class:`~sectionproperties.pre.geometry.Geometry` :cvar materials: A list of material properties corresponding to various regions in the geometry and mesh. :vartype materials: list[:class:`~sectionproperties.pre.pre.Material`] @@ -1955,7 +1955,9 @@ class PlasticSection: :type c_bot: list[float, float] """ - def __init__(self, geom: Union[sections.Geometry, sections.CompoundGeometry]): + def __init__( + self, geom: Union[section_geometry.Geometry, section_geometry.CompoundGeometry] + ): """Inits the PlasticSection class.""" self.geometry = geom.align_center() self.geometry.compile_geometry() @@ -1980,7 +1982,7 @@ def calculate_centroid(self, elements): # General case # loop through all the geometries - if isinstance(self.geometry, sections.CompoundGeometry): + if isinstance(self.geometry, section_geometry.CompoundGeometry): for geom in self.geometry.geoms: e = geom.material.elastic_modulus area = geom.calculate_area() @@ -2002,14 +2004,14 @@ def calculate_centroid(self, elements): return (qy / ea, qx, ea) - def calculate_plastic_properties(self, cross_section, verbose): + def calculate_plastic_properties(self, section, verbose): """Calculates the location of the plastic centroid with respect to the centroidal and principal bending axes, the plastic section moduli and shape factors and stores the results - to the supplied :class:`~sectionproperties.analysis.cross_section.Section` object. + to the supplied :class:`~sectionproperties.analysis.section.Section` object. - :param cross_section: Cross section object that uses the same geometry and materials + :param section: Cross section object that uses the same geometry and materials specified in the class constructor - :type cross_section: :class:`~sectionproperties.analysis.cross_section.Section` + :type section: :class:`~sectionproperties.analysis.section.Section` :param bool verbose: If set to True, the number of iterations required for each plastic axis is printed to the terminal. """ @@ -2025,8 +2027,8 @@ def calculate_plastic_properties(self, cross_section, verbose): ) # fibres[2:] = ymin, ymax self.check_convergence(r, "x-axis") - cross_section.section_props.y_pc = y_pc - cross_section.section_props.sxx = f * abs(c_top[1] - c_bot[1]) + section.section_props.y_pc = y_pc + section.section_props.sxx = f * abs(c_top[1] - c_bot[1]) if verbose: self.print_verbose(y_pc, r, "x-axis") # Location of axis for each iteration @@ -2037,22 +2039,22 @@ def calculate_plastic_properties(self, cross_section, verbose): ) # fibres[0:2] = xmin, xmax self.check_convergence(r, "y-axis") - cross_section.section_props.x_pc = x_pc - cross_section.section_props.syy = f * abs(c_top[0] - c_bot[0]) + section.section_props.x_pc = x_pc + section.section_props.syy = f * abs(c_top[0] - c_bot[0]) if verbose: self.print_verbose(x_pc, r, "y-axis") # Location of axis for each iteration # 2) Calculate plastic properties for principal axis # convert principal axis angle to radians - angle = cross_section.section_props.phi * np.pi / 180 + angle = section.section_props.phi * np.pi / 180 # unit vectors in the axis directions ux = np.array([np.cos(angle), np.sin(angle)]) # Unit vectors uy = np.array([-np.sin(angle), np.cos(angle)]) # Unit vectors # calculate distances to the extreme fibres in the principal axis - fibres = self.calculate_extreme_fibres(cross_section.section_props.phi) + fibres = self.calculate_extreme_fibres(section.section_props.phi) # 2a) Calculate 11-axis plastic centroid (y22_pc, r, f, c_top, c_bot) = self.pc_algorithm( @@ -2061,15 +2063,15 @@ def calculate_plastic_properties(self, cross_section, verbose): # calculate the centroids in the principal coordinate system c_top_p = fea.principal_coordinate( - cross_section.section_props.phi, c_top[0], c_top[1] + section.section_props.phi, c_top[0], c_top[1] ) c_bot_p = fea.principal_coordinate( - cross_section.section_props.phi, c_bot[0], c_bot[1] + section.section_props.phi, c_bot[0], c_bot[1] ) self.check_convergence(r, "11-axis") - cross_section.section_props.y22_pc = y22_pc - cross_section.section_props.s11 = f * abs(c_top_p[1] - c_bot_p[1]) + section.section_props.y22_pc = y22_pc + section.section_props.s11 = f * abs(c_top_p[1] - c_bot_p[1]) if verbose: self.print_verbose(y22_pc, r, "11-axis") @@ -2081,45 +2083,45 @@ def calculate_plastic_properties(self, cross_section, verbose): # calculate the centroids in the principal coordinate system c_top_p = fea.principal_coordinate( - cross_section.section_props.phi, c_top[0], c_top[1] + section.section_props.phi, c_top[0], c_top[1] ) c_bot_p = fea.principal_coordinate( - cross_section.section_props.phi, c_bot[0], c_bot[1] + section.section_props.phi, c_bot[0], c_bot[1] ) self.check_convergence(r, "22-axis") - cross_section.section_props.x11_pc = x11_pc - cross_section.section_props.s22 = f * abs(c_top_p[0] - c_bot_p[0]) + section.section_props.x11_pc = x11_pc + section.section_props.s22 = f * abs(c_top_p[0] - c_bot_p[0]) if verbose: self.print_verbose(x11_pc, r, "22-axis") # if there are no materials specified, calculate shape factors - if list(set(cross_section.materials)) == [pre.DEFAULT_MATERIAL]: - cross_section.section_props.sf_xx_plus = ( - cross_section.section_props.sxx / cross_section.section_props.zxx_plus + if list(set(section.materials)) == [pre.DEFAULT_MATERIAL]: + section.section_props.sf_xx_plus = ( + section.section_props.sxx / section.section_props.zxx_plus ) - cross_section.section_props.sf_xx_minus = ( - cross_section.section_props.sxx / cross_section.section_props.zxx_minus + section.section_props.sf_xx_minus = ( + section.section_props.sxx / section.section_props.zxx_minus ) - cross_section.section_props.sf_yy_plus = ( - cross_section.section_props.syy / cross_section.section_props.zyy_plus + section.section_props.sf_yy_plus = ( + section.section_props.syy / section.section_props.zyy_plus ) - cross_section.section_props.sf_yy_minus = ( - cross_section.section_props.syy / cross_section.section_props.zyy_minus + section.section_props.sf_yy_minus = ( + section.section_props.syy / section.section_props.zyy_minus ) - cross_section.section_props.sf_11_plus = ( - cross_section.section_props.s11 / cross_section.section_props.z11_plus + section.section_props.sf_11_plus = ( + section.section_props.s11 / section.section_props.z11_plus ) - cross_section.section_props.sf_11_minus = ( - cross_section.section_props.s11 / cross_section.section_props.z11_minus + section.section_props.sf_11_minus = ( + section.section_props.s11 / section.section_props.z11_minus ) - cross_section.section_props.sf_22_plus = ( - cross_section.section_props.s22 / cross_section.section_props.z22_plus + section.section_props.sf_22_plus = ( + section.section_props.s22 / section.section_props.z22_plus ) - cross_section.section_props.sf_22_minus = ( - cross_section.section_props.s22 / cross_section.section_props.z22_minus + section.section_props.sf_22_minus = ( + section.section_props.s22 / section.section_props.z22_minus ) def check_convergence(self, root_result, axis): @@ -2327,24 +2329,24 @@ class StressPost: the MaterialGroups within the cross-section to allow the calculation of stresses for each material. Methods for post-processing the calculated stresses are provided. - :param cross_section: Cross section object for stress calculation - :type cross_section: :class:`~sectionproperties.analysis.cross_section.Section` + :param section: Cross section object for stress calculation + :type section: :class:`~sectionproperties.analysis.section.Section` - :cvar cross_section: Cross section object for stress calculation - :vartype cross_section: :class:`~sectionproperties.analysis.cross_section.Section` - :cvar material_groups: A deep copy of the `cross_section` material groups to allow a new stress + :cvar section: Cross section object for stress calculation + :vartype section: :class:`~sectionproperties.analysis.section.Section` + :cvar material_groups: A deep copy of the `section` material groups to allow a new stress analysis :vartype material_groups: list[:class:`~sectionproperties.pre.pre.MaterialGroup`] """ - def __init__(self, cross_section): + def __init__(self, section): """Inits the StressPost class.""" - self.cross_section = cross_section + self.section = section # make a deep copy of the material groups to the StressPost object such that stress results # can be saved to a new material group - self.material_groups = copy.deepcopy(cross_section.material_groups) + self.material_groups = copy.deepcopy(section.material_groups) def plot_stress_contour( self, sigs, title, pause, cmap, normalize=True, size=500, dpi=96 @@ -2371,16 +2373,16 @@ def plot_stress_contour( post.setup_plot(ax, pause) # plot the finite element mesh - self.cross_section.plot_mesh(ax, pause, materials=False, alpha=0.5) + self.section.plot_mesh(ax, pause, materials=False, alpha=0.5) # set up the colormap cmap = cm.get_cmap(name=cmap) # create triangulation triang = tri.Triangulation( - self.cross_section.mesh_nodes[:, 0], - self.cross_section.mesh_nodes[:, 1], - self.cross_section.mesh_elements[:, 0:3], + self.section.mesh_nodes[:, 0], + self.section.mesh_nodes[:, 1], + self.section.mesh_elements[:, 0:3], ) # determine minimum and maximum stress values for the contour list @@ -2404,7 +2406,7 @@ def plot_stress_contour( # plot the filled contour, looping through the materials for (i, sig) in enumerate(sigs): # create and set the mask for the current material - mask_array = np.ones(len(self.cross_section.elements), dtype=bool) + mask_array = np.ones(len(self.section.elements), dtype=bool) mask_array[self.material_groups[i].el_ids] = False triang.set_mask(mask_array) @@ -2450,7 +2452,7 @@ def plot_stress_vector( post.setup_plot(ax, pause) # plot the finite element mesh - self.cross_section.plot_mesh(ax, pause, materials=False, alpha=0.5) + self.section.plot_mesh(ax, pause, materials=False, alpha=0.5) # set up the colormap cmap = cm.get_cmap(name=cmap) @@ -2471,8 +2473,8 @@ def plot_stress_vector( c = np.hypot(sigx, sigy) quiv = ax.quiver( - self.cross_section.mesh_nodes[:, 0], - self.cross_section.mesh_nodes[:, 1], + self.section.mesh_nodes[:, 0], + self.section.mesh_nodes[:, 1], sigx, sigy, c, @@ -2512,7 +2514,7 @@ def plot_stress_vector( def get_stress(self): """Returns the stresses within each material belonging to the current - :class:`~sectionproperties.analysis.cross_section.StressPost` object. + :class:`~sectionproperties.analysis.section.StressPost` object. :return: A list of dictionaries containing the cross-section stresses for each material. :rtype: list[dict] @@ -2572,24 +2574,11 @@ def get_stress(self): :: - import sectionproperties.pre.sections as sections - from sectionproperties.pre.pre import Material - from sectionproperties.analysis.cross_section import Section - - steel = Material( - name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, density=7.85e-6, - yield_strength=250, color='grey' - ) - timber = Material( - name='Timber', elastic_modulus=8e3, poissons_ratio=0.35, density=6.5e-7, - yield_strength=20, color='burlywood' - ) - - geom_steel = sections.rectangular_section(d=50, b=50, material=steel) - geom_timber = sections.rectangular_section(d=50, b=50, material=timber) - geometry = geom_timber.align_to(geom_steel, on="right") + geom_steel - geometry.create_mesh(mesh_sizes=[10, 5]) + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) section.calculate_geometric_properties() @@ -2678,10 +2667,10 @@ def plot_stress_n_zz( The following example plots the normal stress within a 150x90x12 UA section resulting from an axial force of 10 kN:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -2728,10 +2717,10 @@ def plot_stress_mxx_zz( The following example plots the normal stress within a 150x90x12 UA section resulting from a bending moment about the x-axis of 5 kN.m:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -2778,10 +2767,10 @@ def plot_stress_myy_zz( The following example plots the normal stress within a 150x90x12 UA section resulting from a bending moment about the y-axis of 2 kN.m:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -2828,10 +2817,10 @@ def plot_stress_m11_zz( The following example plots the normal stress within a 150x90x12 UA section resulting from a bending moment about the 11-axis of 5 kN.m:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -2878,10 +2867,10 @@ def plot_stress_m22_zz( The following example plots the normal stress within a 150x90x12 UA section resulting from a bending moment about the 22-axis of 2 kN.m:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -2929,10 +2918,10 @@ def plot_stress_m_zz( a bending moment about the x-axis of 5 kN.m, a bending moment about the y-axis of 2 kN.m and a bending moment of 3 kN.m about the 11-axis:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -2979,10 +2968,10 @@ def plot_stress_mzz_zx( The following example plots the x-component of the shear stress within a 150x90x12 UA section resulting from a torsion moment of 1 kN.m:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3029,10 +3018,10 @@ def plot_stress_mzz_zy( The following example plots the y-component of the shear stress within a 150x90x12 UA section resulting from a torsion moment of 1 kN.m:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3079,10 +3068,10 @@ def plot_stress_mzz_zxy( The following example plots a contour of the resultant shear stress within a 150x90x12 UA section resulting from a torsion moment of 1 kN.m:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3129,10 +3118,10 @@ def plot_vector_mzz_zxy( The following example generates a vector plot of the shear stress within a 150x90x12 UA section resulting from a torsion moment of 1 kN.m:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3181,10 +3170,10 @@ def plot_stress_vx_zx( The following example plots the x-component of the shear stress within a 150x90x12 UA section resulting from a shear force in the x-direction of 15 kN:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3231,10 +3220,10 @@ def plot_stress_vx_zy( The following example plots the y-component of the shear stress within a 150x90x12 UA section resulting from a shear force in the x-direction of 15 kN:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3281,10 +3270,10 @@ def plot_stress_vx_zxy( The following example plots a contour of the resultant shear stress within a 150x90x12 UA section resulting from a shear force in the x-direction of 15 kN:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3331,10 +3320,10 @@ def plot_vector_vx_zxy( The following example generates a vector plot of the shear stress within a 150x90x12 UA section resulting from a shear force in the x-direction of 15 kN:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3383,10 +3372,10 @@ def plot_stress_vy_zx( The following example plots the x-component of the shear stress within a 150x90x12 UA section resulting from a shear force in the y-direction of 30 kN:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3433,10 +3422,10 @@ def plot_stress_vy_zy( The following example plots the y-component of the shear stress within a 150x90x12 UA section resulting from a shear force in the y-direction of 30 kN:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3483,10 +3472,10 @@ def plot_stress_vy_zxy( The following example plots a contour of the resultant shear stress within a 150x90x12 UA section resulting from a shear force in the y-direction of 30 kN:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3533,10 +3522,10 @@ def plot_vector_vy_zxy( The following example generates a vector plot of the shear stress within a 150x90x12 UA section resulting from a shear force in the y-direction of 30 kN:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3587,10 +3576,10 @@ def plot_stress_v_zx( section resulting from a shear force of 15 kN in the x-direction and 30 kN in the y-direction:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3639,10 +3628,10 @@ def plot_stress_v_zy( section resulting from a shear force of 15 kN in the x-direction and 30 kN in the y-direction:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3691,10 +3680,10 @@ def plot_stress_v_zxy( section resulting from a shear force of 15 kN in the x-direction and 30 kN in the y-direction:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3743,10 +3732,10 @@ def plot_vector_v_zxy( section resulting from a shear force of 15 kN in the x-direction and 30 kN in the y-direction:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3796,10 +3785,10 @@ def plot_stress_zz( an axial force of 100 kN, a bending moment about the x-axis of 5 kN.m and a bending moment about the y-axis of 2 kN.m:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3847,10 +3836,10 @@ def plot_stress_zx( section resulting from a torsion moment of 1 kN.m and a shear force of 30 kN in the y-direction:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3898,10 +3887,10 @@ def plot_stress_zy( section resulting from a torsion moment of 1 kN.m and a shear force of 30 kN in the y-direction:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -3949,10 +3938,10 @@ def plot_stress_zxy( section resulting from a torsion moment of 1 kN.m and a shear force of 30 kN in the y-direction:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -4000,10 +3989,10 @@ def plot_vector_zxy( section resulting from a torsion moment of 1 kN.m and a shear force of 30 kN in the y-direction:: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -4056,12 +4045,12 @@ def plot_stress_1( :: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) - geometry.create_mesh(mesh_sizes=[20]) - section = Section(geometry) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + mesh = geometry.create_mesh(mesh_sizes=[2.5]) + section = CrossSection(geometry, mesh) section.calculate_geometric_properties() section.calculate_warping_properties() @@ -4112,12 +4101,12 @@ def plot_stress_3( :: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) - geometry.create_mesh(mesh_sizes=[20]) - section = Section(geometry) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + mesh = geometry.create_mesh(mesh_sizes=[2.5]) + section = CrossSection(geometry, mesh) section.calculate_geometric_properties() section.calculate_warping_properties() @@ -4173,10 +4162,10 @@ def plot_stress_vm( :: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) geometry.create_mesh(mesh_sizes=[20]) section = Section(geometry) @@ -4230,12 +4219,12 @@ def plot_mohrs_circles(self, x, y, pause=True, cmap="coolwarm", size=500, dpi=96 :: - import sectionproperties.pre.sections as sections - from sectionproperties.analysis.cross_section import Section + import sectionproperties.pre.library.steel_sections as steel_sections + from sectionproperties.analysis.section import Section - geometry = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) - geometry.create_mesh(mesh_sizes=[20]) - section = Section(geometry) + geometry = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) + mesh = geometry.create_mesh(mesh_sizes=[2.5]) + section = Section(geometry, mesh) section.calculate_geometric_properties() section.calculate_warping_properties() @@ -4254,14 +4243,14 @@ def plot_mohrs_circles(self, x, y, pause=True, cmap="coolwarm", size=500, dpi=96 """ pt = (x, y) - nodes = self.cross_section.mesh_nodes - ele = self.cross_section.mesh_elements + nodes = self.section.mesh_nodes + ele = self.section.mesh_elements triang = tri.Triangulation(nodes[:, 0], nodes[:, 1], ele[:, 0:3]) # Find in which material group the point lies pt_group = None for group in self.material_groups: - mask_array = np.ones(len(self.cross_section.elements), dtype=bool) + mask_array = np.ones(len(self.section.elements), dtype=bool) mask_array[group.el_ids] = False triang.set_mask(mask_array) trifinder = triang.get_trifinder() @@ -4399,7 +4388,7 @@ class MaterialGroup: :cvar material: Material object for the current MaterialGroup :vartype material: :class:`~sectionproperties.pre.pre.Material` :cvar stress_result: A StressResult object for saving the stresses of the current material - :vartype stress_result: :class:`~sectionproperties.analysis.cross_section.StressResult` + :vartype stress_result: :class:`~sectionproperties.analysis.section.StressResult` :cvar elements: A list of finite element objects that are of the current material type :vartype elements: list[:class:`~sectionproperties.analysis.fea.Tri6`] :cvar el_ids: A list of the element IDs of the elements that are of the current material type diff --git a/sectionproperties/pre/bisect_section.py b/sectionproperties/pre/bisect_section.py index a221230e..44b414a7 100644 --- a/sectionproperties/pre/bisect_section.py +++ b/sectionproperties/pre/bisect_section.py @@ -1,5 +1,4 @@ from typing import Tuple, Union, List, Optional -from sectionproperties.pre import sections import numpy as np import shapely diff --git a/sectionproperties/pre/dxf.py b/sectionproperties/pre/dxf.py deleted file mode 100644 index 50df83a1..00000000 --- a/sectionproperties/pre/dxf.py +++ /dev/null @@ -1,26 +0,0 @@ -import pathlib -from shapely.geometry import Polygon, MultiPolygon -import cad_to_shapely as c2s -from sectionproperties.pre.sections import Geometry, CompoundGeometry - - -def load_dxf(dxf_filepath: pathlib.Path): - """ - Import any-old-shape in dxf format for analysis. - Code by aegis1980 and connorferster - """ - if not dxf_filepath.exists(): - raise ValueError(f"The filepath does not exist: {dxf_filepath}") - - my_dxf = c2s.dxf.DxfImporter(dxf_filepath) - my_dxf.process() - my_dxf.cleanup() - - polygons = my_dxf.polygons - new_polygons = c2s.utils.find_holes(polygons) - if isinstance(new_polygons, MultiPolygon): - return CompoundGeometry(new_polygons) - elif isinstance(new_polygons, Polygon): - return Geometry(new_polygons) - else: - print(f"No shapely.Polygon objects found in file: {dxf_filepath}") diff --git a/sectionproperties/pre/sections.py b/sectionproperties/pre/geometry.py similarity index 58% rename from sectionproperties/pre/sections.py rename to sectionproperties/pre/geometry.py index 197ceffa..75a84a8f 100644 --- a/sectionproperties/pre/sections.py +++ b/sectionproperties/pre/geometry.py @@ -76,7 +76,7 @@ def __init__( self.compile_geometry() def _repr_svg_(self): - print("sectionproperties.pre.sections.Geometry") + print("sectionproperties.pre.geometry.Geometry") print(f"object at: {hex(id(self))}") print(f"Material: {self.material.name}") return self.geom._repr_svg_() @@ -226,7 +226,7 @@ def from_3dm(cls, filepath: Union[str, pathlib.Path], **kwargs) -> Geometry: Try adjusting the keyword arguments if this error is raised. :return: A Geometry object. - :rtype: :class:`sectionproperties.pre.sections.Geometry` + :rtype: :class:`sectionproperties.pre.geometry.Geometry` :Keyword Arguments: * *refine_num* (``int, optional``) -- @@ -277,7 +277,7 @@ def from_rhino_encoding(cls, r3dm_brep: str, **kwargs) -> Geometry: See below. :return: A Geometry object found in the encoded string. - :rtype: :class:`sectionproperties.pre.sections.Geometry` + :rtype: :class:`sectionproperties.pre.geometry.Geometry` :Keyword Arguments: * *refine_num* (``int, optional``) -- @@ -341,14 +341,14 @@ def create_mesh(self, mesh_sizes: Union[float, List[float]]): :return: Geometry-object with mesh data stored in .mesh attribute. Returned Geometry-object is self, not a new instance. - :rtype: :class:`sectionproperties.pre.sections.Geometry` + :rtype: :class:`sectionproperties.pre.geometry.Geometry` The following example creates a circular cross-section with a diameter of 50 with 64 points, and generates a mesh with a maximum triangular area of 2.5:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.standard_sections as standard_sections - geometry = sections.CircularSection(d=50, n=64) + geometry = standard_sections.circular_section(d=50, n=64) geometry = geometry.create_mesh(mesh_sizes=2.5) .. figure:: ../images/sections/circle_mesh.png @@ -387,7 +387,7 @@ def align_to( :param other: Either another Geometry or a tuple representing an *(x,y)* coordinate point that 'self' should align to. - :type other: Union[sectionproperties.pre.sections.Geometry, Tuple[float, float]] + :type other: Union[sectionproperties.pre.geometry.Geometry, Tuple[float, float]] :param on: A str of either "left", "right", "bottom", or "top" indicating which side of 'other' that self should be aligned to. @@ -398,7 +398,7 @@ def align_to( :type inner: bool :return: Geometry object translated to alignment location - :rtype: :class:`sections.pre.sections.Geometry` + :rtype: :class:`sectionproperties.pre.geometry.Geometry` """ # Mappings are for indexes in the list of bbox extents of both # 'self' and 'align_to'. i.e. a mapping of which "word" corresponds @@ -460,10 +460,10 @@ def align_center(self, align_to: Optional[Geometry] = None): object will be aligned with it's centroid at the origin. :param align_to: Another Geometry to align to or None (default is None) - :type align_to: Optional[sectionproperties.pre.sections.Geometry] + :type align_to: Optional[sectionproperties.pre.geometry.Geometry] :return: Geometry object translated to new alignment - :rtype: :class:`sections.pre.sections.Geometry` + :rtype: :class:`sectionproperties.pre.geometry.Geometry` """ cx, cy = list(self.geom.centroid.coords)[0] # Suggested by Agent 6-6-6: Hard-rounding of cx and cy allows @@ -494,7 +494,7 @@ def shift_section( :type y_offset: float :return: New Geometry-object shifted by 'x_offset' and 'y_offset' - :rtype: :class:`sections.pre.sections.Geometry` + :rtype: :class:`sectionproperties.pre.geometry.Geometry` """ # Move assigned control point new_ctrl_point = None @@ -526,13 +526,13 @@ def rotate_section( :param use_radians: Boolean to indicate whether 'angle' is in degrees or radians. If True, 'angle' is interpreted as radians. :return: New Geometry-object rotated by 'angle' about 'rot_point' - :rtype: :class:`sections.pre.sections.Geometry` + :rtype: :class:`sectionproperties.pre.geometry.Geometry` The following example rotates a 200UB25 section clockwise by 30 degrees:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.steel_sections as steel_sections - geometry = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8) + geometry = steel_sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8) new_geometry = geometry.rotate_section(angle=-30) """ new_ctrl_point = None @@ -562,13 +562,13 @@ def mirror_section( :type mirror_point: Union[list[float, float], str] :return: New Geometry-object mirrored on 'axis' about 'mirror_point' - :rtype: :class:`sections.pre.sections.Geometry` + :rtype: :class:`sectionproperties.pre.geometry.Geometry` The following example mirrors a 200PFC section about the y-axis and the point (0, 0):: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.steel_sections as steel_sections - geometry = sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8) + geometry = steel_sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8) new_geometry = geometry.mirror_section(axis='y', mirror_point=[0, 0]) """ x_mirror = 1 @@ -631,10 +631,10 @@ def split_section( The following example splits a 200PFC section about the y-axis:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.steel_sections as steel_sections from shapely.geometry import LineString - geometry = sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8) + geometry = steel_sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8) right_geom, left_geom = geometry.split_section((0, 0), (0, 1)) """ if point_j: @@ -680,11 +680,11 @@ def offset_perimeter( :type resolution: float :return: Geometry object translated to new alignment - :rtype: :class:`sections.pre.sections.Geometry` + :rtype: :class:`sectionproperties.pre.geometry.Geometry` The following example erodes a 200PFC section by 2 mm:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.steel_sections as steel_sections geometry = sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8) new_geometry = geometry.offset_perimeter(amount=-2) @@ -785,14 +785,14 @@ def shift_points( :type abs_y: Optional[float] :return: Geometry object with selected points translated to the new location. - :rtype: :class:`sections.pre.sections.Geometry` + :rtype: :class:`sectionproperties.pre.geometry.Geometry` The following example expands the sides of a rectangle, one point at a time, to make it a square:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.standard_sections as standard_sections - geometry = sections.rectangular_section(d=200, b=150) + geometry = standard_sections.rectangular_section(d=200, b=150) # Using relative shifting one_pt_shifted_geom = geometry.shift_points(point_idxs=1, dx=50) @@ -868,9 +868,9 @@ def plot_geometry( The following example creates a CHS discretised with 64 points, with a diameter of 48 and thickness of 3.2, and plots the geometry:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.steel_sections as steel_sections - geometry = sections.chs(d=48, t=3.2, n=64) + geometry = steel_sections.circular_hollow_section(d=48, t=3.2, n=64) geometry.plot_geometry() .. figure:: ../images/sections/chs_geometry.png @@ -1125,9 +1125,6 @@ def __and__(self, other): ) -### - - class CompoundGeometry(Geometry): """Class for defining a geometry of multiple distinct regions, each potentially having different material properties. @@ -1143,7 +1140,7 @@ class CompoundGeometry(Geometry): :cvar geoms: either a list of Geometry objects or a shapely.geometry.MultiPolygon instance. - :vartype geoms: Union[shapely.geometry.MultiPolygon, List[sectionproperties.pre.sections.Geometry]] + :vartype geoms: Union[shapely.geometry.MultiPolygon, List[sectionproperties.pre.geometry.Geometry]] """ def __init__(self, geoms: Union[MultiPolygon, List[Geometry]]): @@ -1372,14 +1369,14 @@ def create_mesh(self, mesh_sizes: List[float]): :return: Geometry-object with mesh data stored in .mesh attribute. Returned Geometry-object is self, not a new instance. - :rtype: :class:`sectionproperties.pre.sections.Geometry` + :rtype: :class:`sectionproperties.pre.geometry.Geometry` The following example creates a circular cross-section with a diameter of 50 with 64 points, and generates a mesh with a maximum triangular area of 2.5:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.standard_sections as standard_sections - geometry = sections.circular_section(d=50, n=64) + geometry = standard_sections.circular_section(d=50, n=64) geometry = geometry.create_mesh(mesh_sizes=[2.5]) .. figure:: ../images/sections/circle_mesh.png @@ -1407,7 +1404,7 @@ def shift_section(self, x_offset: float = 0, y_offset: float = 0): :type y_offset: float :return: CompoundGeometry object shifted by 'x_offset' and 'y_offset' - :rtype: :class:`sections.pre.sections.CompoundGeometry` + :rtype: :class:`sectionproperties.pre.sections.CompoundGeometry` """ geoms_acc = [] for geom in self.geoms: @@ -1432,14 +1429,15 @@ def rotate_section( :param use_radians: Boolean to indicate whether 'angle' is in degrees or radians. If True, 'angle' is interpreted as radians. :return: CompoundGeometry object rotated by 'angle' about 'rot_point' - :rtype: :class:`sections.pre.sections.CompoundGeometry` + :rtype: :class:`sectionproperties.pre.sections.CompoundGeometry` - The following example rotates a 200UB25 section clockwise by 30 degrees:: + The following example rotates a 200UB25 section with a plate clockwise by 30 degrees:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.steel_sections as steel_sections + import sectionproperties.pre.library.standard_sections as standard_sections - geometry_1 = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8) - geometry_2 = sections.rectangular_section(d=20, b=133) + geometry_1 = steel_sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8) + geometry_2 = standard_sections.rectangular_section(d=20, b=133) compound = geometry_2.align_center(geometry_1).align_to(geometry_1, on="top") + geometry_1 new_compound = compound.rotate_section(angle=-30) """ @@ -1463,16 +1461,17 @@ def mirror_section( :type mirror_point: Union[list[float, float], str] :return: Geometry object mirrored on 'axis' about 'mirror_point' - :rtype: :class:`sections.pre.sections.Geometry` + :rtype: :class:`sectionproperties.pre.geometry.Geometry` - The following example mirrors a 200PFC section about the y-axis and the point (0, 0):: + The following example mirrors a 200PFC section with a plate about the y-axis and the point (0, 0):: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.steel_sections as steel_sections + import sectionproperties.pre.library.standard_sections as standard_sections - geometry_1 = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8) - geometry_2 = sections.rectangular_section(d=20, b=133) + geometry_1 = steel_sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8) + geometry_2 = standard_sections.rectangular_section(d=20, b=133) compound = geometry_2.align_center(geometry_1).align_to(geometry_1, on="top") + geometry_1 - new_compound = compound.mirror_section(axis='y') + new_compound = compound.mirror_section(axis='y', mirror_point=[0,0]) """ geoms_acc = [] for geom in self.geoms: @@ -1493,10 +1492,10 @@ def align_center(self, align_to: Optional[Geometry] = None): geometry's assigned material. :param align_to: Another Geometry to align to or None (default is None) - :type align_to: Optional[sectionproperties.pre.sections.Geometry] + :type align_to: Optional[sectionproperties.pre.geometry.Geometry] :return: Geometry object translated to new alignment - :rtype: :class:`sections.pre.sections.Geometry` + :rtype: :class:`sectionproperties.pre.geometry.Geometry` """ EA_sum = sum( [ @@ -1564,10 +1563,10 @@ def split_section( The following example splits a 200PFC section about the y-axis:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.steel_sections as steel_sections from shapely.geometry import LineString - geometry = sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8) + geometry = steel_sections.channel_section(d=200, b=75, t_f=12, t_w=6, r=12, n_r=8) right_geom, left_geom = geometry.split_section((0, 0), (0, 1)) """ top_geoms_acc = [] @@ -1593,14 +1592,15 @@ def offset_perimeter( :param resolution: Number of segments used to approximate a quarter circle around a point :type resolution: float :return: Geometry object translated to new alignment - :rtype: :class:`sections.pre.sections.Geometry` + :rtype: :class:`sectionproperties.pre.geometry.Geometry` The following example erodes a 200UB25 with a 12 plate stiffener section by 2 mm:: - import sectionproperties.pre.sections as sections + import sectionproperties.pre.library.steel_sections as steel_sections + import sectionproperties.pre.library.standard_sections as standard_sections - geometry_1 = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8) - geometry_2 = sections.rectangular_section(d=12, b=133) + geometry_1 = steel_sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=8) + geometry_2 = standard_sections.rectangular_section(d=12, b=133) compound = geometry_2.align_center(geometry_1).align_to(geometry_1, on="top") + geometry_1 new_geometry = compound.offset_perimeter(amount=-2) @@ -1882,1461 +1882,3 @@ def filter_non_polygons( return MultiPolygon(acc) elif isinstance(input_geom, (Point, LineString)): return Polygon() - - -def draw_radius( - pt: list, r: float, theta: float, n, ccw: bool = True -): # Changed 'anti' to ccw to match shapely - """Adds a quarter radius of points to the points list - centered at point *pt*, with radius - *r*, starting at angle *theta*, with *n* points. If r = 0, adds pt only. - - :param pt: Centre of radius *(x,y)* - :type pt: list[float, float] - :param float r: Radius - :param float theta: Initial angle - :param int n: Number of points - :param bool ccw: Counter-clockwise rotation? - """ - points = [] - if r == 0: - points.append(pt) - return points - - if ccw: - mult = 1 - else: - mult = -1 - - # calculate radius of points - for i in range(n): - # determine angle - t = theta + mult * i * 1.0 / max(1, n - 1) * np.pi * 0.5 - - x = pt[0] + r * np.cos(t) - y = pt[1] + r * np.sin(t) - points.append([x, y]) - return points - - -def rectangular_section( - b, d, material: pre.Material = pre.DEFAULT_MATERIAL -) -> Geometry: - """Constructs a rectangular section with the bottom left corner at the origin *(0, 0)*, with - depth *d* and width *b*. - - :param float d: Depth (y) of the rectangle - :param float b: Width (x) of the rectangle - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates a rectangular cross-section with a depth of 100 and width of 50, - and generates a mesh with a maximum triangular area of 5:: - - import sectionproperties.pre.sections as sections - - geometry = sections.rectangular_section(d=100, b=50) - geometry.create_mesh(mesh_sizes=[5]) - - .. figure:: ../images/sections/rectangle_geometry.png - :align: center - :scale: 75 % - - Rectangular section geometry. - - .. figure:: ../images/sections/rectangle_mesh.png - :align: center - :scale: 75 % - - Mesh generated from the above geometry. - """ - points = [[0, 0], [b, 0], [b, d], [0, d]] - rectangle = Polygon(points) - return Geometry(rectangle, material) - - -def circular_section( - d: float, n: int, material: pre.Material = pre.DEFAULT_MATERIAL -) -> Geometry: - """Constructs a solid circle centered at the origin *(0, 0)* with diameter *d* and using *n* - points to construct the circle. - - :param float d: Diameter of the circle - :param int n: Number of points discretising the circle - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates a circular geometry with a diameter of 50 with 64 points, - and generates a mesh with a maximum triangular area of 2.5:: - - import sectionproperties.pre.sections as sections - - geometry = sections.circular_section(d=50, n=64) - geometry.create_mesh(mesh_sizes=[2.5]) - - .. figure:: ../images/sections/circle_geometry.png - :align: center - :scale: 75 % - - Circular section geometry. - - .. figure:: ../images/sections/circle_mesh.png - :align: center - :scale: 75 % - - Mesh generated from the above geometry. - """ - x_off, y_off = (0, 0) - points = [] - # loop through each point on the circle - for i in range(n): - # determine polar angle - theta = i * 2 * np.pi * 1.0 / n - - # calculate location of the point - x = 0.5 * d * np.cos(theta) + x_off - y = 0.5 * d * np.sin(theta) + y_off - - # append the current point to the points list - points.append([x, y]) - - circle = Polygon(points) - return Geometry(circle, material) - - -def circular_hollow_section( - d: float, t: float, n: int, material: pre.Material = pre.DEFAULT_MATERIAL -) -> Geometry: - """Constructs a circular hollow section (CHS) centered at the origin *(0, 0)*, with diameter *d* and - thickness *t*, using *n* points to construct the inner and outer circles. - - :param float d: Outer diameter of the CHS - :param float t: Thickness of the CHS - :param int n: Number of points discretising the inner and outer circles - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates a CHS discretised with 64 points, with a diameter of 48 and - thickness of 3.2, and generates a mesh with a maximum triangular area of 1.0:: - - import sectionproperties.pre.sections as sections - - geometry = sections.circular_hollow_section(d=48, t=3.2, n=64) - geometry.create_mesh(mesh_sizes=[1.0]) - - .. figure:: ../images/sections/chs_geometry.png - :align: center - :scale: 75 % - - CHS geometry. - - .. figure:: ../images/sections/chs_mesh.png - :align: center - :scale: 75 % - - Mesh generated from the above geometry. - """ - points_inner = [] - points_outer = [] - # loop through each point of the CHS - for i in range(n): - # determine polar angle - theta = i * 2 * np.pi * 1.0 / n - - # calculate location of outer and inner points - x_outer = 0.5 * d * np.cos(theta) - y_outer = 0.5 * d * np.sin(theta) - x_inner = (0.5 * d - t) * np.cos(theta) - y_inner = (0.5 * d - t) * np.sin(theta) - - # append the current points to the points list - points_outer.append([x_outer, y_outer]) - points_inner.append([x_inner, y_inner]) - - inner_circle = Polygon(points_inner) - outer_circle = Polygon(points_outer) - return Geometry(outer_circle - inner_circle, material) - - -def elliptical_section( - d_y: float, d_x: float, n: int, material: pre.Material = pre.DEFAULT_MATERIAL -) -> Geometry: - """Constructs a solid ellipse centered at the origin *(0, 0)* with vertical diameter *d_y* and - horizontal diameter *d_x*, using *n* points to construct the ellipse. - - :param float d_y: Diameter of the ellipse in the y-dimension - :param float d_x: Diameter of the ellipse in the x-dimension - :param int n: Number of points discretising the ellipse - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates an elliptical cross-section with a vertical diameter of 25 and - horizontal diameter of 50, with 40 points, and generates a mesh with a maximum triangular area - of 1.0:: - - import sectionproperties.pre.sections as sections - - geometry = sections.elliptical_section(d_y=25, d_x=50, n=40) - geometry.create_mesh(mesh_sizes=[1.0]) - - .. figure:: ../images/sections/ellipse_geometry.png - :align: center - :scale: 75 % - - Elliptical section geometry. - - .. figure:: ../images/sections/ellipse_mesh.png - :align: center - :scale: 75 % - - Mesh generated from the above geometry. - """ - points = [] - - # loop through each point on the ellipse - for i in range(n): - # determine polar angle - theta = i * 2 * np.pi * 1.0 / n - - # calculate location of the point - x = 0.5 * d_x * np.cos(theta) - y = 0.5 * d_y * np.sin(theta) - - # append the current point to the points list - points.append([x, y]) - - ellipse = Polygon(points) - return Geometry(ellipse, material) - - -def elliptical_hollow_section( - d_y: float, - d_x: float, - t: float, - n: int, - material: pre.Material = pre.DEFAULT_MATERIAL, -) -> Geometry: - """Constructs an elliptical hollow section (EHS) centered at the origin *(0, 0)*, with outer vertical - diameter *d_y*, outer horizontal diameter *d_x*, and thickness *t*, using *n* points to - construct the inner and outer ellipses. - - :param float d_y: Diameter of the ellipse in the y-dimension - :param float d_x: Diameter of the ellipse in the x-dimension - :param float t: Thickness of the EHS - :param int n: Number of points discretising the inner and outer ellipses - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates a EHS discretised with 30 points, with a outer vertical diameter - of 25, outer horizontal diameter of 50, and thickness of 2.0, and generates a mesh with a - maximum triangular area of 0.5:: - - import sectionproperties.pre.sections as sections - - geometry = sections.elliptical_hollow_section(d_y=25, d_x=50, t=2.0, n=64) - geometry.create_mesh(mesh_sizes=[0.5]) - - .. figure:: ../images/sections/ehs_geometry.png - :align: center - :scale: 75 % - - EHS geometry. - - .. figure:: ../images/sections/ehs_mesh.png - :align: center - :scale: 75 % - - Mesh generated from the above geometry. - """ - points_inner = [] - points_outer = [] - # loop through each point of the EHS - for i in range(n): - # determine polar angle - theta = i * 2 * np.pi * 1.0 / n - - # calculate location of outer and inner points - x_outer = 0.5 * d_x * np.cos(theta) - y_outer = 0.5 * d_y * np.sin(theta) - x_inner = ((0.5 * d_x) - t) * np.cos(theta) - y_inner = ((0.5 * d_y) - t) * np.sin(theta) - - # append the current points to the points list - points_outer.append([x_outer, y_outer]) - points_inner.append([x_inner, y_inner]) - - outer = Polygon(points_outer) - inner = Polygon(points_inner) - return Geometry(outer - inner, material) - - -def rectangular_hollow_section( - b: float, - d: float, - t: float, - r_out: float, - n_r: int, - material: pre.Material = pre.DEFAULT_MATERIAL, -) -> Geometry: - """Constructs a rectangular hollow section (RHS) centered at *(b/2, d/2)*, with depth *d*, width *b*, - thickness *t* and outer radius *r_out*, using *n_r* points to construct the inner and outer - radii. If the outer radius is less than the thickness of the RHS, the inner radius is set to - zero. - - :param float d: Depth of the RHS - :param float b: Width of the RHS - :param float t: Thickness of the RHS - :param float r_out: Outer radius of the RHS - :param int n_r: Number of points discretising the inner and outer radii - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates an RHS with a depth of 100, a width of 50, a thickness of 6 and - an outer radius of 9, using 8 points to discretise the inner and outer radii. A mesh is - generated with a maximum triangular area of 2.0:: - - import sectionproperties.pre.sections as sections - - geometry = sections.rectangular_hollow_section(d=100, b=50, t=6, r_out=9, n_r=8) - geometry.create_mesh(mesh_sizes=[2.0]) - - .. figure:: ../images/sections/rhs_geometry.png - :align: center - :scale: 75 % - - RHS geometry. - - .. figure:: ../images/sections/rhs_mesh.png - :align: center - :scale: 75 % - - Mesh generated from the above geometry. - """ - points_inner = [] - points_outer = [] - # calculate internal radius - r_in = max(r_out - t, 0) - # construct the outer radius points - points_outer += draw_radius([r_out, r_out], r_out, np.pi, n_r) - points_outer += draw_radius([b - r_out, r_out], r_out, 1.5 * np.pi, n_r) - points_outer += draw_radius([b - r_out, d - r_out], r_out, 0, n_r) - points_outer += draw_radius([r_out, d - r_out], r_out, 0.5 * np.pi, n_r) - - points_inner += draw_radius([t + r_in, t + r_in], r_in, np.pi, n_r) - points_inner += draw_radius([b - t - r_in, t + r_in], r_in, 1.5 * np.pi, n_r) - points_inner += draw_radius([b - t - r_in, d - t - r_in], r_in, 0, n_r) - points_inner += draw_radius([t + r_in, d - t - r_in], r_in, 0.5 * np.pi, n_r) - - outer = Polygon(points_outer) - inner = Polygon(points_inner) - return Geometry(outer - inner, material) - - -def i_section( - d: float, - b: float, - t_f: float, - t_w: float, - r: float, - n_r: int, - material: pre.Material = pre.DEFAULT_MATERIAL, -) -> Geometry: # More specific description and less ambiguous? e.g. not an "S" section. - """Constructs an I-section centered at *(b/2, d/2)*, with depth *d*, width *b*, flange - thickness *t_f*, web thickness *t_w*, and root radius *r*, using *n_r* points to construct the - root radius. - - :param float d: Depth of the I-section - :param float b: Width of the I-section - :param float t_f: Flange thickness of the I-section - :param float t_w: Web thickness of the I-section - :param float r: Root radius of the I-section - :param int n_r: Number of points discretising the root radius - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates an I-section with a depth of 203, a width of 133, a flange - thickness of 7.8, a web thickness of 5.8 and a root radius of 8.9, using 16 points to - discretise the root radius. A mesh is generated with a maximum triangular area of 3.0:: - - import sectionproperties.pre.sections as sections - - geometry = sections.i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=16) - geometry.create_mesh(mesh_sizes=[3.0]) - - .. figure:: ../images/sections/isection_geometry.png - :align: center - :scale: 75 % - - I-section geometry. - - .. figure:: ../images/sections/isection_mesh.png - :align: center - :scale: 75 % - - Mesh generated from the above geometry. - """ - points = [] - - # add first three points - points.append([0, 0]) - points.append([b, 0]) - points.append([b, t_f]) - - # construct the bottom right radius - pt = [b * 0.5 + t_w * 0.5 + r, t_f + r] - points += draw_radius(pt, r, 1.5 * np.pi, n_r, False) - - # construct the top right radius - pt = [b * 0.5 + t_w * 0.5 + r, d - t_f - r] - points += draw_radius(pt, r, np.pi, n_r, False) - - # add the next four points - points.append([b, d - t_f]) - points.append([b, d]) - points.append([0, d]) - points.append([0, d - t_f]) - - # construct the top left radius - pt = [b * 0.5 - t_w * 0.5 - r, d - t_f - r] - points += draw_radius(pt, r, 0.5 * np.pi, n_r, False) - - # construct the bottom left radius - pt = [b * 0.5 - t_w * 0.5 - r, t_f + r] - points += draw_radius(pt, r, 0, n_r, False) - - # # add the last point - points.append([0, t_f]) - i_section = Polygon(points) - return Geometry(i_section, material) - - -def mono_i_section( - d, b_t, b_b, t_fb, t_ft, t_w, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL -) -> Geometry: - """Constructs a monosymmetric I-section centered at *(max(b_t, b_b)/2, d/2)*, with depth *d*, - top flange width *b_t*, bottom flange width *b_b*, top flange thickness *t_ft*, top flange - thickness *t_fb*, web thickness *t_w*, and root radius *r*, using *n_r* points to construct the - root radius. - - :param float d: Depth of the I-section - :param float b_t: Top flange width - :param float b_b: Bottom flange width - :param float t_ft: Top flange thickness of the I-section - :param float t_fb: Bottom flange thickness of the I-section - :param float t_w: Web thickness of the I-section - :param float r: Root radius of the I-section - :param int n_r: Number of points discretising the root radius - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates a monosymmetric I-section with a depth of 200, a top flange width - of 50, a top flange thickness of 12, a bottom flange width of 130, a bottom flange thickness of - 8, a web thickness of 6 and a root radius of 8, using 16 points to discretise the root radius. - A mesh is generated with a maximum triangular area of 3.0:: - - import sectionproperties.pre.sections as sections - - geometry = sections.mono_i_section( - d=200, b_t=50, b_b=130, t_ft=12, t_fb=8, t_w=6, r=8, n_r=16 - ) - geometry.create_mesh(mesh_sizes=[3.0]) - - .. figure:: ../images/sections/monoisection_geometry.png - :align: center - :scale: 75 % - - I-section geometry. - - .. figure:: ../images/sections/monoisection_mesh.png - :align: center - :scale: 75 % - - Mesh generated from the above geometry. - """ - points = [] - # calculate central axis - x_central = max(b_t, b_b) * 0.5 - - # add first three points - points.append([x_central - b_b * 0.5, 0]) - points.append([x_central + b_b * 0.5, 0]) - points.append([x_central + b_b * 0.5, t_fb]) - - # construct the bottom right radius - pt = [x_central + t_w * 0.5 + r, t_fb + r] - points += draw_radius(pt, r, 1.5 * np.pi, n_r, False) - - # construct the top right radius - pt = [x_central + t_w * 0.5 + r, d - t_ft - r] - points += draw_radius(pt, r, np.pi, n_r, False) - - # add the next four points - points.append([x_central + b_t * 0.5, d - t_ft]) - points.append([x_central + b_t * 0.5, d]) - points.append([x_central - b_t * 0.5, d]) - points.append([x_central - b_t * 0.5, d - t_ft]) - - # construct the top left radius - pt = [x_central - t_w * 0.5 - r, d - t_ft - r] - points += draw_radius(pt, r, 0.5 * np.pi, n_r, False) - - # construct the bottom left radius - pt = [x_central - t_w * 0.5 - r, t_fb + r] - points += draw_radius(pt, r, 0, n_r, False) - - # add the last point - points.append([x_central - b_b * 0.5, t_fb]) - - polygon = Polygon(points) - return Geometry(polygon, material) - - -def tapered_flange_i_section( - d, b, t_f, t_w, r_r, r_f, alpha, n_r, material: pre.Material = pre.DEFAULT_MATERIAL -) -> Geometry: - """Constructs a Tapered Flange I-section centered at *(b/2, d/2)*, with depth *d*, width *b*, - mid-flange thickness *t_f*, web thickness *t_w*, root radius *r_r*, flange radius *r_f* and - flange angle *alpha*, using *n_r* points to construct the radii. - - :param float d: Depth of the Tapered Flange I-section - :param float b: Width of the Tapered Flange I-section - :param float t_f: Mid-flange thickness of the Tapered Flange I-section (measured at the point - equidistant from the face of the web to the edge of the flange) - :param float t_w: Web thickness of the Tapered Flange I-section - :param float r_r: Root radius of the Tapered Flange I-section - :param float r_f: Flange radius of the Tapered Flange I-section - :param float alpha: Flange angle of the Tapered Flange I-section (degrees) - :param int n_r: Number of points discretising the radii - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates a Tapered Flange I-section with a depth of 588, a width of 191, a - mid-flange thickness of 27.2, a web thickness of 15.2, a root radius of 17.8, a flange radius - of 8.9 and a flange angle of 8°, using 16 points to discretise the radii. A mesh is generated - with a maximum triangular area of 20.0:: - - import sectionproperties.pre.sections as sections - - geometry = sections.tapered_flange_i_section( - d=588, b=191, t_f=27.2, t_w=15.2, r_r=17.8, r_f=8.9, alpha=8, n_r=16 - ) - geometry.create_mesh(mesh_sizes=[20.0]) - - .. figure:: ../images/sections/taperedisection_geometry.png - :align: center - :scale: 75 % - - I-section geometry. - - .. figure:: ../images/sections/taperedisection_mesh.png - :align: center - :scale: 75 % - - Mesh generated from the above geometry. - """ - points = [] - - # calculate alpha in radians - alpha_rad = np.pi * alpha / 180 - - # calculate the height of the flange toe and dimensions of the straight - x1 = b * 0.25 - t_w * 0.25 - r_f * (1 - np.sin(alpha_rad)) - y1 = x1 * np.tan(alpha_rad) - x2 = b * 0.25 - t_w * 0.25 - r_r * (1 - np.sin(alpha_rad)) - y2 = x2 * np.tan(alpha_rad) - y_t = t_f - y1 - r_f * np.cos(alpha_rad) - - # add first two points - points.append([0, 0]) - points.append([b, 0]) - - # construct the bottom right flange toe radius - if r_f == 0: - points.append([b, y_t]) - else: - for i in range(n_r): - # determine polar angle - theta = i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) - - # calculate the locations of the radius points - x = b - r_f + r_f * np.cos(theta) - y = y_t + r_f * np.sin(theta) - - # append the current points to the points list - points.append([x, y]) - - # construct the bottom right root radius - if r_r == 0: - points.append([b * 0.5 + t_w * 0.5, t_f + y2]) - else: - for i in range(n_r): - # determine polar angle - theta = (3.0 / 2 * np.pi - alpha_rad) - ( - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) - ) - - # calculate the locations of the radius points - x = b * 0.5 + t_w * 0.5 + r_r + r_r * np.cos(theta) - y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta) - - # append the current points to the points list - points.append([x, y]) - - # construct the top right root radius - if r_r == 0: - points.append([b * 0.5 + t_w * 0.5, d - t_f - y2]) - else: - for i in range(n_r): - # determine polar angle - theta = np.pi - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) - - # calculate the locations of the radius points - x = b * 0.5 + t_w * 0.5 + r_r + r_r * np.cos(theta) - y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta) - - # append the current points to the points list - points.append([x, y]) - - # construct the top right flange toe radius - if r_f == 0: - points.append([b, d - y_t]) - else: - for i in range(n_r): - # determine polar angle - theta = (3.0 * np.pi / 2 + alpha_rad) + i * 1.0 / max(1, n_r - 1) * ( - np.pi * 0.5 - alpha_rad - ) - - # calculate the locations of the radius points - x = b - r_f + r_f * np.cos(theta) - y = d - y_t + r_f * np.sin(theta) - - # append the current points to the points list - points.append([x, y]) - - # add the next two points - points.append([b, d]) - points.append([0, d]) - - # construct the top left flange toe radius - if r_f == 0: - points.append([0, d - y_t]) - else: - for i in range(n_r): - # determine polar angle - theta = np.pi + (i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)) - - # calculate the locations of the radius points - x = r_f + r_f * np.cos(theta) - y = d - y_t + r_f * np.sin(theta) - - # append the current points to the points list - points.append([x, y]) - - # construct the top left root radius - if r_r == 0: - points.append([b * 0.5 - t_w * 0.5, d - t_f - y2]) - else: - for i in range(n_r): - # determine polar angle - theta = (np.pi * 0.5 - alpha_rad) - ( - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) - ) - - # calculate the locations of the radius points - x = b * 0.5 - t_w * 0.5 - r_r + r_r * np.cos(theta) - y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta) - - # append the current points to the points list - points.append([x, y]) - - # construct the bottom left root radius - if r_r == 0: - points.append([b * 0.5 - t_w * 0.5, t_f + y2]) - else: - for i in range(n_r): - # determine polar angle - theta = -i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) - - # calculate the locations of the radius points - x = b * 0.5 - t_w * 0.5 - r_r + r_r * np.cos(theta) - y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta) - - # append the current points to the points list - points.append([x, y]) - - # construct the bottom left flange toe radius - if r_f == 0: - points.append([0, y_t]) - else: - for i in range(n_r): - # determine polar angle - theta = (np.pi * 0.5 + alpha_rad) + ( - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) - ) - - # calculate the locations of the radius points - x = r_f + r_f * np.cos(theta) - y = y_t + r_f * np.sin(theta) - - # append the current points to the points list - points.append([x, y]) - - polygon = Polygon(points) - return Geometry(polygon, material) - - -def channel_section( - d, b, t_f, t_w, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL -) -> Geometry: - """Constructs a parallel-flange channel (PFC) section with the bottom left corner at the origin *(0, 0)*, with depth *d*, - width *b*, flange thickness *t_f*, web thickness *t_w* and root radius *r*, using *n_r* points - to construct the root radius. - - :param float d: Depth of the PFC section - :param float b: Width of the PFC section - :param float t_f: Flange thickness of the PFC section - :param float t_w: Web thickness of the PFC section - :param float r: Root radius of the PFC section - :param int n_r: Number of points discretising the root radius - :param shift: Vector that shifts the cross-section by *(x, y)* - :type shift: list[float, float] - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates a PFC section with a depth of 250, a width of 90, a flange - thickness of 15, a web thickness of 8 and a root radius of 12, using 8 points to discretise the - root radius. A mesh is generated with a maximum triangular area of 5.0:: - - import sectionproperties.pre.sections as sections - - geometry = sections.channel_section(d=250, b=90, t_f=15, t_w=8, r=12, n_r=8) - geometry.create_mesh(mesh_sizes=[5.0]) - - .. figure:: ../images/sections/pfc_geometry.png - :align: center - :scale: 75 % - - PFC geometry. - - .. figure:: ../images/sections/pfc_mesh.png - :align: center - :scale: 75 % - - Mesh generated from the above geometry. - """ - points = [] - - # add first three points - points.append([0, 0]) - points.append([b, 0]) - points.append([b, t_f]) - - # construct the bottom right radius - pt = [t_w + r, t_f + r] - points += draw_radius(pt, r, 1.5 * np.pi, n_r, False) - - # construct the top right radius - pt = [t_w + r, d - t_f - r] - points += draw_radius(pt, r, np.pi, n_r, False) - - # add last three points - points.append([b, d - t_f]) - points.append([b, d]) - points.append([0, d]) - - polygon = Polygon(points) - return Geometry(polygon, material) - - -def tapered_flange_channel( - d, b, t_f, t_w, r_r, r_f, alpha, n_r, material: pre.Material = pre.DEFAULT_MATERIAL -) -> Geometry: - """Constructs a Tapered Flange Channel section with the bottom left corner at the origin - *(0, 0)*, with depth *d*, width *b*, mid-flange thickness *t_f*, web thickness *t_w*, root - radius *r_r*, flange radius *r_f* and flange angle *alpha*, using *n_r* points to construct the - radii. - - :param float d: Depth of the Tapered Flange Channel section - :param float b: Width of the Tapered Flange Channel section - :param float t_f: Mid-flange thickness of the Tapered Flange Channel section (measured at the - point equidistant from the face of the web to the edge of the flange) - :param float t_w: Web thickness of the Tapered Flange Channel section - :param float r_r: Root radius of the Tapered Flange Channel section - :param float r_f: Flange radius of the Tapered Flange Channel section - :param float alpha: Flange angle of the Tapered Flange Channel section (degrees) - :param int n_r: Number of points discretising the radii - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates a Tapered Flange Channel section with a depth of 10, a width of - 3.5, a mid-flange thickness of 0.575, a web thickness of 0.475, a root radius of 0.575, a - flange radius of 0.4 and a flange angle of 8°, using 16 points to discretise the radii. A mesh - is generated with a maximum triangular area of 0.02:: - - import sectionproperties.pre.sections as sections - - geometry = sections.tapered_flange_channel( - d=10, b=3.5, t_f=0.575, t_w=0.475, r_r=0.575, r_f=0.4, alpha=8, n_r=16 - ) - geometry.create_mesh(mesh_sizes=[0.02]) - - .. figure:: ../images/sections/taperedchannel_geometry.png - :align: center - :scale: 75 % - - Tapered flange channel geometry. - - .. figure:: ../images/sections/taperedchannel_mesh.png - :align: center - :scale: 75 % - - Mesh generated from the above geometry. - """ - points = [] - - # calculate alpha in radians - alpha_rad = np.pi * alpha / 180 - - # calculate the height of the flange toe and dimensions of the straight - x1 = b * 0.5 - t_w * 0.5 - r_f * (1 - np.sin(alpha_rad)) - y1 = x1 * np.tan(alpha_rad) - x2 = b * 0.5 - t_w * 0.5 - r_r * (1 - np.sin(alpha_rad)) - y2 = x2 * np.tan(alpha_rad) - y_t = t_f - y1 - r_f * np.cos(alpha_rad) - - # add first two points - points.append([0, 0]) - points.append([b, 0]) - - # construct the bottom right flange toe radius - if r_f == 0: - points.append([b, y_t]) - else: - for i in range(n_r): - # determine polar angle - theta = i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) - - # calculate the locations of the radius points - x = b - r_f + r_f * np.cos(theta) - y = y_t + r_f * np.sin(theta) - - # append the current points to the points list - points.append([x, y]) - - # construct the bottom right root radius - if r_r == 0: - points.append([t_w, t_f + y2]) - else: - for i in range(n_r): - # determine polar angle - theta = (3.0 / 2 * np.pi - alpha_rad) - ( - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) - ) - - # calculate the locations of the radius points - x = t_w + r_r + r_r * np.cos(theta) - y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta) - - # append the current points to the points list - points.append([x, y]) - - # construct the top right root radius - if r_r == 0: - points.append([t_w, d - t_f - y2]) - else: - for i in range(n_r): - # determine polar angle - theta = np.pi - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) - - # calculate the locations of the radius points - x = t_w + r_r + r_r * np.cos(theta) - y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta) - - # append the current points to the points list - points.append([x, y]) - - # construct the top right flange toe radius - if r_f == 0: - points.append([b, d - y_t]) - else: - for i in range(n_r): - # determine polar angle - theta = (3.0 * np.pi / 2 + alpha_rad) + ( - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) - ) - - # calculate the locations of the radius points - x = b - r_f + r_f * np.cos(theta) - y = d - y_t + r_f * np.sin(theta) - - # append the current points to the points list - points.append([x, y]) - - # add the final two points - points.append([b, d]) - points.append([0, d]) - - polygon = Polygon(points) - return Geometry(polygon, material) - - -def tee_section( - d, b, t_f, t_w, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL -) -> Geometry: - """Constructs a Tee section with the top left corner at *(0, d)*, with depth *d*, width *b*, - flange thickness *t_f*, web thickness *t_w* and root radius *r*, using *n_r* points to - construct the root radius. - - :param float d: Depth of the Tee section - :param float b: Width of the Tee section - :param float t_f: Flange thickness of the Tee section - :param float t_w: Web thickness of the Tee section - :param float r: Root radius of the Tee section - :param int n_r: Number of points discretising the root radius - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates a Tee section with a depth of 200, a width of 100, a flange - thickness of 12, a web thickness of 6 and a root radius of 8, using 8 points to discretise the - root radius. A mesh is generated with a maximum triangular area of 3.0:: - - import sectionproperties.pre.sections as sections - - geometry = sections.tee_section(d=200, b=100, t_f=12, t_w=6, r=8, n_r=8) - geometry.create_mesh(mesh_sizes=[3.0]) - - .. figure:: ../images/sections/tee_geometry.png - :align: center - :scale: 75 % - - Tee section geometry. - - .. figure:: ../images/sections/tee_mesh.png - :align: center - :scale: 75 % - - Mesh generated from the above geometry. - """ - points = [] - # add first two points - points.append([b * 0.5 - t_w * 0.5, 0]) - points.append([b * 0.5 + t_w * 0.5, 0]) - - # construct the top right radius - pt = [b * 0.5 + t_w * 0.5 + r, d - t_f - r] - points += draw_radius(pt, r, np.pi, n_r, False) - - # add next four points - points.append([b, d - t_f]) - points.append([b, d]) - points.append([0, d]) - points.append([0, d - t_f]) - - # construct the top left radius - pt = [b * 0.5 - t_w * 0.5 - r, d - t_f - r] - points += draw_radius(pt, r, 0.5 * np.pi, n_r, False) - - polygon = Polygon(points) - return Geometry(polygon, material) - - -def angle_section( - d, b, t, r_r, r_t, n_r, material: pre.Material = pre.DEFAULT_MATERIAL -) -> Geometry: - """Constructs an angle section with the bottom left corner at the origin *(0, 0)*, with depth - *d*, width *b*, thickness *t*, root radius *r_r* and toe radius *r_t*, using *n_r* points to - construct the radii. - - :param float d: Depth of the angle section - :param float b: Width of the angle section - :param float t: Thickness of the angle section - :param float r_r: Root radius of the angle section - :param float r_t: Toe radius of the angle section - :param int n_r: Number of points discretising the radii - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates an angle section with a depth of 150, a width of 100, a thickness - of 8, a root radius of 12 and a toe radius of 5, using 16 points to discretise the radii. A - mesh is generated with a maximum triangular area of 2.0:: - - import sectionproperties.pre.sections as sections - - geometry = sections.angle_section(d=150, b=100, t=8, r_r=12, r_t=5, n_r=16) - geometry.create_mesh(mesh_sizes=[2.0]) - - .. figure:: ../images/sections/angle_geometry.png - :align: center - :scale: 75 % - - Angle section geometry. - - .. figure:: ../images/sections/angle_mesh.png - :align: center - :scale: 75 % - """ - if r_t > t: - raise ValueError( - "The radius of the toe (r_t) cannot be larger than the toe thickness (t)." - ) - - points = [] - - # add first two points - points.append([0, 0]) - points.append([b, 0]) - - # construct the bottom toe radius - pt = [b - r_t, t - r_t] - points += draw_radius(pt, r_t, 0, n_r) - - # construct the root radius - pt = [t + r_r, t + r_r] - points += draw_radius(pt, r_r, 1.5 * np.pi, n_r, False) - - # construct the top toe radius - pt = [t - r_t, d - r_t] - points += draw_radius(pt, r_t, 0, n_r) - - # add the next point - points.append([0, d]) - - polygon = Polygon(points) - return Geometry(polygon, material) - - -def cee_section( - d, b, l, t, r_out, n_r, material: pre.Material = pre.DEFAULT_MATERIAL -) -> Geometry: - """Constructs a Cee section (typical of cold-formed steel) with the bottom left corner at the - origin *(0, 0)*, with depth *d*, width *b*, lip *l*, thickness *t* and outer radius *r_out*, - using *n_r* points to construct the radius. If the outer radius is less than the thickness - of the Cee Section, the inner radius is set to zero. - - :param float d: Depth of the Cee section - :param float b: Width of the Cee section - :param float l: Lip of the Cee section - :param float t: Thickness of the Cee section - :param float r_out: Outer radius of the Cee section - :param int n_r: Number of points discretising the outer radius - :raises Exception: Lip length must be greater than the outer radius - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates a Cee section with a depth of 125, a width of 50, a lip of 30, a - thickness of 1.5 and an outer radius of 6, using 8 points to discretise the radius. A mesh is - generated with a maximum triangular area of 0.25:: - - import sectionproperties.pre.sections as sections - - geometry = sections.cee_section(d=125, b=50, l=30, t=1.5, r_out=6, n_r=8) - geometry.create_mesh(mesh_sizes=[0.25]) - - .. figure:: ../images/sections/cee_geometry.png - :align: center - :scale: 75 % - - Cee section geometry. - - .. figure:: ../images/sections/cee_mesh.png - :align: center - :scale: 75 % - """ - # ensure the lip length is greater than the outer radius - if l < r_out: - raise Exception("Lip length must be greater than the outer radius") - - points = [] - - # calculate internal radius - r_in = max(r_out - t, 0) - - # construct the outer bottom left radius - points += draw_radius([r_out, r_out], r_out, np.pi, n_r) - - # construct the outer bottom right radius - points += draw_radius([b - r_out, r_out], r_out, 1.5 * np.pi, n_r) - - if r_out != l: - # add next two points - points.append([b, l]) - points.append([b - t, l]) - - # construct the inner bottom right radius - points += draw_radius([b - t - r_in, t + r_in], r_in, 0, n_r, False) - - # construct the inner bottom left radius - points += draw_radius([t + r_in, t + r_in], r_in, 1.5 * np.pi, n_r, False) - - # construct the inner top left radius - points += draw_radius([t + r_in, d - t - r_in], r_in, np.pi, n_r, False) - - # construct the inner top right radius - points += draw_radius([b - t - r_in, d - t - r_in], r_in, 0.5 * np.pi, n_r, False) - - if r_out != l: - # add next two points - points.append([b - t, d - l]) - points.append([b, d - l]) - - # construct the outer top right radius - points += draw_radius([b - r_out, d - r_out], r_out, 0, n_r) - - # construct the outer top left radius - points += draw_radius([r_out, d - r_out], r_out, 0.5 * np.pi, n_r) - - polygon = Polygon(points) - return Geometry(polygon, material) - - -def zed_section( - d, b_l, b_r, l, t, r_out, n_r, material: pre.Material = pre.DEFAULT_MATERIAL -) -> Geometry: - """Constructs a zed section with the bottom left corner at the origin *(0, 0)*, with depth *d*, - left flange width *b_l*, right flange width *b_r*, lip *l*, thickness *t* and outer radius - *r_out*, using *n_r* points to construct the radius. If the outer radius is less than the - thickness of the Zed Section, the inner radius is set to zero. - - :param float d: Depth of the zed section - :param float b_l: Left flange width of the Zed section - :param float b_r: Right flange width of the Zed section - :param float l: Lip of the Zed section - :param float t: Thickness of the Zed section - :param float r_out: Outer radius of the Zed section - :param int n_r: Number of points discretising the outer radius - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates a zed section with a depth of 100, a left flange width of 40, a - right flange width of 50, a lip of 20, a thickness of 1.2 and an outer radius of 5, using 8 - points to discretise the radius. A mesh is generated with a maximum triangular area of 0.15:: - - import sectionproperties.pre.sections as sections - - geometry = sections.zed_section(d=100, b_l=40, b_r=50, l=20, t=1.2, r_out=5, n_r=8) - geometry.create_mesh(mesh_sizes=[0.15]) - - .. figure:: ../images/sections/zed_geometry.png - :align: center - :scale: 75 % - - zed section geometry. - - .. figure:: ../images/sections/zed_mesh.png - :align: center - :scale: 75 % - """ - # ensure the lip length is greater than the outer radius - if l < r_out: - raise Exception("Lip length must be greater than the outer radius") - - points = [] - - # calculate internal radius - r_in = max(r_out - t, 0) - - # construct the outer bottom left radius - points += draw_radius([r_out, r_out], r_out, np.pi, n_r) - - # construct the outer bottom right radius - points += draw_radius([b_r - r_out, r_out], r_out, 1.5 * np.pi, n_r) - - if r_out != l: - # add next two points - points.append([b_r, l]) - points.append([b_r - t, l]) - - # construct the inner bottom right radius - points += draw_radius([b_r - t - r_in, t + r_in], r_in, 0, n_r, False) - - # construct the inner bottom left radius - points += draw_radius([t + r_in, t + r_in], r_in, 1.5 * np.pi, n_r, False) - - # construct the outer top right radius - points += draw_radius([t - r_out, d - r_out], r_out, 0, n_r) - - # construct the outer top left radius - points += draw_radius([t - b_l + r_out, d - r_out], r_out, 0.5 * np.pi, n_r) - - if r_out != l: - # add the next two points - points.append([t - b_l, d - l]) - points.append([t - b_l + t, d - l]) - - # construct the inner top left radius - points += draw_radius([2 * t - b_l + r_in, d - t - r_in], r_in, np.pi, n_r, False) - - # construct the inner top right radius - points += draw_radius([-r_in, d - t - r_in], r_in, 0.5 * np.pi, n_r, False) - polygon = Polygon(points) - return Geometry(polygon, material) - - -zee_section = zed_section # An alias for our American friends (and friends who use "American English") - - -def cruciform_section( - d, b, t, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL -) -> Geometry: - """Constructs a cruciform section centered at the origin *(0, 0)*, with depth *d*, width *b*, - thickness *t* and root radius *r*, using *n_r* points to construct the root radius. - - :param float d: Depth of the cruciform section - :param float b: Width of the cruciform section - :param float t: Thickness of the cruciform section - :param float r: Root radius of the cruciform section - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - - The following example creates a cruciform section with a depth of 250, a width of 175, a - thickness of 12 and a root radius of 16, using 16 points to discretise the radius. A mesh is - generated with a maximum triangular area of 5.0:: - - import sectionproperties.pre.sections as sections - - geometry = sections.cruciform_section(d=250, b=175, t=12, r=16, n_r=16) - geometry.create_mesh(mesh_sizes=[5.0]) - - .. figure:: ../images/sections/cruciform_geometry.png - :align: center - :scale: 75 % - - Cruciform section geometry. - - .. figure:: ../images/sections/cruciform_mesh.png - :align: center - :scale: 75 % - """ - points = [] - - # add first two points - points.append([-t * 0.5, -d * 0.5]) - points.append([t * 0.5, -d * 0.5]) - - # construct the bottom right radius - pt = [0.5 * t + r, -0.5 * t - r] - points += draw_radius(pt, r, np.pi, n_r, False) - - # add the next two points - points.append([0.5 * b, -t * 0.5]) - points.append([0.5 * b, t * 0.5]) - - # construct the top right radius - pt = [0.5 * t + r, 0.5 * t + r] - points += draw_radius(pt, r, 1.5 * np.pi, n_r, False) - - # add the next two points - points.append([t * 0.5, 0.5 * d]) - points.append([-t * 0.5, 0.5 * d]) - - # construct the top left radius - pt = [-0.5 * t - r, 0.5 * t + r] - points += draw_radius(pt, r, 0, n_r, False) - - # add the next two points - points.append([-0.5 * b, t * 0.5]) - points.append([-0.5 * b, -t * 0.5]) - - # construct the bottom left radius - pt = [-0.5 * t - r, -0.5 * t - r] - points += draw_radius(pt, r, 0.5 * np.pi, n_r, False) - - polygon = Polygon(points) - return Geometry(polygon, material) - - -def polygon_hollow_section( - d, t, n_sides, r_in=0, n_r=1, rot=0, material: pre.Material = pre.DEFAULT_MATERIAL -) -> Geometry: - """Constructs a regular hollow polygon section centered at *(0, 0)*, with a pitch circle - diameter of bounding polygon *d*, thickness *t*, number of sides *n_sides* and an optional - inner radius *r_in*, using *n_r* points to construct the inner and outer radii (if radii is - specified). - - :param float d: Pitch circle diameter of the outer bounding polygon (i.e. diameter of circle - that passes through all vertices of the outer polygon) - :param float t: Thickness of the polygon section wall - :param float r_in: Inner radius of the polygon corners. By default, if not specified, a polygon - with no corner radii is generated. - :param int n_r: Number of points discretising the inner and outer radii, ignored if no inner - radii is specified - :param rot: Initial counterclockwise rotation in degrees. By default bottom face is aligned - with x axis. - :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry - :raises Exception: Number of sides in polygon must be greater than or equal to 3 - - The following example creates an Octagonal section (8 sides) with a diameter of 200, a - thickness of 6 and an inner radius of 20, using 12 points to discretise the inner and outer - radii. A mesh is generated with a maximum triangular area of 5:: - - import sectionproperties.pre.sections as sections - - geometry = sections.polygon_hollow_section(d=200, t=6, n_sides=8, r_in=20, n_r=12) - geometry.create_mesh(mesh_sizes=[5]) - - .. figure:: ../images/sections/polygon_geometry.png - :align: center - :scale: 75 % - - Octagonal section geometry. - - .. figure:: ../images/sections/polygon_mesh.png - :align: center - :scale: 75 % - - Mesh generated from the above geometry. - """ - outer_points = [] - inner_points = [] - - if n_sides < 3: - msg = "n_sides required to be greater than 3 for polygon_section()" - raise Exception(msg) - - # initial rotation - rot = rot * np.pi / 180 # radians - - # determine triangular segment angle - alpha = 2 * np.pi / n_sides # radians - - # determine distance from origin to point perpendicular on face of side - a_out = d / 2 * np.cos(alpha / 2) - a_in = a_out - t - - # determine side length for outer & inner faces neglecting radii - side_length_out = d * np.sin(alpha / 2) - side_length_in = a_in / a_out * side_length_out - - # check limit on internal radii, if exceeded then radii merge to circle - if r_in > a_in: - r_in = a_in - circle = True - else: - circle = False - - # calculate external radius, if r_in is zero, r_out also is zero - if r_in == 0: - r_out = 0 - n_r = 1 - else: - r_out = r_in + t - - # equivalent side length of half the corner radii triangular segment - c_out = r_out * (side_length_out / 2) / a_out - c_in = r_in * (side_length_in / 2) / a_in - - # determine straight side length between corner radii (if present) - side_length_straight_out = side_length_out - (2 * c_out) - side_length_straight_in = side_length_in - (2 * c_in) - - # temp list for repeating geometry - outer_base_points = [] - inner_base_points = [] - - # start at bottom face, constructing one corner radii, then rotate by initial rotation + - # alpha and repeat for n_side number of times to form full section perimeter - - # construct the first radius (bottom right) - for i in range(n_r): - # determine polar angle - theta = 1 / 2 * np.pi + i * 1.0 / max(1, n_r - 1) * alpha - - # calculate location of inner and outer points - x_outer = side_length_straight_out / 2 - r_out * np.cos(theta) - y_outer = -a_out + r_out - r_out * np.sin(theta) - x_inner = side_length_straight_in / 2 - r_in * np.cos(theta) - y_inner = -a_in + r_in - r_in * np.sin(theta) - - # append the current temporary points to the temporary points list - outer_base_points.append([x_outer, y_outer]) - inner_base_points.append([x_inner, y_inner]) - - for i in range(n_sides): - for point in outer_base_points: - point_new = rotate(point, alpha * i + rot) - outer_points.append(point_new) - - for point in inner_base_points: - point_new = rotate(point, alpha * i + rot) - inner_points.append(point_new) - - outer_polygon = Polygon(outer_points) - inner_polygon = Polygon(inner_points) - return Geometry(outer_polygon - inner_polygon, material) - - -def rotate(point, angle: float): - """ - Rotate a point counterclockwise by a given angle around origin [0, 0] - - :param list point: Point coordinates to be rotated - :param float angle: Angle to rotate point coordinates - :return: Coordinates of rotated point - :rtype: list[float, float] - """ - - pt_x, pt_y = point - - c = np.cos(angle) - s = np.sin(angle) - - new_x = c * pt_x - s * pt_y - new_y = s * pt_x + c * pt_y - - return [new_x, new_y] - - -def box_girder_section( - d, b_t, b_b, t_ft, t_fb, t_w, material: pre.Material = pre.DEFAULT_MATERIAL -): - """Constructs a box girder section centered at at *(max(b_t, b_b)/2, d/2)*, with depth *d*, top - width *b_t*, bottom width *b_b*, top flange thickness *t_ft*, bottom flange thickness *t_fb* - and web thickness *t_w*. - - :param float d: Depth of the Box Girder section - :param float b_t: Top width of the Box Girder section - :param float b_b: Bottom width of the Box Girder section - :param float t_ft: Top flange thickness of the Box Girder section - :param float t_fb: Bottom flange thickness of the Box Girder section - :param float t_w: Web thickness of the Box Girder section - - The following example creates a Box Girder section with a depth of 1200, a top width of 1200, a - bottom width of 400, a top flange thickness of 16, a bottom flange thickness of 12 and a web - thickness of 8. A mesh is generated with a maximum triangular area of 5.0:: - - import sectionproperties.pre.sections as sections - - geometry = sections.box_girder_section(d=1200, b_t=1200, b_b=400, t_ft=100, t_fb=80, t_w=50) - geometry.create_mesh(mesh_sizes=[200.0]) - - .. figure:: ../images/sections/box_girder_geometry.png - :align: center - :scale: 75 % - - Box Girder geometry. - - .. figure:: ../images/sections/box_girder_mesh.png - :align: center - :scale: 75 % - - Mesh generated from the above geometry. - """ - outer_points = [] - inner_points = [] - - # calculate central axis - x_c = max(b_t, b_b) * 0.5 - - # determine side wall angle - if b_t < b_b: - phi_b = np.arctan2(d, 0.5 * (b_b - b_t)) - phi_t = np.pi - phi_b - else: - phi_t = np.arctan2(d, 0.5 * (b_t - b_b)) - phi_b = np.pi - phi_t - - # determine inner wall x-offsets - x_bot = t_fb / np.tan(np.pi - phi_b) - x_top = t_ft / np.tan(np.pi - phi_t) - web_x = abs(t_w / np.sin(np.pi - phi_b)) - - # add outer points - outer_points.append([x_c - 0.5 * b_b, 0]) - outer_points.append([x_c + 0.5 * b_b, 0]) - outer_points.append([x_c + 0.5 * b_t, d]) - outer_points.append([x_c - 0.5 * b_t, d]) - - # add inner points - inner_points.append([x_c - 0.5 * b_b - x_bot + web_x, t_fb]) - inner_points.append([x_c + 0.5 * b_b + x_bot - web_x, t_fb]) - inner_points.append([x_c + 0.5 * b_t + x_top - web_x, d - t_ft]) - inner_points.append([x_c - 0.5 * b_t - x_top + web_x, d - t_ft]) - - outer_polygon = Polygon(outer_points) - inner_polygon = Polygon(inner_points) - - return Geometry(outer_polygon - inner_polygon, material) diff --git a/sectionproperties/pre/library/bridge_sections.py b/sectionproperties/pre/library/bridge_sections.py new file mode 100644 index 00000000..58b992a4 --- /dev/null +++ b/sectionproperties/pre/library/bridge_sections.py @@ -0,0 +1 @@ +# to be completed by @ccaprani diff --git a/sectionproperties/pre/library/concrete_sections.py b/sectionproperties/pre/library/concrete_sections.py new file mode 100644 index 00000000..1f95a17f --- /dev/null +++ b/sectionproperties/pre/library/concrete_sections.py @@ -0,0 +1,234 @@ +import numpy as np +from shapely.geometry import Polygon +import sectionproperties.pre.pre as pre +from sectionproperties.pre.geometry import Geometry +import sectionproperties.pre.library.standard_sections as standard_sections + + +def concrete_rectangular_section( + b: float, + d: float, + dia: float, + n_bar: int, + n_circle: int, + cover: float, + conc_mat: pre.Material = pre.DEFAULT_MATERIAL, + steel_mat: pre.Material = pre.DEFAULT_MATERIAL, +) -> Geometry: + """Constructs a concrete rectangular section of width *b* and depth *d*, with *n_bar* steel bars + of diameter *dia*, discretised with *n_circle* points with equal side and bottom *cover* to the + steel. + + :param float b: Concrete section depth + :param float d: Concrete section width + :param float dia: Diameter of the steel reinforcing bars + :param int n_bar: Number of steel reinforcing bars + :param int n_circle: Number of points discretising the steel reinforcing bars + :param float cover: Side and bottom cover to the steel reinforcing bars + :param Optional[sectionproperties.pre.pre.Material] conc_mat: Material to associate with + the concrete + :param Optional[sectionproperties.pre.pre.Material] steel_mat: Material to associate with + the steel + + :raises ValueErorr: If the number of bars is not greater than or equal to 2 + + The following example creates a 600D x 300W concrete beam with 3N20 steel reinforcing bars and + 30 mm cover:: + + from sectionproperties.pre.library.concrete_sections import concrete_rectangular_section + from sectionproperties.pre.pre import Material + + concrete = Material( + name='Concrete', elastic_modulus=30.1e3, poissons_ratio=0.2, yield_strength=32, color='lightgrey' + ) + steel = Material( + name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, yield_strength=500, color='grey' + ) + + geometry = concrete_rectangular_section( + b=300, d=600, dia=20, n_bar=3, n_circle=24, cover=30, conc_mat=concrete, steel_mat=steel + ) + geometry.create_mesh(mesh_sizes=[500]) + + .. figure:: ../images/sections/concrete_rectangular_section_geometry.png + :align: center + :scale: 50 % + + Concrete rectangular section geometry. + + .. figure:: ../images/sections/concrete_rectangular_section_mesh.png + :align: center + :scale: 50 % + + Mesh generated from the above geometry. + """ + + if n_bar < 2: + raise ValueError("Please provide 2 or more steel reinforcing bars.") + + geom = standard_sections.rectangular_section(b=b, d=d, material=conc_mat) + + x_i = cover + dia / 2 + spacing = (b - 2 * cover - dia) / (n_bar - 1) + + for i in range(n_bar): + bar = standard_sections.circular_section(d=dia, n=n_circle, material=steel_mat) + geom += bar.shift_section(x_offset=x_i + spacing * i, y_offset=cover + dia / 2) + + return geom + + +def concrete_tee_section( + b: float, + d: float, + b_f: float, + d_f: float, + dia: float, + n_bar: int, + n_circle: int, + cover: float, + conc_mat: pre.Material = pre.DEFAULT_MATERIAL, + steel_mat: pre.Material = pre.DEFAULT_MATERIAL, +) -> Geometry: + """Constructs a concrete tee section of width *b*, depth *d*, flange width *b_f* and flange + depth *d_f* with *n_bar* steel bars of diameter *dia*, discretised with *n_circle* points with + equal side and bottom *cover* to the steel. + + :param float b: Concrete section depth + :param float d: Concrete section width + :param float b_f: Concrete section flange depth + :param float d_f: Concrete section flange width + :param float dia: Diameter of the steel reinforcing bars + :param int n_bar: Number of steel reinforcing bars + :param int n_circle: Number of points discretising the steel reinforcing bars + :param float cover: Side and bottom cover to the steel reinforcing bars + :param Optional[sectionproperties.pre.pre.Material] conc_mat: Material to associate with + the concrete + :param Optional[sectionproperties.pre.pre.Material] steel_mat: Material to associate with + the steel + + :raises ValueErorr: If the number of bars is not greater than or equal to 2 + + The following example creates a 900D x 450W concrete beam with a 1200W x 250D flange, with 5N24 + steel reinforcing bars and 30 mm cover:: + + from sectionproperties.pre.library.concrete_sections import concrete_tee_section + from sectionproperties.pre.pre import Material + + concrete = Material( + name='Concrete', elastic_modulus=30.1e3, poissons_ratio=0.2, yield_strength=32, color='lightgrey' + ) + steel = Material( + name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, yield_strength=500, color='grey' + ) + + geometry = concrete_tee_section( + b=450, d=900, b_f=1200, d_f=250, dia=24, n_bar=5, n_circle=24, cover=30, + conc_mat=concrete, steel_mat=steel + ) + geometry.create_mesh(mesh_sizes=[500]) + + .. figure:: ../images/sections/concrete_tee_section_geometry.png + :align: center + :scale: 50 % + + Concrete tee section geometry. + + .. figure:: ../images/sections/concrete_tee_section_mesh.png + :align: center + :scale: 50 % + + Mesh generated from the above geometry. + """ + + if n_bar < 2: + raise ValueError("Please provide 2 or more steel reinforcing bars.") + + geom = standard_sections.rectangular_section(b=b, d=d - d_f, material=conc_mat) + flange = standard_sections.rectangular_section(b=b_f, d=d_f, material=conc_mat) + geom += flange.align_center(align_to=geom).align_to(other=geom, on="top") + # geom += flange.align_center(align_to=geom) + + x_i = cover + dia / 2 + spacing = (b - 2 * cover - dia) / (n_bar - 1) + + for i in range(n_bar): + bar = standard_sections.circular_section(d=dia, n=n_circle, material=steel_mat) + geom += bar.shift_section(x_offset=x_i + spacing * i, y_offset=cover + dia / 2) + + return geom + + +def concrete_circular_section( + d: float, + n: int, + dia: float, + n_bar: int, + n_circle: int, + cover: float, + conc_mat: pre.Material = pre.DEFAULT_MATERIAL, + steel_mat: pre.Material = pre.DEFAULT_MATERIAL, +) -> Geometry: + """Constructs a concrete circular section of diameter *d* discretised with *n* points, with + *n_bar* steel bars of diameter *dia*, discretised with *n_circle* points with equal side and + bottom *cover* to the steel. + + :param float d: Concrete diameter + :param float n: Number of points discretising the concrete section + :param float dia: Diameter of the steel reinforcing bars + :param int n_bar: Number of steel reinforcing bars + :param int n_circle: Number of points discretising the steel reinforcing bars + :param float cover: Side and bottom cover to the steel reinforcing bars + :param Optional[sectionproperties.pre.pre.Material] conc_mat: Material to associate with + the concrete + :param Optional[sectionproperties.pre.pre.Material] steel_mat: Material to associate with + the steel + + :raises ValueErorr: If the number of bars is not greater than or equal to 2 + + The following example creates a 450DIA concrete column with with 6N20 steel reinforcing bars + and 45 mm cover:: + + from sectionproperties.pre.library.concrete_sections import concrete_circular_section + from sectionproperties.pre.pre import Material + + concrete = Material( + name='Concrete', elastic_modulus=30.1e3, poissons_ratio=0.2, yield_strength=32, color='lightgrey' + ) + steel = Material( + name='Steel', elastic_modulus=200e3, poissons_ratio=0.3, yield_strength=500, color='grey' + ) + + geometry = concrete_circular_section( + d=450, n=64, dia=20, n_bar=6, n_circle=24, cover=45, conc_mat=concrete, steel_mat=steel + ) + geometry.create_mesh(mesh_sizes=[500]) + + .. figure:: ../images/sections/concrete_circular_section_geometry.png + :align: center + :scale: 50 % + + Concrete circular section geometry. + + .. figure:: ../images/sections/concrete_circular_section_mesh.png + :align: center + :scale: 50 % + + Mesh generated from the above geometry. + """ + + if n_bar < 2: + raise ValueError("Please provide 2 or more steel reinforcing bars.") + + geom = standard_sections.circular_section(d=d, n=n, material=conc_mat) + + r = d / 2 - cover - dia / 2 + d_theta = 2 * np.pi / n_bar + + for i in range(n_bar): + bar = standard_sections.circular_section(d=dia, n=n_circle, material=steel_mat) + geom += bar.shift_section( + x_offset=r * np.cos(i * d_theta), y_offset=r * np.sin(i * d_theta) + ) + + return geom diff --git a/sectionproperties/pre/nastran_sections.py b/sectionproperties/pre/library/nastran_sections.py similarity index 92% rename from sectionproperties/pre/nastran_sections.py rename to sectionproperties/pre/library/nastran_sections.py index 023e362a..198a13b9 100644 --- a/sectionproperties/pre/nastran_sections.py +++ b/sectionproperties/pre/library/nastran_sections.py @@ -1,8 +1,8 @@ import numpy as np from shapely.geometry import Polygon -from sectionproperties.pre.sections import Geometry, CompoundGeometry -from sectionproperties.pre import pre -from sectionproperties.pre.sections import draw_radius +from sectionproperties.pre.geometry import Geometry +import sectionproperties.pre.pre as pre +from sectionproperties.pre.library.utils import draw_radius def nastran_bar( @@ -19,9 +19,9 @@ def nastran_bar( The following example creates a BAR cross-section with a depth of 1.5 and width of 2.0, and generates a mesh with a maximum triangular area of 0.001:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_bar - geometry = nsections.nastran_bar(DIM1=2.0, DIM2=1.5) + geometry = nastran_bar(DIM1=2.0, DIM2=1.5) mesh = geometry.create_mesh(mesh_sizes=[0.001]) .. figure:: ../images/sections/bar_geometry.png @@ -71,9 +71,9 @@ def nastran_box( The following example creates a BOX cross-section with a depth of 3.0 and width of 4.0, and generates a mesh with a maximum triangular area of 0.001:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_box - geometry = nsections.nastran_box(DIM1=4.0, DIM2=3.0, DIM3=0.375, DIM4=0.5) + geometry = nastran_box(DIM1=4.0, DIM2=3.0, DIM3=0.375, DIM4=0.5) mesh = geometry.create_mesh(mesh_sizes=[0.001]) .. figure:: ../images/sections/box_geometry.png @@ -91,23 +91,30 @@ def nastran_box( # Ensure dimensions are physically relevant np.testing.assert_(2.0 * DIM4 < DIM1, "Invalid geometry specified.") np.testing.assert_(2.0 * DIM3 < DIM2, "Invalid geometry specified.") - - points = [ + points_outer = [ [-0.5 * DIM1, -0.5 * DIM2], [0.5 * DIM1, -0.5 * DIM2], [0.5 * DIM1, 0.5 * DIM2], [-0.5 * DIM1, 0.5 * DIM2], + ] + points_inner = [ [-0.5 * DIM1 + DIM4, -0.5 * DIM2 + DIM3], [0.5 * DIM1 - DIM4, -0.5 * DIM2 + DIM3], [0.5 * DIM1 - DIM4, 0.5 * DIM2 - DIM3], [-0.5 * DIM1 + DIM4, 0.5 * DIM2 - DIM3], ] - geometry = Geometry(Polygon(points), material) + + inner_box = Polygon(points_inner) + outer_box = Polygon(points_outer) + C = (0.5 * DIM1, 0.5 * DIM2) D = (0.5 * DIM1, -0.5 * DIM2) E = (-0.5 * DIM1, -0.5 * DIM2) F = (-0.5 * DIM1, 0.5 * DIM2) + + geometry = Geometry(outer_box - inner_box, material) geometry.recovery_points = [C, D, E, F] + return geometry @@ -135,9 +142,9 @@ def nastran_box1( The following example creates a BOX1 cross-section with a depth of 3.0 and width of 4.0, and generates a mesh with a maximum triangular area of 0.007:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_box1 - geometry = nsections.nastran_box1( + geometry = nastran_box1( DIM1=4.0, DIM2=3.0, DIM3=0.375, DIM4=0.5, DIM5=0.25, DIM6=0.75 ) mesh = geometry.create_mesh(mesh_sizes=[0.007]) @@ -200,9 +207,9 @@ def nastran_chan( The following example creates a CHAN cross-section with a depth of 4.0 and width of 2.0, and generates a mesh with a maximum triangular area of 0.008:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_chan - geometry = nsections.nastran_chan(DIM1=2.0, DIM2=4.0, DIM3=0.25, DIM4=0.5) + geometry = nastran_chan(DIM1=2.0, DIM2=4.0, DIM3=0.25, DIM4=0.5) mesh = geometry.create_mesh(mesh_sizes=[0.008]) .. figure:: ../images/sections/chan_geometry.png @@ -264,9 +271,9 @@ def nastran_chan1( The following example creates a CHAN1 cross-section with a depth of 4.0 and width of 1.75, and generates a mesh with a maximum triangular area of 0.01:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_chan1 - geometry = nsections.nastran_chan1(DIM1=0.75, DIM2=1.0, DIM3=3.5, DIM4=4.0) + geometry = nastran_chan1(DIM1=0.75, DIM2=1.0, DIM3=3.5, DIM4=4.0) mesh = geometry.create_mesh(mesh_sizes=[0.01]) .. figure:: ../images/sections/chan1_geometry.png @@ -326,9 +333,9 @@ def nastran_chan2( The following example creates a CHAN2 cross-section with a depth of 2.0 and width of 4.0, and generates a mesh with a maximum triangular area of 0.01:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_chan2 - geometry = nsections.nastran_chan2(DIM1=0.375, DIM2=0.5, DIM3=2.0, DIM4=4.0) + geometry = nastran_chan2(DIM1=0.375, DIM2=0.5, DIM3=2.0, DIM4=4.0) mesh = geometry.create_mesh(mesh_sizes=[0.01]) .. figure:: ../images/sections/chan2_geometry.png @@ -389,9 +396,9 @@ def nastran_cross( The following example creates a rectangular cross-section with a depth of 3.0 and width of 1.875, and generates a mesh with a maximum triangular area of 0.008:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_cross - geometry = nsections.nastran_cross(DIM1=1.5, DIM2=0.375, DIM3=3.0, DIM4=0.25) + geometry = nastran_cross(DIM1=1.5, DIM2=0.375, DIM3=3.0, DIM4=0.25) mesh = geometry.create_mesh(mesh_sizes=[0.008]) .. figure:: ../images/sections/cross_geometry.png @@ -460,9 +467,9 @@ def nastran_fcross( The following example demonstrates the creation of a flanged cross section:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_fcross - geometry = nsections.nastran_fcross( + geometry = nastran_fcross( DIM1=9.0, DIM2=6.0, DIM3=0.75, DIM4=0.625, DIM5=2.1, DIM6=0.375, DIM7=4.5, DIM8=0.564 ) mesh = geometry.create_mesh(mesh_sizes=[0.03]) @@ -560,9 +567,9 @@ def nastran_dbox( The following example creates a DBOX cross-section with a depth of 3.0 and width of 8.0, and generates a mesh with a maximum triangular area of 0.01:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_dbox - geometry = nsections.nastran_dbox( + geometry = nastran_dbox( DIM1=8.0, DIM2=3.0, DIM3=3.0, DIM4=0.5, DIM5=0.625, DIM6=0.75, DIM7=0.375, DIM8=0.25, DIM9=0.5, DIM10=0.375 ) @@ -641,9 +648,9 @@ def nastran_gbox( The following example creates a GBOX cross-section with a depth of 2.5 and width of 6.0, and generates a mesh with a maximum triangular area of 0.01:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_gbox - geometry = nsections.nastran_gbox( + geometry = nastran_gbox( DIM1=6.0, DIM2=2.5, DIM3=0.375, DIM4=0.25, DIM5=0.625, DIM6=1.0 ) mesh = geometry.create_mesh(mesh_sizes=[0.01]) @@ -717,9 +724,9 @@ def nastran_h( The following example creates a H cross-section with a depth of 3.5 and width of 2.75, and generates a mesh with a maximum triangular area of 0.005:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_h - geometry = nsections.nastran_h(DIM1=2.0, DIM2=0.75, DIM3=3.5, DIM4=0.25) + geometry = nastran_h(DIM1=2.0, DIM2=0.75, DIM3=3.5, DIM4=0.25) mesh = geometry.create_mesh(mesh_sizes=[0.005]) .. figure:: ../images/sections/h_geometry.png @@ -784,9 +791,9 @@ def nastran_hat( The following example creates a HAT cross-section with a depth of 1.25 and width of 2.5, and generates a mesh with a maximum triangular area of 0.001:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_hat - geometry = nsections.nastran_hat(DIM1=1.25, DIM2=0.25, DIM3=1.5, DIM4=0.5) + geometry = nastran_hat(DIM1=1.25, DIM2=0.25, DIM3=1.5, DIM4=0.5) mesh = geometry.create_mesh(mesh_sizes=[0.001]) .. figure:: ../images/sections/hat_geometry.png @@ -852,9 +859,9 @@ def nastran_hat1( The following example creates a HAT1 cross-section with a depth of 2.0 and width of 4.0, and generates a mesh with a maximum triangular area of 0.005:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_hat1 - geometry = nsections.nastran_hat1(DIM1=4.0, DIM2=2.0, DIM3=1.5, DIM4=0.1875, DIM5=0.375) + geometry = nastran_hat1(DIM1=4.0, DIM2=2.0, DIM3=1.5, DIM4=0.1875, DIM5=0.375) mesh = geometry.create_mesh(mesh_sizes=[0.005]) .. figure:: ../images/sections/hat1_geometry.png @@ -914,9 +921,9 @@ def nastran_hexa( The following example creates a rectangular cross-section with a depth of 1.5 and width of 2.0, and generates a mesh with a maximum triangular area of 0.005:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_hexa - geometry = nsections.nastran_hexa(DIM1=0.5, DIM2=2.0, DIM3=1.5) + geometry = nastran_hexa(DIM1=0.5, DIM2=2.0, DIM3=1.5) mesh = geometry.create_mesh(mesh_sizes=[0.005]) .. figure:: ../images/sections/hexa_geometry.png @@ -978,9 +985,9 @@ def nastran_i( The following example creates a Nastran I cross-section with a depth of 5.0, and generates a mesh with a maximum triangular area of 0.008:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_i - geometry = nsections.nastran_i( + geometry = nastran_i( DIM1=5.0, DIM2=2.0, DIM3=3.0, DIM4=0.25, DIM5=0.375, DIM6=0.5 ) mesh = geometry.create_mesh(mesh_sizes=[0.008]) @@ -1051,9 +1058,9 @@ def nastran_i1( 5.0 and width of 1.75, and generates a mesh with a maximum triangular area of 0.02:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_i1 - geometry = nsections.nastran_i1(DIM1=1.0, DIM2=0.75, DIM3=4.0, DIM4=5.0) + geometry = nastran_i1(DIM1=1.0, DIM2=0.75, DIM3=4.0, DIM4=5.0) mesh = geometry.create_mesh(mesh_sizes=[0.02]) .. figure:: ../images/sections/i1_geometry.png @@ -1118,9 +1125,9 @@ def nastran_l( The following example creates a L cross-section with a depth of 6.0 and width of 3.0, and generates a mesh with a maximum triangular area of 0.01:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_l - geometry = nsections.nastran_l(DIM1=3.0, DIM2=6.0, DIM3=0.375, DIM4=0.625) + geometry = nastran_l(DIM1=3.0, DIM2=6.0, DIM3=0.375, DIM4=0.625) mesh = geometry.create_mesh(mesh_sizes=[0.01]) .. figure:: ../images/sections/l_geometry.png @@ -1149,7 +1156,7 @@ def nastran_l( E = (-0.5 * DIM4, -0.5 * DIM3) F = (-0.5 * DIM4, DIM2 - 0.5 * DIM3) - geometry.recovery_points([C, D, E, F]) + geometry.recovery_points = [C, D, E, F] return geometry @@ -1167,9 +1174,9 @@ def nastran_rod( The following example creates a circular rod with a radius of 3.0 and 50 points discretising the boundary, and generates a mesh with a maximum triangular area of 0.01:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_rod - geometry = nsections.nastran_rod(DIM1=3.0, n=50) + geometry = nastran_rod(DIM1=3.0, n=50) mesh = geometry.create_mesh(mesh_sizes=[0.01]) .. figure:: ../images/sections/rod_geometry.png @@ -1205,7 +1212,7 @@ def nastran_rod( E = (0, -DIM1) F = (-DIM1, 0) - geometry.recovery_points([C, D, E, F]) + geometry.recovery_points = [C, D, E, F] return geometry @@ -1230,9 +1237,9 @@ def nastran_tee( The following example creates a T cross-section with a depth of 4.0 and width of 3.0, and generates a mesh with a maximum triangular area of 0.001:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_tee - geometry = nsections.nastran_t(DIM1=3.0, DIM2=4.0, DIM3=0.375, DIM4=0.25) + geometry = nastran_tee(DIM1=3.0, DIM2=4.0, DIM3=0.375, DIM4=0.25) mesh = geometry.create_mesh(mesh_sizes=[0.001]) .. figure:: ../images/sections/t_geometry.png @@ -1309,9 +1316,9 @@ def nastran_tee1( The following example creates a T1 cross-section with a depth of 3.0 and width of 3.875, and generates a mesh with a maximum triangular area of 0.001:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_tee1 - geometry = nsections.nastran_t1(DIM1=3.0, DIM2=3.5, DIM3=0.375, DIM4=0.25) + geometry = nastran_tee1(DIM1=3.0, DIM2=3.5, DIM3=0.375, DIM4=0.25) mesh = geometry.create_mesh(mesh_sizes=[0.001]) .. figure:: ../images/sections/t1_geometry.png @@ -1373,9 +1380,9 @@ def nastran_tee2( The following example creates a T2 cross-section with a depth of 4.0 and width of 3.0, and generates a mesh with a maximum triangular area of 0.005:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_tee2 - geometry = nsections.nastran_t2(DIM1=3.0, DIM2=4.0, DIM3=0.375, DIM4=0.5) + geometry = nastran_tee2(DIM1=3.0, DIM2=4.0, DIM3=0.375, DIM4=0.5) mesh = geometry.create_mesh(mesh_sizes=[0.005]) .. figure:: ../images/sections/t2_geometry.png @@ -1433,9 +1440,9 @@ def nastran_tube( inner radius of 2.5, and generates a mesh with 37 points discretising the boundaries and a maximum triangular area of 0.01:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_tube - geometry = nsections.nastran_tube(DIM1=3.0, DIM2=2.5, n=37) + geometry = nastran_tube(DIM1=3.0, DIM2=2.5, n=37) mesh = geometry.create_mesh(mesh_sizes=[0.01]) .. figure:: ../images/sections/tube_geometry.png @@ -1501,9 +1508,9 @@ def nastran_tube2( wall thickness of 0.5, and generates a mesh with 37 point discretising the boundary and a maximum triangular area of 0.01:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_tube2 - geometry = nsections.nastran_tube2(DIM1=3.0, DIM2=0.5, n=37) + geometry = nastran_tube2(DIM1=3.0, DIM2=0.5, n=37) mesh = geometry.create_mesh(mesh_sizes=[0.01]) .. figure:: ../images/sections/tube2_geometry.png @@ -1542,16 +1549,16 @@ def nastran_tube2( points_outer.append([x_outer, y_outer]) points_inner.append([x_inner, y_inner]) - exterior = Geometry(Polygon(points_outer), material) - interior = Geometry(Polygon(points_inner), material) - geometry = exterior - interior + exterior = Geometry(Polygon(points_outer), material) + interior = Geometry(Polygon(points_inner), material) + geometry = exterior - interior - C = (0, DIM1) - D = (DIM1, 0) - E = (0, -DIM1) - F = (-DIM1, 0) - geometry.recovery_points = [C, D, E, F] - return geometry + C = (0, DIM1) + D = (DIM1, 0) + E = (0, -DIM1) + F = (-DIM1, 0) + geometry.recovery_points = [C, D, E, F] + return geometry def nastran_zed( @@ -1574,9 +1581,9 @@ def nastran_zed( The following example creates a rectangular cross-section with a depth of 4.0 and width of 2.75, and generates a mesh with a maximum triangular area of 0.005:: - import sectionproperties.pre.nastran_sections as nsections + from sectionproperties.pre.library.nastran_sections import nastran_zed - geometry = nsections.nastran_z(DIM1=1.125, DIM2=0.5, DIM3=3.5, DIM4=4.0) + geometry = nastran_zed(DIM1=1.125, DIM2=0.5, DIM3=3.5, DIM4=4.0) mesh = geometry.create_mesh(mesh_sizes=[0.005]) .. figure:: ../images/sections/z_geometry.png diff --git a/sectionproperties/pre/library/standard_sections.py b/sectionproperties/pre/library/standard_sections.py new file mode 100644 index 00000000..7058d02b --- /dev/null +++ b/sectionproperties/pre/library/standard_sections.py @@ -0,0 +1,207 @@ +import numpy as np +from shapely.geometry import Polygon +from sectionproperties.pre.geometry import Geometry +import sectionproperties.pre.pre as pre +from sectionproperties.pre.library.utils import draw_radius + + +def rectangular_section( + b, d, material: pre.Material = pre.DEFAULT_MATERIAL +) -> Geometry: + """Constructs a rectangular section with the bottom left corner at the origin *(0, 0)*, with + depth *d* and width *b*. + + :param float d: Depth (y) of the rectangle + :param float b: Width (x) of the rectangle + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates a rectangular cross-section with a depth of 100 and width of 50, + and generates a mesh with a maximum triangular area of 5:: + + from sectionproperties.pre.library.standard_sections import rectangular_section + + geometry = rectangular_section(d=100, b=50) + geometry.create_mesh(mesh_sizes=[5]) + + .. figure:: ../images/sections/rectangle_geometry.png + :align: center + :scale: 75 % + + Rectangular section geometry. + + .. figure:: ../images/sections/rectangle_mesh.png + :align: center + :scale: 75 % + + Mesh generated from the above geometry. + """ + points = [[0, 0], [b, 0], [b, d], [0, d]] + rectangle = Polygon(points) + return Geometry(rectangle, material) + + +def circular_section( + d: float, n: int, material: pre.Material = pre.DEFAULT_MATERIAL +) -> Geometry: + """Constructs a solid circle centered at the origin *(0, 0)* with diameter *d* and using *n* + points to construct the circle. + + :param float d: Diameter of the circle + :param int n: Number of points discretising the circle + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates a circular geometry with a diameter of 50 with 64 points, + and generates a mesh with a maximum triangular area of 2.5:: + + from sectionproperties.pre.library.standard_sections import circular_section + + geometry = circular_section(d=50, n=64) + geometry.create_mesh(mesh_sizes=[2.5]) + + .. figure:: ../images/sections/circle_geometry.png + :align: center + :scale: 75 % + + Circular section geometry. + + .. figure:: ../images/sections/circle_mesh.png + :align: center + :scale: 75 % + + Mesh generated from the above geometry. + """ + x_off, y_off = (0, 0) + points = [] + # loop through each point on the circle + for i in range(n): + # determine polar angle + theta = i * 2 * np.pi * 1.0 / n + + # calculate location of the point + x = 0.5 * d * np.cos(theta) + x_off + y = 0.5 * d * np.sin(theta) + y_off + + # append the current point to the points list + points.append([x, y]) + + circle = Polygon(points) + return Geometry(circle, material) + + +def elliptical_section( + d_y: float, d_x: float, n: int, material: pre.Material = pre.DEFAULT_MATERIAL +) -> Geometry: + """Constructs a solid ellipse centered at the origin *(0, 0)* with vertical diameter *d_y* and + horizontal diameter *d_x*, using *n* points to construct the ellipse. + + :param float d_y: Diameter of the ellipse in the y-dimension + :param float d_x: Diameter of the ellipse in the x-dimension + :param int n: Number of points discretising the ellipse + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates an elliptical cross-section with a vertical diameter of 25 and + horizontal diameter of 50, with 40 points, and generates a mesh with a maximum triangular area + of 1.0:: + + from sectionproperties.pre.library.standard_sections import elliptical_section + + geometry = elliptical_section(d_y=25, d_x=50, n=40) + geometry.create_mesh(mesh_sizes=[1.0]) + + .. figure:: ../images/sections/ellipse_geometry.png + :align: center + :scale: 75 % + + Elliptical section geometry. + + .. figure:: ../images/sections/ellipse_mesh.png + :align: center + :scale: 75 % + + Mesh generated from the above geometry. + """ + points = [] + + # loop through each point on the ellipse + for i in range(n): + # determine polar angle + theta = i * 2 * np.pi * 1.0 / n + + # calculate location of the point + x = 0.5 * d_x * np.cos(theta) + y = 0.5 * d_y * np.sin(theta) + + # append the current point to the points list + points.append([x, y]) + + ellipse = Polygon(points) + return Geometry(ellipse, material) + + +def cruciform_section( + d, b, t, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL +) -> Geometry: + """Constructs a cruciform section centered at the origin *(0, 0)*, with depth *d*, width *b*, + thickness *t* and root radius *r*, using *n_r* points to construct the root radius. + + :param float d: Depth of the cruciform section + :param float b: Width of the cruciform section + :param float t: Thickness of the cruciform section + :param float r: Root radius of the cruciform section + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates a cruciform section with a depth of 250, a width of 175, a + thickness of 12 and a root radius of 16, using 16 points to discretise the radius. A mesh is + generated with a maximum triangular area of 5.0:: + + from sectionproperties.pre.library.standard_sections import cruciform_section + + geometry = cruciform_section(d=250, b=175, t=12, r=16, n_r=16) + geometry.create_mesh(mesh_sizes=[5.0]) + + .. figure:: ../images/sections/cruciform_geometry.png + :align: center + :scale: 75 % + + Cruciform section geometry. + + .. figure:: ../images/sections/cruciform_mesh.png + :align: center + :scale: 75 % + """ + points = [] + + # add first two points + points.append([-t * 0.5, -d * 0.5]) + points.append([t * 0.5, -d * 0.5]) + + # construct the bottom right radius + pt = [0.5 * t + r, -0.5 * t - r] + points += draw_radius(pt, r, np.pi, n_r, False) + + # add the next two points + points.append([0.5 * b, -t * 0.5]) + points.append([0.5 * b, t * 0.5]) + + # construct the top right radius + pt = [0.5 * t + r, 0.5 * t + r] + points += draw_radius(pt, r, 1.5 * np.pi, n_r, False) + + # add the next two points + points.append([t * 0.5, 0.5 * d]) + points.append([-t * 0.5, 0.5 * d]) + + # construct the top left radius + pt = [-0.5 * t - r, 0.5 * t + r] + points += draw_radius(pt, r, 0, n_r, False) + + # add the next two points + points.append([-0.5 * b, t * 0.5]) + points.append([-0.5 * b, -t * 0.5]) + + # construct the bottom left radius + pt = [-0.5 * t - r, -0.5 * t - r] + points += draw_radius(pt, r, 0.5 * np.pi, n_r, False) + + polygon = Polygon(points) + return Geometry(polygon, material) diff --git a/sectionproperties/pre/library/steel_sections.py b/sectionproperties/pre/library/steel_sections.py new file mode 100644 index 00000000..3c4cd660 --- /dev/null +++ b/sectionproperties/pre/library/steel_sections.py @@ -0,0 +1,1203 @@ +import numpy as np +from shapely.geometry import Polygon +from sectionproperties.pre.geometry import Geometry +import sectionproperties.pre.pre as pre +from sectionproperties.pre.library.utils import draw_radius, rotate + + +def circular_hollow_section( + d: float, t: float, n: int, material: pre.Material = pre.DEFAULT_MATERIAL +) -> Geometry: + """Constructs a circular hollow section (CHS) centered at the origin *(0, 0)*, with diameter *d* and + thickness *t*, using *n* points to construct the inner and outer circles. + + :param float d: Outer diameter of the CHS + :param float t: Thickness of the CHS + :param int n: Number of points discretising the inner and outer circles + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates a CHS discretised with 64 points, with a diameter of 48 and + thickness of 3.2, and generates a mesh with a maximum triangular area of 1.0:: + + from sectionproperties.pre.library.steel_sections import circular_hollow_section + + geometry = circular_hollow_section(d=48, t=3.2, n=64) + geometry.create_mesh(mesh_sizes=[1.0]) + + .. figure:: ../images/sections/chs_geometry.png + :align: center + :scale: 75 % + + CHS geometry. + + .. figure:: ../images/sections/chs_mesh.png + :align: center + :scale: 75 % + + Mesh generated from the above geometry. + """ + points_inner = [] + points_outer = [] + # loop through each point of the CHS + for i in range(n): + # determine polar angle + theta = i * 2 * np.pi * 1.0 / n + + # calculate location of outer and inner points + x_outer = 0.5 * d * np.cos(theta) + y_outer = 0.5 * d * np.sin(theta) + x_inner = (0.5 * d - t) * np.cos(theta) + y_inner = (0.5 * d - t) * np.sin(theta) + + # append the current points to the points list + points_outer.append([x_outer, y_outer]) + points_inner.append([x_inner, y_inner]) + + inner_circle = Polygon(points_inner) + outer_circle = Polygon(points_outer) + return Geometry(outer_circle - inner_circle, material) + + +def elliptical_hollow_section( + d_y: float, + d_x: float, + t: float, + n: int, + material: pre.Material = pre.DEFAULT_MATERIAL, +) -> Geometry: + """Constructs an elliptical hollow section (EHS) centered at the origin *(0, 0)*, with outer vertical + diameter *d_y*, outer horizontal diameter *d_x*, and thickness *t*, using *n* points to + construct the inner and outer ellipses. + + :param float d_y: Diameter of the ellipse in the y-dimension + :param float d_x: Diameter of the ellipse in the x-dimension + :param float t: Thickness of the EHS + :param int n: Number of points discretising the inner and outer ellipses + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates a EHS discretised with 30 points, with a outer vertical diameter + of 25, outer horizontal diameter of 50, and thickness of 2.0, and generates a mesh with a + maximum triangular area of 0.5:: + + from sectionproperties.pre.library.steel_sections import elliptical_hollow_section + + geometry = elliptical_hollow_section(d_y=25, d_x=50, t=2.0, n=64) + geometry.create_mesh(mesh_sizes=[0.5]) + + .. figure:: ../images/sections/ehs_geometry.png + :align: center + :scale: 75 % + + EHS geometry. + + .. figure:: ../images/sections/ehs_mesh.png + :align: center + :scale: 75 % + + Mesh generated from the above geometry. + """ + points_inner = [] + points_outer = [] + # loop through each point of the EHS + for i in range(n): + # determine polar angle + theta = i * 2 * np.pi * 1.0 / n + + # calculate location of outer and inner points + x_outer = 0.5 * d_x * np.cos(theta) + y_outer = 0.5 * d_y * np.sin(theta) + x_inner = ((0.5 * d_x) - t) * np.cos(theta) + y_inner = ((0.5 * d_y) - t) * np.sin(theta) + + # append the current points to the points list + points_outer.append([x_outer, y_outer]) + points_inner.append([x_inner, y_inner]) + + outer = Polygon(points_outer) + inner = Polygon(points_inner) + return Geometry(outer - inner, material) + + +def rectangular_hollow_section( + b: float, + d: float, + t: float, + r_out: float, + n_r: int, + material: pre.Material = pre.DEFAULT_MATERIAL, +) -> Geometry: + """Constructs a rectangular hollow section (RHS) centered at *(b/2, d/2)*, with depth *d*, width *b*, + thickness *t* and outer radius *r_out*, using *n_r* points to construct the inner and outer + radii. If the outer radius is less than the thickness of the RHS, the inner radius is set to + zero. + + :param float d: Depth of the RHS + :param float b: Width of the RHS + :param float t: Thickness of the RHS + :param float r_out: Outer radius of the RHS + :param int n_r: Number of points discretising the inner and outer radii + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates an RHS with a depth of 100, a width of 50, a thickness of 6 and + an outer radius of 9, using 8 points to discretise the inner and outer radii. A mesh is + generated with a maximum triangular area of 2.0:: + + from sectionproperties.pre.library.steel_sections import rectangular_hollow_section + + geometry = rectangular_hollow_section(d=100, b=50, t=6, r_out=9, n_r=8) + geometry.create_mesh(mesh_sizes=[2.0]) + + .. figure:: ../images/sections/rhs_geometry.png + :align: center + :scale: 75 % + + RHS geometry. + + .. figure:: ../images/sections/rhs_mesh.png + :align: center + :scale: 75 % + + Mesh generated from the above geometry. + """ + points_inner = [] + points_outer = [] + # calculate internal radius + r_in = max(r_out - t, 0) + # construct the outer radius points + points_outer += draw_radius([r_out, r_out], r_out, np.pi, n_r) + points_outer += draw_radius([b - r_out, r_out], r_out, 1.5 * np.pi, n_r) + points_outer += draw_radius([b - r_out, d - r_out], r_out, 0, n_r) + points_outer += draw_radius([r_out, d - r_out], r_out, 0.5 * np.pi, n_r) + + points_inner += draw_radius([t + r_in, t + r_in], r_in, np.pi, n_r) + points_inner += draw_radius([b - t - r_in, t + r_in], r_in, 1.5 * np.pi, n_r) + points_inner += draw_radius([b - t - r_in, d - t - r_in], r_in, 0, n_r) + points_inner += draw_radius([t + r_in, d - t - r_in], r_in, 0.5 * np.pi, n_r) + + outer = Polygon(points_outer) + inner = Polygon(points_inner) + return Geometry(outer - inner, material) + + +def polygon_hollow_section( + d, t, n_sides, r_in=0, n_r=1, rot=0, material: pre.Material = pre.DEFAULT_MATERIAL +) -> Geometry: + """Constructs a regular hollow polygon section centered at *(0, 0)*, with a pitch circle + diameter of bounding polygon *d*, thickness *t*, number of sides *n_sides* and an optional + inner radius *r_in*, using *n_r* points to construct the inner and outer radii (if radii is + specified). + + :param float d: Pitch circle diameter of the outer bounding polygon (i.e. diameter of circle + that passes through all vertices of the outer polygon) + :param float t: Thickness of the polygon section wall + :param float r_in: Inner radius of the polygon corners. By default, if not specified, a polygon + with no corner radii is generated. + :param int n_r: Number of points discretising the inner and outer radii, ignored if no inner + radii is specified + :param rot: Initial counterclockwise rotation in degrees. By default bottom face is aligned + with x axis. + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + :raises Exception: Number of sides in polygon must be greater than or equal to 3 + + The following example creates an Octagonal section (8 sides) with a diameter of 200, a + thickness of 6 and an inner radius of 20, using 12 points to discretise the inner and outer + radii. A mesh is generated with a maximum triangular area of 5:: + + from sectionproperties.pre.library.steel_sections import polygon_hollow_section + + geometry = polygon_hollow_section(d=200, t=6, n_sides=8, r_in=20, n_r=12) + geometry.create_mesh(mesh_sizes=[5]) + + .. figure:: ../images/sections/polygon_geometry.png + :align: center + :scale: 75 % + + Octagonal section geometry. + + .. figure:: ../images/sections/polygon_mesh.png + :align: center + :scale: 75 % + + Mesh generated from the above geometry. + """ + outer_points = [] + inner_points = [] + + if n_sides < 3: + msg = "n_sides required to be greater than 3 for polygon_section()" + raise Exception(msg) + + # initial rotation + rot = rot * np.pi / 180 # radians + + # determine triangular segment angle + alpha = 2 * np.pi / n_sides # radians + + # determine distance from origin to point perpendicular on face of side + a_out = d / 2 * np.cos(alpha / 2) + a_in = a_out - t + + # determine side length for outer & inner faces neglecting radii + side_length_out = d * np.sin(alpha / 2) + side_length_in = a_in / a_out * side_length_out + + # check limit on internal radii, if exceeded then radii merge to circle + if r_in > a_in: + r_in = a_in + circle = True + else: + circle = False + + # calculate external radius, if r_in is zero, r_out also is zero + if r_in == 0: + r_out = 0 + n_r = 1 + else: + r_out = r_in + t + + # equivalent side length of half the corner radii triangular segment + c_out = r_out * (side_length_out / 2) / a_out + c_in = r_in * (side_length_in / 2) / a_in + + # determine straight side length between corner radii (if present) + side_length_straight_out = side_length_out - (2 * c_out) + side_length_straight_in = side_length_in - (2 * c_in) + + # temp list for repeating geometry + outer_base_points = [] + inner_base_points = [] + + # start at bottom face, constructing one corner radii, then rotate by initial rotation + + # alpha and repeat for n_side number of times to form full section perimeter + + # construct the first radius (bottom right) + for i in range(n_r): + # determine polar angle + theta = 1 / 2 * np.pi + i * 1.0 / max(1, n_r - 1) * alpha + + # calculate location of inner and outer points + x_outer = side_length_straight_out / 2 - r_out * np.cos(theta) + y_outer = -a_out + r_out - r_out * np.sin(theta) + x_inner = side_length_straight_in / 2 - r_in * np.cos(theta) + y_inner = -a_in + r_in - r_in * np.sin(theta) + + # append the current temporary points to the temporary points list + outer_base_points.append([x_outer, y_outer]) + inner_base_points.append([x_inner, y_inner]) + + for i in range(n_sides): + for point in outer_base_points: + point_new = rotate(point, alpha * i + rot) + outer_points.append(point_new) + + for point in inner_base_points: + point_new = rotate(point, alpha * i + rot) + inner_points.append(point_new) + + outer_polygon = Polygon(outer_points) + inner_polygon = Polygon(inner_points) + return Geometry(outer_polygon - inner_polygon, material) + + +def i_section( + d: float, + b: float, + t_f: float, + t_w: float, + r: float, + n_r: int, + material: pre.Material = pre.DEFAULT_MATERIAL, +) -> Geometry: # More specific description and less ambiguous? e.g. not an "S" section. + """Constructs an I-section centered at *(b/2, d/2)*, with depth *d*, width *b*, flange + thickness *t_f*, web thickness *t_w*, and root radius *r*, using *n_r* points to construct the + root radius. + + :param float d: Depth of the I-section + :param float b: Width of the I-section + :param float t_f: Flange thickness of the I-section + :param float t_w: Web thickness of the I-section + :param float r: Root radius of the I-section + :param int n_r: Number of points discretising the root radius + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates an I-section with a depth of 203, a width of 133, a flange + thickness of 7.8, a web thickness of 5.8 and a root radius of 8.9, using 16 points to + discretise the root radius. A mesh is generated with a maximum triangular area of 3.0:: + + from sectionproperties.pre.library.steel_sections import i_section + + geometry = i_section(d=203, b=133, t_f=7.8, t_w=5.8, r=8.9, n_r=16) + geometry.create_mesh(mesh_sizes=[3.0]) + + .. figure:: ../images/sections/isection_geometry.png + :align: center + :scale: 75 % + + I-section geometry. + + .. figure:: ../images/sections/isection_mesh.png + :align: center + :scale: 75 % + + Mesh generated from the above geometry. + """ + points = [] + + # add first three points + points.append([0, 0]) + points.append([b, 0]) + points.append([b, t_f]) + + # construct the bottom right radius + pt = [b * 0.5 + t_w * 0.5 + r, t_f + r] + points += draw_radius(pt, r, 1.5 * np.pi, n_r, False) + + # construct the top right radius + pt = [b * 0.5 + t_w * 0.5 + r, d - t_f - r] + points += draw_radius(pt, r, np.pi, n_r, False) + + # add the next four points + points.append([b, d - t_f]) + points.append([b, d]) + points.append([0, d]) + points.append([0, d - t_f]) + + # construct the top left radius + pt = [b * 0.5 - t_w * 0.5 - r, d - t_f - r] + points += draw_radius(pt, r, 0.5 * np.pi, n_r, False) + + # construct the bottom left radius + pt = [b * 0.5 - t_w * 0.5 - r, t_f + r] + points += draw_radius(pt, r, 0, n_r, False) + + # # add the last point + points.append([0, t_f]) + i_section = Polygon(points) + return Geometry(i_section, material) + + +def mono_i_section( + d, b_t, b_b, t_fb, t_ft, t_w, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL +) -> Geometry: + """Constructs a monosymmetric I-section centered at *(max(b_t, b_b)/2, d/2)*, with depth *d*, + top flange width *b_t*, bottom flange width *b_b*, top flange thickness *t_ft*, top flange + thickness *t_fb*, web thickness *t_w*, and root radius *r*, using *n_r* points to construct the + root radius. + + :param float d: Depth of the I-section + :param float b_t: Top flange width + :param float b_b: Bottom flange width + :param float t_ft: Top flange thickness of the I-section + :param float t_fb: Bottom flange thickness of the I-section + :param float t_w: Web thickness of the I-section + :param float r: Root radius of the I-section + :param int n_r: Number of points discretising the root radius + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates a monosymmetric I-section with a depth of 200, a top flange width + of 50, a top flange thickness of 12, a bottom flange width of 130, a bottom flange thickness of + 8, a web thickness of 6 and a root radius of 8, using 16 points to discretise the root radius. + A mesh is generated with a maximum triangular area of 3.0:: + + from sectionproperties.pre.library.steel_sections import mono_i_section + + geometry = mono_i_section( + d=200, b_t=50, b_b=130, t_ft=12, t_fb=8, t_w=6, r=8, n_r=16 + ) + geometry.create_mesh(mesh_sizes=[3.0]) + + .. figure:: ../images/sections/monoisection_geometry.png + :align: center + :scale: 75 % + + I-section geometry. + + .. figure:: ../images/sections/monoisection_mesh.png + :align: center + :scale: 75 % + + Mesh generated from the above geometry. + """ + points = [] + # calculate central axis + x_central = max(b_t, b_b) * 0.5 + + # add first three points + points.append([x_central - b_b * 0.5, 0]) + points.append([x_central + b_b * 0.5, 0]) + points.append([x_central + b_b * 0.5, t_fb]) + + # construct the bottom right radius + pt = [x_central + t_w * 0.5 + r, t_fb + r] + points += draw_radius(pt, r, 1.5 * np.pi, n_r, False) + + # construct the top right radius + pt = [x_central + t_w * 0.5 + r, d - t_ft - r] + points += draw_radius(pt, r, np.pi, n_r, False) + + # add the next four points + points.append([x_central + b_t * 0.5, d - t_ft]) + points.append([x_central + b_t * 0.5, d]) + points.append([x_central - b_t * 0.5, d]) + points.append([x_central - b_t * 0.5, d - t_ft]) + + # construct the top left radius + pt = [x_central - t_w * 0.5 - r, d - t_ft - r] + points += draw_radius(pt, r, 0.5 * np.pi, n_r, False) + + # construct the bottom left radius + pt = [x_central - t_w * 0.5 - r, t_fb + r] + points += draw_radius(pt, r, 0, n_r, False) + + # add the last point + points.append([x_central - b_b * 0.5, t_fb]) + + polygon = Polygon(points) + return Geometry(polygon, material) + + +def tapered_flange_i_section( + d, b, t_f, t_w, r_r, r_f, alpha, n_r, material: pre.Material = pre.DEFAULT_MATERIAL +) -> Geometry: + """Constructs a Tapered Flange I-section centered at *(b/2, d/2)*, with depth *d*, width *b*, + mid-flange thickness *t_f*, web thickness *t_w*, root radius *r_r*, flange radius *r_f* and + flange angle *alpha*, using *n_r* points to construct the radii. + + :param float d: Depth of the Tapered Flange I-section + :param float b: Width of the Tapered Flange I-section + :param float t_f: Mid-flange thickness of the Tapered Flange I-section (measured at the point + equidistant from the face of the web to the edge of the flange) + :param float t_w: Web thickness of the Tapered Flange I-section + :param float r_r: Root radius of the Tapered Flange I-section + :param float r_f: Flange radius of the Tapered Flange I-section + :param float alpha: Flange angle of the Tapered Flange I-section (degrees) + :param int n_r: Number of points discretising the radii + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates a Tapered Flange I-section with a depth of 588, a width of 191, a + mid-flange thickness of 27.2, a web thickness of 15.2, a root radius of 17.8, a flange radius + of 8.9 and a flange angle of 8°, using 16 points to discretise the radii. A mesh is generated + with a maximum triangular area of 20.0:: + + from sectionproperties.pre.library.steel_sections import tapered_flange_i_section + + geometry = tapered_flange_i_section( + d=588, b=191, t_f=27.2, t_w=15.2, r_r=17.8, r_f=8.9, alpha=8, n_r=16 + ) + geometry.create_mesh(mesh_sizes=[20.0]) + + .. figure:: ../images/sections/taperedisection_geometry.png + :align: center + :scale: 75 % + + I-section geometry. + + .. figure:: ../images/sections/taperedisection_mesh.png + :align: center + :scale: 75 % + + Mesh generated from the above geometry. + """ + points = [] + + # calculate alpha in radians + alpha_rad = np.pi * alpha / 180 + + # calculate the height of the flange toe and dimensions of the straight + x1 = b * 0.25 - t_w * 0.25 - r_f * (1 - np.sin(alpha_rad)) + y1 = x1 * np.tan(alpha_rad) + x2 = b * 0.25 - t_w * 0.25 - r_r * (1 - np.sin(alpha_rad)) + y2 = x2 * np.tan(alpha_rad) + y_t = t_f - y1 - r_f * np.cos(alpha_rad) + + # add first two points + points.append([0, 0]) + points.append([b, 0]) + + # construct the bottom right flange toe radius + if r_f == 0: + points.append([b, y_t]) + else: + for i in range(n_r): + # determine polar angle + theta = i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) + + # calculate the locations of the radius points + x = b - r_f + r_f * np.cos(theta) + y = y_t + r_f * np.sin(theta) + + # append the current points to the points list + points.append([x, y]) + + # construct the bottom right root radius + if r_r == 0: + points.append([b * 0.5 + t_w * 0.5, t_f + y2]) + else: + for i in range(n_r): + # determine polar angle + theta = (3.0 / 2 * np.pi - alpha_rad) - ( + i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) + ) + + # calculate the locations of the radius points + x = b * 0.5 + t_w * 0.5 + r_r + r_r * np.cos(theta) + y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta) + + # append the current points to the points list + points.append([x, y]) + + # construct the top right root radius + if r_r == 0: + points.append([b * 0.5 + t_w * 0.5, d - t_f - y2]) + else: + for i in range(n_r): + # determine polar angle + theta = np.pi - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) + + # calculate the locations of the radius points + x = b * 0.5 + t_w * 0.5 + r_r + r_r * np.cos(theta) + y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta) + + # append the current points to the points list + points.append([x, y]) + + # construct the top right flange toe radius + if r_f == 0: + points.append([b, d - y_t]) + else: + for i in range(n_r): + # determine polar angle + theta = (3.0 * np.pi / 2 + alpha_rad) + i * 1.0 / max(1, n_r - 1) * ( + np.pi * 0.5 - alpha_rad + ) + + # calculate the locations of the radius points + x = b - r_f + r_f * np.cos(theta) + y = d - y_t + r_f * np.sin(theta) + + # append the current points to the points list + points.append([x, y]) + + # add the next two points + points.append([b, d]) + points.append([0, d]) + + # construct the top left flange toe radius + if r_f == 0: + points.append([0, d - y_t]) + else: + for i in range(n_r): + # determine polar angle + theta = np.pi + (i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad)) + + # calculate the locations of the radius points + x = r_f + r_f * np.cos(theta) + y = d - y_t + r_f * np.sin(theta) + + # append the current points to the points list + points.append([x, y]) + + # construct the top left root radius + if r_r == 0: + points.append([b * 0.5 - t_w * 0.5, d - t_f - y2]) + else: + for i in range(n_r): + # determine polar angle + theta = (np.pi * 0.5 - alpha_rad) - ( + i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) + ) + + # calculate the locations of the radius points + x = b * 0.5 - t_w * 0.5 - r_r + r_r * np.cos(theta) + y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta) + + # append the current points to the points list + points.append([x, y]) + + # construct the bottom left root radius + if r_r == 0: + points.append([b * 0.5 - t_w * 0.5, t_f + y2]) + else: + for i in range(n_r): + # determine polar angle + theta = -i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) + + # calculate the locations of the radius points + x = b * 0.5 - t_w * 0.5 - r_r + r_r * np.cos(theta) + y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta) + + # append the current points to the points list + points.append([x, y]) + + # construct the bottom left flange toe radius + if r_f == 0: + points.append([0, y_t]) + else: + for i in range(n_r): + # determine polar angle + theta = (np.pi * 0.5 + alpha_rad) + ( + i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) + ) + + # calculate the locations of the radius points + x = r_f + r_f * np.cos(theta) + y = y_t + r_f * np.sin(theta) + + # append the current points to the points list + points.append([x, y]) + + polygon = Polygon(points) + return Geometry(polygon, material) + + +def channel_section( + d, b, t_f, t_w, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL +) -> Geometry: + """Constructs a parallel-flange channel (PFC) section with the bottom left corner at the origin *(0, 0)*, with depth *d*, + width *b*, flange thickness *t_f*, web thickness *t_w* and root radius *r*, using *n_r* points + to construct the root radius. + + :param float d: Depth of the PFC section + :param float b: Width of the PFC section + :param float t_f: Flange thickness of the PFC section + :param float t_w: Web thickness of the PFC section + :param float r: Root radius of the PFC section + :param int n_r: Number of points discretising the root radius + :param shift: Vector that shifts the cross-section by *(x, y)* + :type shift: list[float, float] + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates a PFC section with a depth of 250, a width of 90, a flange + thickness of 15, a web thickness of 8 and a root radius of 12, using 8 points to discretise the + root radius. A mesh is generated with a maximum triangular area of 5.0:: + + from sectionproperties.pre.library.steel_sections import channel_section + + geometry = channel_section(d=250, b=90, t_f=15, t_w=8, r=12, n_r=8) + geometry.create_mesh(mesh_sizes=[5.0]) + + .. figure:: ../images/sections/pfc_geometry.png + :align: center + :scale: 75 % + + PFC geometry. + + .. figure:: ../images/sections/pfc_mesh.png + :align: center + :scale: 75 % + + Mesh generated from the above geometry. + """ + points = [] + + # add first three points + points.append([0, 0]) + points.append([b, 0]) + points.append([b, t_f]) + + # construct the bottom right radius + pt = [t_w + r, t_f + r] + points += draw_radius(pt, r, 1.5 * np.pi, n_r, False) + + # construct the top right radius + pt = [t_w + r, d - t_f - r] + points += draw_radius(pt, r, np.pi, n_r, False) + + # add last three points + points.append([b, d - t_f]) + points.append([b, d]) + points.append([0, d]) + + polygon = Polygon(points) + return Geometry(polygon, material) + + +def tapered_flange_channel( + d, b, t_f, t_w, r_r, r_f, alpha, n_r, material: pre.Material = pre.DEFAULT_MATERIAL +) -> Geometry: + """Constructs a Tapered Flange Channel section with the bottom left corner at the origin + *(0, 0)*, with depth *d*, width *b*, mid-flange thickness *t_f*, web thickness *t_w*, root + radius *r_r*, flange radius *r_f* and flange angle *alpha*, using *n_r* points to construct the + radii. + + :param float d: Depth of the Tapered Flange Channel section + :param float b: Width of the Tapered Flange Channel section + :param float t_f: Mid-flange thickness of the Tapered Flange Channel section (measured at the + point equidistant from the face of the web to the edge of the flange) + :param float t_w: Web thickness of the Tapered Flange Channel section + :param float r_r: Root radius of the Tapered Flange Channel section + :param float r_f: Flange radius of the Tapered Flange Channel section + :param float alpha: Flange angle of the Tapered Flange Channel section (degrees) + :param int n_r: Number of points discretising the radii + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates a Tapered Flange Channel section with a depth of 10, a width of + 3.5, a mid-flange thickness of 0.575, a web thickness of 0.475, a root radius of 0.575, a + flange radius of 0.4 and a flange angle of 8°, using 16 points to discretise the radii. A mesh + is generated with a maximum triangular area of 0.02:: + + from sectionproperties.pre.library.steel_sections import tapered_flange_channel + + geometry = tapered_flange_channel( + d=10, b=3.5, t_f=0.575, t_w=0.475, r_r=0.575, r_f=0.4, alpha=8, n_r=16 + ) + geometry.create_mesh(mesh_sizes=[0.02]) + + .. figure:: ../images/sections/taperedchannel_geometry.png + :align: center + :scale: 75 % + + Tapered flange channel geometry. + + .. figure:: ../images/sections/taperedchannel_mesh.png + :align: center + :scale: 75 % + + Mesh generated from the above geometry. + """ + points = [] + + # calculate alpha in radians + alpha_rad = np.pi * alpha / 180 + + # calculate the height of the flange toe and dimensions of the straight + x1 = b * 0.5 - t_w * 0.5 - r_f * (1 - np.sin(alpha_rad)) + y1 = x1 * np.tan(alpha_rad) + x2 = b * 0.5 - t_w * 0.5 - r_r * (1 - np.sin(alpha_rad)) + y2 = x2 * np.tan(alpha_rad) + y_t = t_f - y1 - r_f * np.cos(alpha_rad) + + # add first two points + points.append([0, 0]) + points.append([b, 0]) + + # construct the bottom right flange toe radius + if r_f == 0: + points.append([b, y_t]) + else: + for i in range(n_r): + # determine polar angle + theta = i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) + + # calculate the locations of the radius points + x = b - r_f + r_f * np.cos(theta) + y = y_t + r_f * np.sin(theta) + + # append the current points to the points list + points.append([x, y]) + + # construct the bottom right root radius + if r_r == 0: + points.append([t_w, t_f + y2]) + else: + for i in range(n_r): + # determine polar angle + theta = (3.0 / 2 * np.pi - alpha_rad) - ( + i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) + ) + + # calculate the locations of the radius points + x = t_w + r_r + r_r * np.cos(theta) + y = t_f + y2 + r_r * np.cos(alpha_rad) + r_r * np.sin(theta) + + # append the current points to the points list + points.append([x, y]) + + # construct the top right root radius + if r_r == 0: + points.append([t_w, d - t_f - y2]) + else: + for i in range(n_r): + # determine polar angle + theta = np.pi - i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) + + # calculate the locations of the radius points + x = t_w + r_r + r_r * np.cos(theta) + y = d - t_f - y2 - r_r * np.cos(alpha_rad) + r_r * np.sin(theta) + + # append the current points to the points list + points.append([x, y]) + + # construct the top right flange toe radius + if r_f == 0: + points.append([b, d - y_t]) + else: + for i in range(n_r): + # determine polar angle + theta = (3.0 * np.pi / 2 + alpha_rad) + ( + i * 1.0 / max(1, n_r - 1) * (np.pi * 0.5 - alpha_rad) + ) + + # calculate the locations of the radius points + x = b - r_f + r_f * np.cos(theta) + y = d - y_t + r_f * np.sin(theta) + + # append the current points to the points list + points.append([x, y]) + + # add the final two points + points.append([b, d]) + points.append([0, d]) + + polygon = Polygon(points) + return Geometry(polygon, material) + + +def tee_section( + d, b, t_f, t_w, r, n_r, material: pre.Material = pre.DEFAULT_MATERIAL +) -> Geometry: + """Constructs a Tee section with the top left corner at *(0, d)*, with depth *d*, width *b*, + flange thickness *t_f*, web thickness *t_w* and root radius *r*, using *n_r* points to + construct the root radius. + + :param float d: Depth of the Tee section + :param float b: Width of the Tee section + :param float t_f: Flange thickness of the Tee section + :param float t_w: Web thickness of the Tee section + :param float r: Root radius of the Tee section + :param int n_r: Number of points discretising the root radius + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates a Tee section with a depth of 200, a width of 100, a flange + thickness of 12, a web thickness of 6 and a root radius of 8, using 8 points to discretise the + root radius. A mesh is generated with a maximum triangular area of 3.0:: + + from sectionproperties.pre.library.steel_sections import tee_section + + geometry = tee_section(d=200, b=100, t_f=12, t_w=6, r=8, n_r=8) + geometry.create_mesh(mesh_sizes=[3.0]) + + .. figure:: ../images/sections/tee_geometry.png + :align: center + :scale: 75 % + + Tee section geometry. + + .. figure:: ../images/sections/tee_mesh.png + :align: center + :scale: 75 % + + Mesh generated from the above geometry. + """ + points = [] + # add first two points + points.append([b * 0.5 - t_w * 0.5, 0]) + points.append([b * 0.5 + t_w * 0.5, 0]) + + # construct the top right radius + pt = [b * 0.5 + t_w * 0.5 + r, d - t_f - r] + points += draw_radius(pt, r, np.pi, n_r, False) + + # add next four points + points.append([b, d - t_f]) + points.append([b, d]) + points.append([0, d]) + points.append([0, d - t_f]) + + # construct the top left radius + pt = [b * 0.5 - t_w * 0.5 - r, d - t_f - r] + points += draw_radius(pt, r, 0.5 * np.pi, n_r, False) + + polygon = Polygon(points) + return Geometry(polygon, material) + + +def angle_section( + d, b, t, r_r, r_t, n_r, material: pre.Material = pre.DEFAULT_MATERIAL +) -> Geometry: + """Constructs an angle section with the bottom left corner at the origin *(0, 0)*, with depth + *d*, width *b*, thickness *t*, root radius *r_r* and toe radius *r_t*, using *n_r* points to + construct the radii. + + :param float d: Depth of the angle section + :param float b: Width of the angle section + :param float t: Thickness of the angle section + :param float r_r: Root radius of the angle section + :param float r_t: Toe radius of the angle section + :param int n_r: Number of points discretising the radii + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates an angle section with a depth of 150, a width of 100, a thickness + of 8, a root radius of 12 and a toe radius of 5, using 16 points to discretise the radii. A + mesh is generated with a maximum triangular area of 2.0:: + + from sectionproperties.pre.library.steel_sections import angle_section + + geometry = angle_section(d=150, b=100, t=8, r_r=12, r_t=5, n_r=16) + geometry.create_mesh(mesh_sizes=[2.0]) + + .. figure:: ../images/sections/angle_geometry.png + :align: center + :scale: 75 % + + Angle section geometry. + + .. figure:: ../images/sections/angle_mesh.png + :align: center + :scale: 75 % + """ + if r_t > t: + raise ValueError( + "The radius of the toe (r_t) cannot be larger than the toe thickness (t)." + ) + + points = [] + + # add first two points + points.append([0, 0]) + points.append([b, 0]) + + # construct the bottom toe radius + pt = [b - r_t, t - r_t] + points += draw_radius(pt, r_t, 0, n_r) + + # construct the root radius + pt = [t + r_r, t + r_r] + points += draw_radius(pt, r_r, 1.5 * np.pi, n_r, False) + + # construct the top toe radius + pt = [t - r_t, d - r_t] + points += draw_radius(pt, r_t, 0, n_r) + + # add the next point + points.append([0, d]) + + polygon = Polygon(points) + return Geometry(polygon, material) + + +def cee_section( + d, b, l, t, r_out, n_r, material: pre.Material = pre.DEFAULT_MATERIAL +) -> Geometry: + """Constructs a Cee section (typical of cold-formed steel) with the bottom left corner at the + origin *(0, 0)*, with depth *d*, width *b*, lip *l*, thickness *t* and outer radius *r_out*, + using *n_r* points to construct the radius. If the outer radius is less than the thickness + of the Cee Section, the inner radius is set to zero. + + :param float d: Depth of the Cee section + :param float b: Width of the Cee section + :param float l: Lip of the Cee section + :param float t: Thickness of the Cee section + :param float r_out: Outer radius of the Cee section + :param int n_r: Number of points discretising the outer radius + :raises Exception: Lip length must be greater than the outer radius + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates a Cee section with a depth of 125, a width of 50, a lip of 30, a + thickness of 1.5 and an outer radius of 6, using 8 points to discretise the radius. A mesh is + generated with a maximum triangular area of 0.25:: + + from sectionproperties.pre.library.steel_sections import cee_section + + geometry = cee_section(d=125, b=50, l=30, t=1.5, r_out=6, n_r=8) + geometry.create_mesh(mesh_sizes=[0.25]) + + .. figure:: ../images/sections/cee_geometry.png + :align: center + :scale: 75 % + + Cee section geometry. + + .. figure:: ../images/sections/cee_mesh.png + :align: center + :scale: 75 % + """ + # ensure the lip length is greater than the outer radius + if l < r_out: + raise Exception("Lip length must be greater than the outer radius") + + points = [] + + # calculate internal radius + r_in = max(r_out - t, 0) + + # construct the outer bottom left radius + points += draw_radius([r_out, r_out], r_out, np.pi, n_r) + + # construct the outer bottom right radius + points += draw_radius([b - r_out, r_out], r_out, 1.5 * np.pi, n_r) + + if r_out != l: + # add next two points + points.append([b, l]) + points.append([b - t, l]) + + # construct the inner bottom right radius + points += draw_radius([b - t - r_in, t + r_in], r_in, 0, n_r, False) + + # construct the inner bottom left radius + points += draw_radius([t + r_in, t + r_in], r_in, 1.5 * np.pi, n_r, False) + + # construct the inner top left radius + points += draw_radius([t + r_in, d - t - r_in], r_in, np.pi, n_r, False) + + # construct the inner top right radius + points += draw_radius([b - t - r_in, d - t - r_in], r_in, 0.5 * np.pi, n_r, False) + + if r_out != l: + # add next two points + points.append([b - t, d - l]) + points.append([b, d - l]) + + # construct the outer top right radius + points += draw_radius([b - r_out, d - r_out], r_out, 0, n_r) + + # construct the outer top left radius + points += draw_radius([r_out, d - r_out], r_out, 0.5 * np.pi, n_r) + + polygon = Polygon(points) + return Geometry(polygon, material) + + +def zed_section( + d, b_l, b_r, l, t, r_out, n_r, material: pre.Material = pre.DEFAULT_MATERIAL +) -> Geometry: + """Constructs a zed section with the bottom left corner at the origin *(0, 0)*, with depth *d*, + left flange width *b_l*, right flange width *b_r*, lip *l*, thickness *t* and outer radius + *r_out*, using *n_r* points to construct the radius. If the outer radius is less than the + thickness of the Zed Section, the inner radius is set to zero. + + :param float d: Depth of the zed section + :param float b_l: Left flange width of the Zed section + :param float b_r: Right flange width of the Zed section + :param float l: Lip of the Zed section + :param float t: Thickness of the Zed section + :param float r_out: Outer radius of the Zed section + :param int n_r: Number of points discretising the outer radius + :param Optional[sectionproperties.pre.pre.Material]: Material to associate with this geometry + + The following example creates a zed section with a depth of 100, a left flange width of 40, a + right flange width of 50, a lip of 20, a thickness of 1.2 and an outer radius of 5, using 8 + points to discretise the radius. A mesh is generated with a maximum triangular area of 0.15:: + + from sectionproperties.pre.library.steel_sections import zed_section + + geometry = zed_section(d=100, b_l=40, b_r=50, l=20, t=1.2, r_out=5, n_r=8) + geometry.create_mesh(mesh_sizes=[0.15]) + + .. figure:: ../images/sections/zed_geometry.png + :align: center + :scale: 75 % + + zed section geometry. + + .. figure:: ../images/sections/zed_mesh.png + :align: center + :scale: 75 % + """ + # ensure the lip length is greater than the outer radius + if l < r_out: + raise Exception("Lip length must be greater than the outer radius") + + points = [] + + # calculate internal radius + r_in = max(r_out - t, 0) + + # construct the outer bottom left radius + points += draw_radius([r_out, r_out], r_out, np.pi, n_r) + + # construct the outer bottom right radius + points += draw_radius([b_r - r_out, r_out], r_out, 1.5 * np.pi, n_r) + + if r_out != l: + # add next two points + points.append([b_r, l]) + points.append([b_r - t, l]) + + # construct the inner bottom right radius + points += draw_radius([b_r - t - r_in, t + r_in], r_in, 0, n_r, False) + + # construct the inner bottom left radius + points += draw_radius([t + r_in, t + r_in], r_in, 1.5 * np.pi, n_r, False) + + # construct the outer top right radius + points += draw_radius([t - r_out, d - r_out], r_out, 0, n_r) + + # construct the outer top left radius + points += draw_radius([t - b_l + r_out, d - r_out], r_out, 0.5 * np.pi, n_r) + + if r_out != l: + # add the next two points + points.append([t - b_l, d - l]) + points.append([t - b_l + t, d - l]) + + # construct the inner top left radius + points += draw_radius([2 * t - b_l + r_in, d - t - r_in], r_in, np.pi, n_r, False) + + # construct the inner top right radius + points += draw_radius([-r_in, d - t - r_in], r_in, 0.5 * np.pi, n_r, False) + polygon = Polygon(points) + return Geometry(polygon, material) + + +def box_girder_section( + d, b_t, b_b, t_ft, t_fb, t_w, material: pre.Material = pre.DEFAULT_MATERIAL +): + """Constructs a box girder section centered at at *(max(b_t, b_b)/2, d/2)*, with depth *d*, top + width *b_t*, bottom width *b_b*, top flange thickness *t_ft*, bottom flange thickness *t_fb* + and web thickness *t_w*. + + :param float d: Depth of the Box Girder section + :param float b_t: Top width of the Box Girder section + :param float b_b: Bottom width of the Box Girder section + :param float t_ft: Top flange thickness of the Box Girder section + :param float t_fb: Bottom flange thickness of the Box Girder section + :param float t_w: Web thickness of the Box Girder section + + The following example creates a Box Girder section with a depth of 1200, a top width of 1200, a + bottom width of 400, a top flange thickness of 16, a bottom flange thickness of 12 and a web + thickness of 8. A mesh is generated with a maximum triangular area of 5.0:: + + from sectionproperties.pre.library.steel_sections import box_girder_section + + geometry = box_girder_section(d=1200, b_t=1200, b_b=400, t_ft=100, t_fb=80, t_w=50) + geometry.create_mesh(mesh_sizes=[200.0]) + + .. figure:: ../images/sections/box_girder_geometry.png + :align: center + :scale: 75 % + + Box Girder geometry. + + .. figure:: ../images/sections/box_girder_mesh.png + :align: center + :scale: 75 % + + Mesh generated from the above geometry. + """ + outer_points = [] + inner_points = [] + + # calculate central axis + x_c = max(b_t, b_b) * 0.5 + + # determine side wall angle + if b_t < b_b: + phi_b = np.arctan2(d, 0.5 * (b_b - b_t)) + phi_t = np.pi - phi_b + else: + phi_t = np.arctan2(d, 0.5 * (b_t - b_b)) + phi_b = np.pi - phi_t + + # determine inner wall x-offsets + x_bot = t_fb / np.tan(np.pi - phi_b) + x_top = t_ft / np.tan(np.pi - phi_t) + web_x = abs(t_w / np.sin(np.pi - phi_b)) + + # add outer points + outer_points.append([x_c - 0.5 * b_b, 0]) + outer_points.append([x_c + 0.5 * b_b, 0]) + outer_points.append([x_c + 0.5 * b_t, d]) + outer_points.append([x_c - 0.5 * b_t, d]) + + # add inner points + inner_points.append([x_c - 0.5 * b_b - x_bot + web_x, t_fb]) + inner_points.append([x_c + 0.5 * b_b + x_bot - web_x, t_fb]) + inner_points.append([x_c + 0.5 * b_t + x_top - web_x, d - t_ft]) + inner_points.append([x_c - 0.5 * b_t - x_top + web_x, d - t_ft]) + + outer_polygon = Polygon(outer_points) + inner_polygon = Polygon(inner_points) + + return Geometry(outer_polygon - inner_polygon, material) diff --git a/sectionproperties/pre/library/utils.py b/sectionproperties/pre/library/utils.py new file mode 100644 index 00000000..495f2316 --- /dev/null +++ b/sectionproperties/pre/library/utils.py @@ -0,0 +1,54 @@ +import numpy as np + + +def draw_radius(pt: list, r: float, theta: float, n, ccw: bool = True): + """Adds a quarter radius of points to the points list - centered at point *pt*, with radius + *r*, starting at angle *theta*, with *n* points. If r = 0, adds pt only. + + :param pt: Centre of radius *(x,y)* + :type pt: list[float, float] + :param float r: Radius + :param float theta: Initial angle + :param int n: Number of points + :param bool ccw: Counter-clockwise rotation? + """ + points = [] + if r == 0: + points.append(pt) + return points + + if ccw: + mult = 1 + else: + mult = -1 + + # calculate radius of points + for i in range(n): + # determine angle + t = theta + mult * i * 1.0 / max(1, n - 1) * np.pi * 0.5 + + x = pt[0] + r * np.cos(t) + y = pt[1] + r * np.sin(t) + points.append([x, y]) + return points + + +def rotate(point, angle: float): + """ + Rotate a point counterclockwise by a given angle around origin [0, 0] + + :param list point: Point coordinates to be rotated + :param float angle: Angle to rotate point coordinates + :return: Coordinates of rotated point + :rtype: list[float, float] + """ + + pt_x, pt_y = point + + c = np.cos(angle) + s = np.sin(angle) + + new_x = c * pt_x - s * pt_y + new_y = s * pt_x + c * pt_y + + return [new_x, new_y] diff --git a/sectionproperties/tests/test_offset.py b/sectionproperties/tests/test_offset.py index b4211a41..7830bf86 100644 --- a/sectionproperties/tests/test_offset.py +++ b/sectionproperties/tests/test_offset.py @@ -1,9 +1,10 @@ import pytest_check as check import numpy as np -import sectionproperties.pre.sections as sections -from sectionproperties.analysis.cross_section import Section +import sectionproperties.pre.library.standard_sections as sections +import sectionproperties.pre.library.steel_sections as steel_sections +from sectionproperties.analysis.section import Section from shapely.geometry import Polygon -from sectionproperties.pre.sections import Geometry +from sectionproperties.pre.geometry import Geometry r_tol = 1e-3 @@ -31,7 +32,7 @@ def test_rectangular_offset(): def test_box_offset(): # exterior negative offset - box = sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1) + box = steel_sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1) box = box.offset_perimeter(amount=-5, where="exterior") box.create_mesh([50]) section = Section(box) @@ -40,7 +41,7 @@ def test_box_offset(): check.almost_equal(section.get_area(), area, rel=r_tol) # exterior positve offset - box = sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1) + box = steel_sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1) box = box.offset_perimeter(amount=5, where="exterior") box.create_mesh([50]) section = Section(box) @@ -49,7 +50,7 @@ def test_box_offset(): check.almost_equal(section.get_area(), area, rel=r_tol) # interior negative offset - box = sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1) + box = steel_sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1) box = box.offset_perimeter(amount=-5, where="interior") box.create_mesh([50]) section = Section(box) @@ -58,7 +59,7 @@ def test_box_offset(): check.almost_equal(section.get_area(), area, rel=r_tol) # interior positive offset - box = sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1) + box = steel_sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1) box = box.offset_perimeter(amount=5, where="interior") box.create_mesh([50]) section = Section(box) @@ -67,7 +68,7 @@ def test_box_offset(): check.almost_equal(section.get_area(), area, rel=r_tol) # all negative offset - box = sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1) + box = steel_sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1) box = box.offset_perimeter(amount=-2.5, where="all") box.create_mesh([50]) section = Section(box) @@ -76,7 +77,7 @@ def test_box_offset(): check.almost_equal(section.get_area(), area, rel=r_tol) # all positive offset - box = sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1) + box = steel_sections.rectangular_hollow_section(d=200, b=100, t=10, r_out=0, n_r=1) box = box.offset_perimeter(amount=5, where="all") box.create_mesh([50]) section = Section(box) @@ -105,7 +106,7 @@ def test_compound_rectangular_isection_offset_corrode(): r = 12 b_p = 250 t_p = 16 - ub = sections.i_section(d=d, b=b, t_f=tf, t_w=tw, r=r, n_r=16) + ub = steel_sections.i_section(d=d, b=b, t_f=tf, t_w=tw, r=r, n_r=16) plate = ( sections.rectangular_section(b=b_p, d=t_p) .align_center(ub) @@ -117,7 +118,7 @@ def test_compound_rectangular_isection_offset_corrode(): section_test = Section(geom_test) section_test.calculate_geometric_properties() - ub_corroded = sections.mono_i_section( + ub_corroded = steel_sections.mono_i_section( d=298, b_t=146, b_b=146, t_ft=8, t_fb=6, t_w=4, r=14, n_r=16 ) plate_corroded1 = ( @@ -154,7 +155,7 @@ def test_compound_stiffened_isection(): Tests that plates 1 and 2 can be eroded to nothing and a valid Section can still be generated without errors. """ - uc = sections.i_section(d=400, b=400, t_f=25, t_w=25, r=30, n_r=8) + uc = steel_sections.i_section(d=400, b=400, t_f=25, t_w=25, r=30, n_r=8) plate1 = ( sections.rectangular_section(b=500, d=10).align_center(uc).align_to(uc, "top") ) diff --git a/sectionproperties/tests/test_perimeter.py b/sectionproperties/tests/test_perimeter.py index 8426240d..3258575c 100644 --- a/sectionproperties/tests/test_perimeter.py +++ b/sectionproperties/tests/test_perimeter.py @@ -1,7 +1,9 @@ import pytest_check as check import numpy as np -import sectionproperties.pre.sections as sections -from sectionproperties.analysis.cross_section import Section +import sectionproperties.pre.library.standard_sections as sections +import sectionproperties.pre.library.steel_sections as steel_sections +from sectionproperties.pre.geometry import Geometry +from sectionproperties.analysis.section import Section r_tol = 1e-3 @@ -16,7 +18,9 @@ def test_rectangular_perimeter(): def test_i_section(): - i_section = sections.i_section(d=308, b=305, t_f=15.4, t_w=9.9, r=16.5, n_r=16) + i_section = steel_sections.i_section( + d=308, b=305, t_f=15.4, t_w=9.9, r=16.5, n_r=16 + ) i_section.create_mesh([100]) section = Section(i_section) section.calculate_geometric_properties() @@ -31,7 +35,7 @@ def test_i_section(): def test_box_girder_perimeter(): - box_girder = sections.box_girder_section( + box_girder = steel_sections.box_girder_section( d=400, b_t=700, b_b=100, t_ft=20, t_fb=20, t_w=12 ) box_girder.create_mesh([100]) @@ -44,7 +48,7 @@ def test_custom_geometry_perimeter(): points = [[0, 0], [5, 0], [11, 8], [3, 2], [0, 2]] facets = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 0]] control_points = [[5, 5]] - custom = sections.Geometry.from_points(points, facets, control_points, holes=None) + custom = Geometry.from_points(points, facets, control_points, holes=None) custom.create_mesh([100]) section = Section(custom) section.calculate_geometric_properties() @@ -77,7 +81,7 @@ def test_compound_rectangular_isection_perimeter1(): r = 12 b_p = 250 t_p = 16 - ub = sections.i_section(d=d, b=b, t_f=tf, t_w=tw, r=r, n_r=16) + ub = steel_sections.i_section(d=d, b=b, t_f=tf, t_w=tw, r=r, n_r=16) plate = ( sections.rectangular_section(b=b_p, d=t_p) .align_center(ub) @@ -101,7 +105,9 @@ def test_compound_rectangular_isection_perimeter1(): def test_compound_rectangular_isection_perimeter2(): - i_section = sections.i_section(d=308, b=305, t_f=15.4, t_w=9.9, r=16.5, n_r=16) + i_section = steel_sections.i_section( + d=308, b=305, t_f=15.4, t_w=9.9, r=16.5, n_r=16 + ) rect1 = ( sections.rectangular_section(d=330, b=16) .align_center(i_section) @@ -126,7 +132,7 @@ def test_compound_rhs_isection_perimeter(): r = 15 b_p = 250 t_p = 16 - rhs = sections.rectangular_hollow_section(d=d, b=b, t=t, r_out=r, n_r=16) + rhs = steel_sections.rectangular_hollow_section(d=d, b=b, t=t, r_out=r, n_r=16) plate1 = ( sections.rectangular_section(b=b_p, d=t_p) .align_center(rhs) diff --git a/sectionproperties/tests/test_rectangle.py b/sectionproperties/tests/test_rectangle.py index cd7713d9..a5520c42 100644 --- a/sectionproperties/tests/test_rectangle.py +++ b/sectionproperties/tests/test_rectangle.py @@ -1,15 +1,15 @@ import pytest_check as check # import unittest -import sectionproperties.pre.sections as sections +import sectionproperties.pre.library.standard_sections as standard_sections import sectionproperties.pre.pre as pre -from sectionproperties.analysis.cross_section import Section +from sectionproperties.analysis.section import Section from sectionproperties.tests.helper_functions import validate_properties -import sectionproperties.analysis.cross_section as file +import sectionproperties.analysis.section as file # Rectangle section setup -rectangle_geometry = sections.rectangular_section(b=50, d=100) +rectangle_geometry = standard_sections.rectangular_section(b=50, d=100) rectangle_geometry.create_mesh(mesh_sizes=100) rectangle_section = Section(rectangle_geometry) rectangle_section.calculate_geometric_properties() diff --git a/sectionproperties/tests/test_sections.py b/sectionproperties/tests/test_sections.py index 4bc2c3c4..5b42bf4e 100644 --- a/sectionproperties/tests/test_sections.py +++ b/sectionproperties/tests/test_sections.py @@ -1,9 +1,11 @@ import pathlib import pytest -from sectionproperties.pre.sections import * -from sectionproperties.pre.nastran_sections import * -from sectionproperties.analysis.cross_section import Section +from sectionproperties.pre.geometry import * +from sectionproperties.pre.library.standard_sections import * +from sectionproperties.pre.library.steel_sections import * +from sectionproperties.pre.library.nastran_sections import * +from sectionproperties.analysis.section import Section from sectionproperties.pre.pre import Material from sectionproperties.pre.rhino import load_3dm, load_brep_encoding from shapely.geometry import ( diff --git a/sectionproperties/tests/test_validation.py b/sectionproperties/tests/test_validation.py index 7f122504..c09bc4d3 100644 --- a/sectionproperties/tests/test_validation.py +++ b/sectionproperties/tests/test_validation.py @@ -1,12 +1,14 @@ import pytest_check as check from shapely.geometry import Polygon -import sectionproperties.pre.sections as sections -from sectionproperties.analysis.cross_section import Section +from sectionproperties.pre.geometry import Geometry +import sectionproperties.pre.library.standard_sections as sections +import sectionproperties.pre.library.steel_sections as steel_sections +from sectionproperties.analysis.section import Section from sectionproperties.tests.helper_functions import validate_properties # Setup for angle section -angle = sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) +angle = steel_sections.angle_section(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) angle.create_mesh(mesh_sizes=2.5) angle_section = Section(angle) angle_section.calculate_geometric_properties() @@ -85,7 +87,7 @@ def test_angle_all_properties(): [45, 10], [-10, 10], ] -custom_geom = sections.Geometry(Polygon(custom_geom_points)) +custom_geom = Geometry(Polygon(custom_geom_points)) custom_geom.create_mesh(mesh_sizes=5) custom_section = Section(custom_geom) custom_section.calculate_geometric_properties()