Source code for lib.solver_input
""" solver_input module contains classes that represents the input data"""
import numpy as np
import os
from abc import ABCMeta, abstractmethod
[docs]class SolverInput(metaclass=ABCMeta):
"""
SolverInput is the object representing the input data of the
structure to be solved.
This is a abstract class that cannot be instantiated, served as a base
class for all the specific input data object.
Parameters
----------
source_name : str
The name of the input directory or the input xlsx file
containing struture's data.
Attributes
----------
node_per_element: int
Number of node per element.
dof : int
Degree of freedoms of nodes.
num_of_nodes : int
Total number of nodes of the structure.
num_of_elements : int
Total number of elements of the structure.
nodal_data : numpy.ndarray
An array containing the nodal labels and nodal coordinates.
The structure is as follows:
1st column : node labels
2nd column : x coordinate of the node
3rd column : y coordinate of the node
4th column : z coordinate of the node (if applicable)
element_data : numpy.ndarray
An array containing the cooresponding nodes and properties
of the elements. The structure is as follows:
1st column : element labels
2nd column : first nodes
3rd column : second nodes
4th column : property number (see properties array)
bound_con : numpy.ndarray
an array containing the nodal fixed boundary conditions of
the problem. The 1st column is the corresponding nodal labels,
the remaining columns corresponds to conditions in x, y, and
z coordinates. 1 represents fixed, 0 represents fixed.
Nodes not included in this array are treated as free nodes.
bound_con_nonhomo : numpy.ndarray
An array containing the non-homogeneous conditions.
Similar structure as bound_con, except that columns
corresponding x, y, and z coodinates are the magnitude
of displacements.
nodal_forces : numpy.ndarray
An array containing the external nodal forces. Similar
structure as bound_con, except that the columns
corresponding x, y, and z coordinates are the magnitude of
displacements.
properties : numpy.ndarray
an array containing the properties of all elements. The
structure is as follows:
1st column : property labels corresponds to array 'element_data'
2nd column : material number corresponds to array 'materials'
3rd column : cross-sectional area of the cooresponding elements.
4th column : z Moment of inertia of the corresponding elements.
materials : numpy.ndarray
an array containing the properties of all elements. The
structure is as follows:
1st column : material labels corresponds to array 'properties'
2nd column : Young's modulus
3rd column : Density of the material
Methods
-------
get_element_property(property_type, element_num, is_label=False)
returns the property of a single element.
"""
def __init__(self, source_name):
if os.path.isfile('./'+source_name):
self._read_excel_input(source_name)
else:
self._read_txt_input(source_name)
@property
@abstractmethod
def node_per_element(self):
pass
@property
@abstractmethod
def dof(self):
pass
@property
@abstractmethod
def num_of_nodes(self):
pass
@property
@abstractmethod
def num_of_elements(self):
pass
@property
@abstractmethod
def element_dim(self):
pass
def _read_excel_input(self, filename):
""" get input data of the structure from a excel file. """
from pandas import read_excel
self.nodal_data = read_excel(filename, sheet_name = 'N').values
self.element_data = read_excel(filename, sheet_name = 'E').values
self.bound_con = read_excel(filename, sheet_name = 'BC').values
self.bound_con_nonhomo = \
read_excel(filename, sheet_name = 'BC_NH').values
self.nodal_forces = read_excel(filename, sheet_name = 'F').values
self.properties = read_excel(filename, sheet_name = 'P' ).values
self.materials = read_excel(filename, sheet_name = 'M').values
def _read_txt_input(self, dirname):
"""
get input data of the structure from a directory contains
txt files
"""
input_dir_path = './' + dirname
self.nodal_data = np.loadtxt(input_dir_path + '/nodal_data.txt')
self.element_data = np.loadtxt(input_dir_path + '/element_data.txt',
ndmin = 2)
self.bound_con = np.loadtxt(input_dir_path + '/bound_con.txt',
ndmin = 2)
if os.path.isfile(input_dir_path + '/bound_con_nonhomo.txt'):
self.bound_con_nonhomo = \
np.loadtxt(input_dir_path + '/bound_con_nonhomo.txt',
ndmin = 2)
else:
self.bound_con_nonhomo = np.array([])
self.nodal_forces = np.loadtxt(input_dir_path + '/nodal_forces.txt',
ndmin = 2)
self.properties = np.loadtxt(input_dir_path + '/properties.txt',
ndmin = 2)
self.materials = np.loadtxt(input_dir_path + '/materials.txt',
ndmin = 2)
[docs] @abstractmethod
def get_element_property(self, property_type, element_num, is_label=False):
""" Returns the property of a single elements.
parameters
----------
property_type : str
A string that indicates the property to return.
element_num : int
an integer indicates the index or the label of
the element.
is_label : bool
a boolean indicates if the variable 'element_num' is a
label. If it is true, the function will search for the
element property using the element's label. If it is
false, the function will search for the element property
using the index of the array 'element_data'.
The default is false.
"""
pass
[docs]class TrussInput2D(SolverInput):
""" TrussInput object represents input data for truss structures.
See SolverInput class for more descriptions on parameters and attributes.
"""
def __init__(self, filename):
SolverInput.__init__(self, filename)
self.node_per_element = 2
self.dof = self.bound_con.shape[1]-1
self.num_of_nodes = self.nodal_data.shape[0]
self.num_of_elements = self.element_data.shape[0]
self.element_dim = 1
[docs] def get_element_property(self, property_type, element_num, is_label=False):
"""
See SolverInput for descriptions.
property_type options:
'A' : area
'E' : Young's modulus
'I' : moment of inertia
'rho' : material density
'Yc' : compressive yield strength
'Yt' : tensile yield strenth
'L' : element length
'dcos' : directional cosine values of the element
'node_ind' : indicies in the array 'nodal_data'
corresponding to the element
"""
if is_label:
element_num = \
np.argwhere(self.element_data[:,0] == element_num).item(0)
property_label = self.element_data[element_num, 3]
property_index = \
np.argwhere(self.properties[:,0]==property_label).item(0)
material_label = \
self.properties[property_index,1]
material_index = \
np.argwhere(self.materials[:,0]==material_label).item(0)
if property_type == 'A':
result = self.properties[property_index,2]
elif property_type == 'E':
result = self.materials[material_index,1]
elif property_type == 'I':
result = self.properties[property_index,3]
elif property_type == 'rho':
result = self.materials[material_index,2]
elif property_type == 'Yc': # compressive yield strength
result = self.materials[material_index,3]
elif property_type == 'Yt': # tensile yield strength
result = self.materials[material_index,4]
elif property_type == 'L' or property_type == 'dcos' \
or property_type == 'node_ind':
result = self._node_derived_properties(property_type, element_num)
return result
def _node_derived_properties(self, property_type, element_num):
"""returns the property related to the nodal data"""
node1_index = np.argwhere(self.nodal_data[:,0] ==
self.element_data[element_num,1]).item(0)
node2_index = np.argwhere(self.nodal_data[:,0] ==
self.element_data[element_num,2]).item(0)
if property_type == 'node_ind':
return [node1_index, node2_index]
length = 0
for i in range(1, self.nodal_data.shape[1]):
length += (self.nodal_data[node1_index, i]
- self.nodal_data[node2_index, i]) ** 2
length = length ** 0.5
if property_type == 'L':
return length
else:
cx = (self.nodal_data[node2_index,1]
- self.nodal_data[node1_index,1]) / length
cy = (self.nodal_data[node2_index,2]
- self.nodal_data[node1_index,2]) / length
if self.nodal_data.shape[1] - 1 == 2: # 2D
cz = 0
else:
cz = (self.nodal_data[node2_index,3]
- self.nodal_data[node1_index,3]) / length
return np.array([cx,cy,cz])
[docs]class TriangularElementInput(SolverInput):
def __init__(self, filename=None):
SolverInput.__init__(self, filename)
self.node_per_element = 3
self.dof = self.bound_con.shape[1]-1
self.num_of_nodes = self.nodal_data.shape[0]
self.num_of_elements = self.element_data.shape[0]
self.element_dim = 2
[docs] def get_element_property(self, property_type, element_num, is_label=False):
"""
See SolverInput for descriptions.
property_type options:
't' : thickness
'E' : Young's modulus
'nu' : poisson's ratio
'node_ind' : indicies in the array 'nodal_data' corresponding
to the element.
'nodal_coord' : nodal coordinates of the given element.
"""
if is_label:
element_num = \
np.argwhere(self.element_data[:,0] == element_num).item(0)
property_label = self.element_data[element_num,
self.node_per_element + 1]
property_index = \
np.argwhere(self.properties[:,0]==property_label).item(0)
material_label = self.properties[property_index,1]
material_index = \
np.argwhere(self.materials[:,0]==material_label).item(0)
if property_type == 't':
result = self.properties[property_index,2]
elif property_type == 'E':
result = self.materials[material_index,1]
elif property_type == 'nu':
result = self.materials[material_index,2]
elif property_type == 'node_ind':
result = self._get_nodal_indices(element_num)
elif property_type == 'nodal_coord':
result = self._get_nodal_coordinates(element_num)
return result
def _get_nodal_indices(self, element_num):
"""get nodal indices of a given element. """
nodal_indices = []
for i in range(1,4):
nodal_indices.append(np.argwhere(self.nodal_data[:,0] ==
self.element_data[element_num, i]).item(0))
return nodal_indices
def _get_nodal_coordinates(self, element_num):
"""get nodal coorinates of a given element. """
nodal_indices = self._get_nodal_indices(element_num)
nodal_coord_nparray = self.nodal_data[nodal_indices, 1:]
return nodal_coord_nparray