Skip to content

Commit

Permalink
Improvements to add_mesh method
Browse files Browse the repository at this point in the history
  • Loading branch information
JWock82 committed Feb 4, 2022
1 parent 0201d25 commit 31ad425
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 53 deletions.
159 changes: 106 additions & 53 deletions PyNite/FEModel3D.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,45 +376,69 @@ def add_quad(self, name, i_node, j_node, m_node, n_node, t, E, nu, kx_mod=1, ky_
#Return the quad name
return name

def add_mesh(self, mesh):
def add_mesh(self, mesh, rename=True):
"""
Adds a predefined mesh to the model.
Parameters
----------
mesh : Mesh
A mesh object.
rename : bool
When set to `True`, all nodes and elements in the model will be renamed prior to
merging the mesh into the model. It's recommended to leave this value at its default of
`True`. Setting this value to `False` can cause problems if node or element names in
the mesh are already being used by the model.
"""

# rename all the nodes and elements currently in the model
if rename: self.rename()

# Add the mesh's nodes to the finite element model
self.Nodes.update(mesh.nodes)
for node in mesh.nodes.values():

# Add the mesh's elements to the finite element model
if list(mesh.elements.values())[0].type == 'Quad':
self.Quads.update(mesh.elements)
elif list(mesh.elements.values())[0].type == 'Rect':
self.Plates.update(mesh.elements)

# If the mesh contained duplicate keys that were already in the `Nodes` dictionary, the old
# nodes will have been abandoned in favor of the new nodes. Reattach any elements that are
# still referencing the old nodes to the new nodes.
for element in self.Quads.values():
element.i_node = self.Nodes[element.i_node.Name]
element.j_node = self.Nodes[element.j_node.Name]
element.m_node = self.Nodes[element.m_node.Name]
element.n_node = self.Nodes[element.n_node.Name]

for element in self.Plates.values():
element.i_node = self.Nodes[element.i_node.Name]
element.j_node = self.Nodes[element.j_node.Name]
element.m_node = self.Nodes[element.m_node.Name]
element.n_node = self.Nodes[element.n_node.Name]

for element in self.Members.values():
element.i_node = self.Nodes[element.i_node.Name]
element.j_node = self.Nodes[element.j_node.Name]
# Check to see if this node's name already exists in the `Nodes` dictionary
if not node.Name in self.Nodes.keys():
# Add the node to the `Nodes` dictionary
self.Nodes[node.Name] = node
else:
# Get the next available node name and rename the node
new_name = 'N' + str(len(self.Nodes))
node.Name = new_name
self.Nodes[new_name] = node

# Determine what type of elements are in the mesh from the mesh's first element
element_type = list(mesh.elements.values())[0].type

# Add the mesh's elements to the finite element model
for element in mesh.elements.values():

# Check the element type
if element_type == 'Rect':

# Check to see if this element's name already exists in the `Plates` dictionary
if not element.Name in self.Plates.keys():
# Add the element to the `Plates` dictionary
self.Plates[element.Name] = element
else:
# Get the next available element name and rename the element
new_name = 'P' + str(len(self.Plates))
element.Name = new_name
self.Plates[new_name] = element

elif element_type == 'Quad':

# Check to see if this element's name already exists in the `Quads` dictionary
if not element.Name in self.Quads.keys():
# Add the element to the `Quads` dictionary
self.Quads[element.Name] = element
else:
# Get the next available element name and rename the element
new_name = 'Q' + str(len(self.Quads))
element.Name = new_name
self.Quads[new_name] = element

# Attach the model's load combinations to each element from the mesh
for element in mesh.elements.values():
element.LoadCombos = self.LoadCombos

Expand Down Expand Up @@ -489,6 +513,11 @@ def merge_duplicate_nodes(self, tolerance=0.001):

# Add `name_2` to the list of nodes to be removed
remove_list.append(name_2)

# # Determine if there are any other nodes using this node's name
# if name_1 == name_2:
# # Rename the node:
# self.Nodes[name_2].Name = 'N' + str(len(self.Nodes))

# Remove the duplicate nodes from the model
for name in remove_list:
Expand Down Expand Up @@ -1004,33 +1033,6 @@ def GetQuad(self, name):
# If the quad name is not found
raise ValueError(f"Quad '{name}' was not found in the model")

def _renumber(self):
'''
Assigns node, spring, member, and plate member ID numbers to be used internally by the
program. Numbers are assigned according to the order nodes, springs, members, and plates
were added to the model.
'''

# Number each node in the model
for id, node in enumerate(self.Nodes.values()):
node.ID = id

# Number each spring in the model
for id, spring in enumerate(self.Springs.values()):
spring.ID = id

# Number each member in the model
for id, member in enumerate(self.Members.values()):
member.ID = id

# Number each plate in the model
for id, plate in enumerate(self.Plates.values()):
plate.ID = id

# Number each quadrilateral in the model
for id, quad in enumerate(self.Quads.values()):
quad.ID = id

def _aux_list(self):
'''
Builds a list with known nodal displacements and with the positions in global stiffness matrix of known
Expand Down Expand Up @@ -2746,6 +2748,57 @@ def _check_statics(self):
# Print the static check table
print(statics_table)
print('')

def _renumber(self):
"""
Assigns noe and element ID numbers to be used internally by the program. Numbers are
assigned according to the order in which they occur in each dictionary.
"""

# Number each node in the model
for id, node in enumerate(self.Nodes.values()):
node.ID = id

# Number each spring in the model
for id, spring in enumerate(self.Springs.values()):
spring.ID = id

# Number each member in the model
for id, member in enumerate(self.Members.values()):
member.ID = id

# Number each plate in the model
for id, plate in enumerate(self.Plates.values()):
plate.ID = id

# Number each quadrilateral in the model
for id, quad in enumerate(self.Quads.values()):
quad.ID = id

def rename(self):
"""
Renames all the nodes and elements in the model.
"""

# Rename each node in the model
for id, node in enumerate(self.Nodes.values()):
node.Name = 'N' + str(id)

# Rename each spring in the model
for id, spring in enumerate(self.Springs.values()):
spring.Name = 'S' + str(id)

# Rename each member in the model
for id, member in enumerate(self.Members.values()):
member.Name = 'M' + str(id)

# Rename each plate in the model
for id, plate in enumerate(self.Plates.values()):
plate.Name = 'P' + str(id)

# Rename each quad in the model
for id, quad in enumerate(self.Quads.values()):
quad.Name = 'Q' + str(id)

def orphaned_nodes(self):
"""
Expand Down
5 changes: 5 additions & 0 deletions PyNite/Mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def __init__(self, t, E, nu, kx_mod=1, ky_mod=1, start_node='N1', start_element=
self.kx_mod = kx_mod # Local x stiffness modification factor for elements in the mesh
self.ky_mod = ky_mod # Local y stiffness modification factor for elements in the mesh
self.start_node = start_node # The name of the first node in the mesh
self.last_node = None # The name of the last node in the mesh
self.start_element = start_element # The name of the first element in the mesh
self.last_element = None # The name of the last element in the mesh
self.nodes = {} # A dictionary containing the nodes in the mesh
Expand Down Expand Up @@ -574,6 +575,10 @@ def generate(self):
for node_name in node_del_list:
del self.nodes[node_name]

# Identify the last node and last element in the mesh
self.last_node = list(self.nodes.values())[-1]
self.last_element = list(self.elements.values())[-1]

def node_local_coords(self, node):
"""
Calculates a node's position in the mesh's local coordinate system
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ PyNite depends on the following packages:
# What's New?
v0.0.62
* PyNite now checks for nodal instabilities when analyzing a model. If nodal instabilities are found, PyNite will output the unstable nodes and directions to the console, and will throw an exception.
* Added a method called `rename` to the `FEModel3D` class for quickly renaming all the nodes and elements in the model in sequential order.
* Added a `last_node` and `last_element` attribute to the `mesh` class. These methods can be used to get the name of the last node or element in a mesh.
* Improved the reliability of the `add_mesh` method. It now can handle adding meshes containing node and element names already defined in the model. It automatically resolves the duplicate names.

v0.0.57 thru 0.0.61
* Fixed a stubborn bug that wouldn't create openings if they didn't have a node inside them. This prevented openings from showing up in some meshes.
Expand Down

0 comments on commit 31ad425

Please sign in to comment.