Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
cb6d6e3
Option for not rendering nodes added
JWock82 Jul 11, 2023
54cbb1e
Fix for cylinder meshes about X and Z axes
JWock82 Jul 15, 2023
c63780a
Update README.md
JWock82 Jul 15, 2023
43a8db7
Added 'default' theme to rendering
JWock82 Jul 15, 2023
bbff7a1
Move TC checks out of `FEModel3D`
JWock82 Jul 16, 2023
05738a1
Merge pull request #166 from Ottermatics/master
JWock82 Jul 22, 2023
8378bf1
Revert "Allow Selective Analysis Of Load Combos"
JWock82 Jul 22, 2023
c6652ac
Merge pull request #167 from JWock82/revert-166-master
JWock82 Jul 22, 2023
ef6ab49
Moved analysis methods out of `FEModel3D`
JWock82 Jul 22, 2023
db26cfc
Merge branch 'analysis_code_organization' of https://github.com/JWock…
JWock82 Jul 22, 2023
63afe56
Added load combination tags
JWock82 Jul 22, 2023
f108b21
Changed * to @ now that arrays are used
JWock82 Jul 25, 2023
c067195
Changed * to @ for numpy array multiplication
JWock82 Jul 25, 2023
0314746
Improvements for 'print' theme
JWock82 Jul 26, 2023
b26bdba
Updates to load combo tags
JWock82 Jul 26, 2023
cd7b5ba
Worked on "themes" for visualization
JWock82 Jul 29, 2023
442c407
Allowed for multiple tags to a single load combo
JWock82 Jul 29, 2023
a0d7ade
Prep for v0.0.80
JWock82 Jul 29, 2023
b9cfb27
Add fix for 3D cylinder mesh:
SoundsSerious Aug 4, 2023
a5f437e
Merge branch 'master' into cylinder_mesh_3d
SoundsSerious Aug 4, 2023
1030701
Moved `_renumber` out of `FEModel3D`
JWock82 Aug 5, 2023
fbfa2b4
Analysis code simplification/organization
JWock82 Aug 5, 2023
721ee83
Revert mesh loop changes, while accomodating at least one mesh element.
SoundsSerious Aug 7, 2023
5a8dbd9
Merge branch 'cylinder_mesh_3d' of https://github.com/Ottermatics/PyN…
SoundsSerious Aug 7, 2023
fa1910b
Merge pull request #169 from Ottermatics/cylinder_mesh_3d
JWock82 Aug 7, 2023
952573e
Merge pull request #3 from JWock82/master
SoundsSerious Aug 9, 2023
23f5d3c
uncomment AnnulusMesh.generate()
Aug 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Examples/Beam on Elastic Foundation.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
# Analyze the model. PyNite's standard solver is most appropriate or this model since there are
# non-linear features (compression-only springs) but no large axial forces that would cause P-Delta
# effects.
boef.analyze(check_statics=True)
boef.analyze(log=True, check_statics=True)

# Render the mdoel with the deformed shape using PyNite's buit-in renderer
from PyNite.Visualization import Renderer
Expand Down
606 changes: 606 additions & 0 deletions PyNite/Analysis.py

Large diffs are not rendered by default.

887 changes: 65 additions & 822 deletions PyNite/FEModel3D.py

Large diffs are not rendered by default.

9 changes: 4 additions & 5 deletions PyNite/LoadCombo.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@ class LoadCombo():
"""A class that stores all the information necessary to define a load combination.
"""

def __init__(self, name, combo_type=None, factors={}):
def __init__(self, name, combo_tags=None, factors={}):
"""Initializes a new load combination.

:param name: A unique name for the load combination.
:type name: str
:param combo_type: The type of load combination. This can be any string you would like to use to categorize your load combinations. It is useful for separating load combinations into strength, service, or overstrength combinations as often required by building codes. This parameter has no effect on the analysis. It's simply a tool to help you filter results later on. Defaults to `None`.
:type combo_type: str, optional
:param combo_tags: A list of tags for the load combination. This is a list of any strings you would like to use to categorize your load combinations. It is useful for separating load combinations into strength, service, or overstrength combinations as often required by building codes. This parameter has no effect on the analysis, but it can be used to restrict analysis to only the load combinations with the tags you specify.
:type combo_tags: list, optional
:param factors: A dictionary of load case names (`keys`) followed by their load factors (`items`). For example, the load combination 1.2D+1.6L would be represented as follows: `{'D': 1.2, 'L': 1.6}`. Defaults to {}.
:type factors: dict, optional
"""

self.name = name # A unique user-defined name for the load combination
self.combo_type = combo_type # Used to track what type of load combination (e.g. strength or serviceability)
# The 'combo_type' is just a placeholder for future features for now
self.combo_tags = combo_tags # Used to categorize the load combination (e.g. strength or serviceability)
self.factors = factors # A dictionary containing each load case name and associated load factor

def AddLoadCase(self, case_name, factor):
Expand Down
55 changes: 30 additions & 25 deletions PyNite/Mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ def __init__(self, mesh_size, outer_radius, inner_radius, thickness, material, m
self.num_quads_inner = None
self.num_quads_outer = None

# self.generate()
self.generate()

def generate(self):

Expand Down Expand Up @@ -1203,12 +1203,12 @@ class CylinderMesh(Mesh):
A mesh of quadrilaterals forming a cylinder.

The mesh is formed with the local y-axis of the elements pointed toward
the base of the
the base of the cylinder

Parameters
----------
mesh_size : number
The desired mesh size. This value will only be used to mesh vertically if `num_elements` is
The desired mesh element edge size. This value will only be used to mesh vertically if `num_elements` is
specified. Otherwise it will be used to mesh the circumference too.
radius : number
The radius of the cylinder to the element centers
Expand Down Expand Up @@ -1240,40 +1240,53 @@ class CylinderMesh(Mesh):
The type of element to use for the mesh: 'Quad' or 'Rect'
"""

def __init__(self, mesh_size, radius, height, thickness, material, model, kx_mod=1, ky_mod=1,
origin=[0, 0, 0], axis='Y', start_node='N1', start_element='Q1',
num_elements=None, element_type='Quad'):
def __init__(self, mesh_size, radius, height, thickness, material, model, kx_mod=1, ky_mod=1,origin=[0, 0, 0], axis='Y', start_node='N1', start_element='Q1', num_elements=None, element_type='Quad'):

# Inherit properties and methods from the parent `Mesh` class
super().__init__(thickness, material, model, kx_mod, ky_mod, start_node, start_element)

# Define a few new additional class properties related to cylinders
self.radius = radius
self.h = height
self.mesh_size = mesh_size
self.origin = origin
self.axis = axis

# Check if the user has requested a specific number of elements for each course of plates. This can be useful for ensuring the mesh matches up with other meshes.
if num_elements == None:
# Calculate the number of elements if the user hasn't specified
self.num_elements = int(round(2*pi*radius/mesh_size, 0))
else:
# Use the user specified number of elements
self.num_elements = num_elements

self.origin = origin
self.axis = axis

# Check which type of element the user has requested (rectangular plate or quad)
self.element_type = element_type

# Generate the mesh
self.generate()

def generate(self):

# Get the mesh thickness and the material name
thickness = self.thickness
material = self.material

mesh_size = self.mesh_size # Desired mesh size
num_elements = self.num_elements # Number of quadrilaterals in the ring
n = self.num_elements
num_elements = self.num_elements # Number of quadrilaterals in each course of the ring
n = self.num_elements # Total number of elements in the mesh (initialized for a single ring at the moment)

radius = self.radius
h = self.h
y = self.origin[1]

# Set the cylinder base's local y-coordinate
if self.axis == 'Y':
y = self.origin[1]
elif self.axis == 'X':
y = self.origin[0]
elif self.axis == 'Z':
y = self.origin[2]

n = int(self.start_node[1:])
q = int(self.start_element[1:])

Expand All @@ -1292,31 +1305,23 @@ def generate(self):
h_y = height/n_vert # Element height in the vertical direction
# Create a mesh of nodes for the ring
if self.axis == 'Y':
ring = CylinderRingMesh(radius, h_y, num_elements, thickness, material, self.model, 1, 1, [0, y, 0],
self.axis, 'N' + str(n), 'Q' + str(q), element_type)
ring = CylinderRingMesh(radius, h_y, num_elements, thickness, material, self.model, 1, 1, [0, y, 0], self.axis, 'N' + str(n), 'Q' + str(q), element_type)
elif self.axis == 'X':
ring = CylinderRingMesh(radius, h_y, num_elements, thickness, material, self.model, 1, 1, [y, 0, 0],
self.axis, 'N' + str(n), 'Q' + str(q), element_type)
ring = CylinderRingMesh(radius, h_y, num_elements, thickness, material, self.model, 1, 1, [y, 0, 0], self.axis, 'N' + str(n), 'Q' + str(q), element_type)
elif self.axis == 'Z':
ring = CylinderRingMesh(radius, h_y, num_elements, thickness, material, self.model, 1, 1, [0, 0, y],
self.axis, 'N' + str(n), 'Q' + str(q), element_type)
ring = CylinderRingMesh(radius, h_y, num_elements, thickness, material, self.model, 1, 1, [0, 0, y], self.axis, 'N' + str(n), 'Q' + str(q), element_type)

n += num_elements
q += num_elements

# Add the newly generated nodes and elements to the overall mesh. Note that if duplicate
# keys exist, the `.update()` method will overwrite them with the newly generated key value
# pairs. This works in our favor by automatically eliminating duplicate nodes at the shared
# boundaries between rings.
# Add the newly generated nodes and elements to the overall mesh. Note that if duplicate keys exist, the `.update()` method will overwrite them with the newly generated key value pairs. This works in our favor by automatically eliminating duplicate nodes at the shared boundaries between rings.
self.nodes.update(ring.nodes)
self.elements.update(ring.elements)

# Prepare to move to the next ring
y += h_y

# After calling the `.update()` method some elements are still attached to the duplicate
# nodes that are no longer in the dictionary. Attach these plates to the nodes that are
# still in the dictionary instead.
# After calling the `.update()` method some elements are still attached to the duplicate nodes that are no longer in the dictionary. Attach these plates to the nodes that are still in the dictionary instead.
for element in self.elements.values():
element.i_node = self.nodes[element.i_node.name]
element.j_node = self.nodes[element.j_node.name]
Expand Down
20 changes: 10 additions & 10 deletions PyNite/Plate3D.py
Original file line number Diff line number Diff line change
Expand Up @@ -616,25 +616,25 @@ def shear(self, x, y, combo_name='Combo 1'):
a = self._a(combo_name)

# Calculate the derivatives of the plate moments needed to compute shears
dMx_dx = (Db*array([[0, 0, 0, 0, 0, 0, -6, 0, 0, 0, -6*y, 0],
dMx_dx = (Db @ array([[0, 0, 0, 0, 0, 0, -6, 0, 0, 0, -6*y, 0],
[0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, -6*y],
[0, 0, 0, 0, 0, 0, 0, -4, 0, 0, -12*x, 0]])*a)[0]
[0, 0, 0, 0, 0, 0, 0, -4, 0, 0, -12*x, 0]]) @ a)[0]

dMxy_dy = (Db*array([[0, 0, 0, 0, 0, 0, 0, -2, 0, 0, -6*x, 0],
dMxy_dy = (Db @ array([[0, 0, 0, 0, 0, 0, 0, -2, 0, 0, -6*x, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 0, -6*x],
[0, 0, 0, 0, 0, 0, 0, 0, -4, 0, 0, -12*y]])*a)[2]
[0, 0, 0, 0, 0, 0, 0, 0, -4, 0, 0, -12*y]]) @ a)[2]

dMy_dy = (Db*array([[0, 0, 0, 0, 0, 0, 0, -2, 0, 0, -6*x, 0],
dMy_dy = (Db @ array([[0, 0, 0, 0, 0, 0, 0, -2, 0, 0, -6*x, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 0, -6*x],
[0, 0, 0, 0, 0, 0, 0, 0, -4, 0, 0, -12*y]])*a)[1]
[0, 0, 0, 0, 0, 0, 0, 0, -4, 0, 0, -12*y]]) @ a)[1]

dMxy_dx = (Db*array([[0, 0, 0, 0, 0, 0, -6, 0, 0, 0, -6*y, 0],
dMxy_dx = (Db @ array([[0, 0, 0, 0, 0, 0, -6, 0, 0, 0, -6*y, 0],
[0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, -6*y],
[0, 0, 0, 0, 0, 0, 0, -4, 0, 0, -12*x, 0]])*a)[2]
[0, 0, 0, 0, 0, 0, 0, -4, 0, 0, -12*x, 0]]) @ a)[2]

# Calculate internal shears
Qx = (dMx_dx + dMxy_dy)[0, 0]
Qy = (dMy_dy + dMxy_dx)[0, 0]
Qx = (dMx_dx + dMxy_dy)[0]
Qy = (dMy_dy + dMxy_dx)[0]

# Return internal shears
return array([[Qx],
Expand Down
Loading