Skip to content

Commit

Permalink
Merge branch 'master' into addRestraintToNodeWithOnePinnedElement
Browse files Browse the repository at this point in the history
  • Loading branch information
smith120bh committed Aug 28, 2023
2 parents 5531322 + 9dccd55 commit ba6c6b7
Show file tree
Hide file tree
Showing 34 changed files with 961 additions and 451 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
black --check .
- name: Run type checks with mypy
run: |
mypy
mypy -p anastruct
- name: Run FEM tests with pytest
run: |
python -m pytest --pspec tests/
Expand Down
18 changes: 18 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp

// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"njpwerner.autodocstring",
"streetsidesoftware.code-spell-checker",
"ktnrg45.vscode-cython",
"ms-python.isort",
"ms-python.python",
"ms-python.pylint"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [

]
}
15 changes: 13 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"Nmin",
"numpy",
"perp",
"postprocess",
"pspec",
"Qmax",
"Qmin",
Expand All @@ -33,5 +34,15 @@
"wmax",
"wmin"
],
"editor.formatOnSave": true
}
"editor.formatOnSave": true,
"editor.formatOnType": true,
"cSpell.diagnosticLevel": "Hint",
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
"editor.formatOnPaste": true,
"python.linting.mypyArgs": [
"--show-column-numbers",
"--no-pretty"
]
}
3 changes: 2 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
include *.pyx
recursive-include anastruct *.pyx
recursive-include anastruct *.pyx
include anastruct py.typed
2 changes: 1 addition & 1 deletion anastruct/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.4.1"
__version__ = "1.4.2"
37 changes: 24 additions & 13 deletions anastruct/basic.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import collections.abc
from typing import Any, Sequence, Tuple

import numpy as np

try:
from anastruct.cython.cbasic import ( # type: ignore # pylint: disable=unused-import
converge,
angle_x_axis,
converge,
)
except ImportError:
from anastruct.cython.basic import converge, angle_x_axis # type: ignore
from anastruct.cython.basic import angle_x_axis, converge


def find_nearest(array, value):
def find_nearest(array: np.ndarray, value: float) -> Tuple[float, int]:
"""
:param array: (numpy array object)
:param value: (float) value searched for
Expand All @@ -22,20 +24,29 @@ def find_nearest(array, value):
return array[index], index


def integrate_array(y, dx):
def integrate_array(y: np.ndarray, dx: float) -> np.ndarray:
"""
integrate array y * dx
"""
return np.cumsum(y) * dx
return np.cumsum(y) * dx # type: ignore


class FEMException(Exception):
def __init__(self, type_, message):
def __init__(self, type_: str, message: str):
self.type = type_
self.message = message


def args_to_lists(*args):
def arg_to_list(arg: Any, n: int) -> list:
if isinstance(arg, Sequence) and not isinstance(arg, str) and len(arg) == n:
return list(arg)
elif isinstance(arg, Sequence) and not isinstance(arg, str) and len(arg) == 1:
return [arg[0] for _ in range(n)]
else:
return [arg for _ in range(n)]


def args_to_lists(*args: list) -> list:
arg_lists = []
for arg in args:
if isinstance(arg, collections.abc.Iterable) and not isinstance(arg, str):
Expand All @@ -47,16 +58,16 @@ def args_to_lists(*args):
if n == 1:
return arg_lists

args = []
args_return = []
for arg, l in zip(arg_lists, lengths):
if l == n:
args.append(arg)
args_return.append(arg)
else:
args.append([arg[0] for _ in range(n)])
return args
args_return.append([arg[0] for _ in range(n)])
return args_return


def rotation_matrix(angle):
def rotation_matrix(angle: float) -> np.ndarray:
"""
:param angle: (flt) angle in radians
Expand All @@ -67,7 +78,7 @@ def rotation_matrix(angle):
return np.array([[c, -s], [s, c]])


def rotate_xy(a, angle):
def rotate_xy(a: np.ndarray, angle: float) -> np.ndarray:
b = np.array(a)
b[:, 0] -= a[0, 0]
b[:, 1] -= a[0, 1]
Expand Down
4 changes: 2 additions & 2 deletions anastruct/cython/basic.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import math


def converge(lhs, rhs):
def converge(lhs: float, rhs: float) -> float:
"""
Determine convergence factor.
Expand All @@ -17,7 +17,7 @@ def converge(lhs, rhs):
return (rhs / lhs - 1) / div + 1


def angle_x_axis(delta_x, delta_z):
def angle_x_axis(delta_x: float, delta_z: float) -> float:
# dot product v_x = [1, 0] ; v = [delta_x, delta_z]
# dot product = 1 * delta_x + 0 * delta_z -> delta_x
ai = math.acos(delta_x / math.sqrt(delta_x**2 + delta_z**2))
Expand Down
10 changes: 7 additions & 3 deletions anastruct/fem/cython/elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@


@lru_cache(32000)
def det_moment(kl, kr, qi, q, x, EI, L):
def det_moment(
kl: float, kr: float, qi: float, q: float, x: float, EI: float, L: float
) -> float:
"""
See notebook in: anastruct/fem/background/primary_m_v.ipynb
Expand Down Expand Up @@ -47,7 +49,9 @@ def det_moment(kl, kr, qi, q, x, EI, L):


@lru_cache(32000)
def det_shear(kl, kr, qi, q, x, EI, L):
def det_shear(
kl: float, kr: float, qi: float, q: float, x: float, EI: float, L: float
) -> float:
"""
See notebook in: anastruct/fem/background/primary_m_v.ipynb
Expand Down Expand Up @@ -83,7 +87,7 @@ def det_shear(kl, kr, qi, q, x, EI, L):


@lru_cache(32000)
def det_axial(qi, q, x, EA, L):
def det_axial(qi: float, q: float, x: float, EA: float, L: float) -> float:
"""
See notebook in: anastruct/fem/background/distributed_ax_force.ipynb
Expand Down
43 changes: 23 additions & 20 deletions anastruct/fem/elements.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
from __future__ import annotations
from math import sin, cos
from functools import lru_cache

import copy
from typing import TYPE_CHECKING, Dict, Optional, List
from functools import lru_cache
from math import cos, sin
from typing import TYPE_CHECKING, Dict, List, Optional

import numpy as np
from anastruct.basic import FEMException

from anastruct.basic import FEMException

if TYPE_CHECKING:
from anastruct.vertex import Vertex
from anastruct.fem.node import Node
from anastruct.fem.system import Spring
from anastruct.vertex import Vertex

try:
from anastruct.fem.cython.celements import ( # type: ignore # pylint: disable=unused-import
det_shear,
det_moment,
from anastruct.fem.cython.celements import ( # pylint: disable=unused-import
det_axial,
det_moment,
det_shear,
)
except ImportError:
from anastruct.fem.cython.elements import det_shear, det_moment, det_axial
from anastruct.fem.cython.elements import det_axial, det_moment, det_shear

"""
The matrices underneath are for slender beams, where the most deformation occurs due to bending.
Expand All @@ -41,7 +43,7 @@ def __init__(
vertex_2: Vertex,
type_: str,
section_name: str,
spring: Spring = None,
spring: Optional[Spring] = None,
):
"""
:param id_: integer representing the elements ID
Expand Down Expand Up @@ -154,12 +156,12 @@ def determine_force_vector(self) -> Optional[np.ndarray]:
)
return self.element_force_vector

def compile_stiffness_matrix(self):
def compile_stiffness_matrix(self) -> None:
self.stiffness_matrix = stiffness_matrix(
self.constitutive_matrix, self.kinematic_matrix
)

def compile_kinematic_matrix(self, a1: float, a2: float, l: float):
def compile_kinematic_matrix(self, a1: float, a2: float, l: float) -> None:
self.kinematic_matrix = kinematic_matrix(a1, a2, l)

def compile_constitutive_matrix(
Expand All @@ -170,12 +172,12 @@ def compile_constitutive_matrix(
spring: Optional[Dict[int, float]] = None,
node_1_hinge: Optional[bool] = False,
node_2_hinge: Optional[bool] = False,
):
) -> None:
self.constitutive_matrix = constitutive_matrix(
EA, EI, l, spring, node_1_hinge, node_2_hinge
)

def update_stiffness(self, factor: float, node: int):
def update_stiffness(self, factor: float, node: int) -> None:
if node == 1:
self.constitutive_matrix[1][1] *= factor
self.constitutive_matrix[1][2] *= factor
Expand All @@ -186,13 +188,14 @@ def update_stiffness(self, factor: float, node: int):
self.constitutive_matrix[2][2] *= factor
self.compile_stiffness_matrix()

def compile_geometric_non_linear_stiffness_matrix(self):
def compile_geometric_non_linear_stiffness_matrix(self) -> None:
self.compile_stiffness_matrix()
assert self.N_1 is not None
self.stiffness_matrix += geometric_stiffness_matrix(
self.l, self.N_1, self.a1, self.a2
)

def reset(self):
def reset(self) -> None:
self.element_displacement_vector = np.zeros(6)
self.element_primary_force_vector = np.zeros(6)

Expand Down Expand Up @@ -308,10 +311,10 @@ def constitutive_matrix(
def stiffness_matrix(
var_constitutive_matrix: np.ndarray, var_kinematic_matrix: np.ndarray
) -> np.ndarray:
kinematic_transposed_times_constitutive = np.dot(
var_kinematic_matrix.transpose(), var_constitutive_matrix
kinematic_transposed_times_constitutive = (
var_kinematic_matrix.transpose() @ var_constitutive_matrix
)
return np.dot(kinematic_transposed_times_constitutive, var_kinematic_matrix)
return kinematic_transposed_times_constitutive @ var_kinematic_matrix # type: ignore


def geometric_stiffness_matrix(l: float, N: float, a1: float, a2: float) -> np.ndarray:
Expand All @@ -327,7 +330,7 @@ def geometric_stiffness_matrix(l: float, N: float, a1: float, a2: float) -> np.n
c2 = cos(a2)
s2 = sin(a2)
# http://people.duke.edu/~hpgavin/cee421/frame-finite-def.pdf
return (
return ( # type: ignore
N
/ l
* np.array(
Expand Down
2 changes: 1 addition & 1 deletion anastruct/fem/examples/ex_1_2.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from anastruct.fem import system as se


def run():
def run() -> None:
system = se.SystemElements()
system.add_element(location=[[3, 4], [0, 0]], EA=5e9, EI=8000)
system.add_element(location=[[8, 4], [3, 4]], EA=5e9, EI=4000)
Expand Down
3 changes: 2 additions & 1 deletion anastruct/fem/examples/ex_22_loadcombination_doc.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import matplotlib.pyplot as plt
import numpy as np
from anastruct.fem.system import SystemElements

from anastruct import LoadCase, LoadCombination
from anastruct.fem.system import SystemElements

ss = SystemElements()

Expand Down
2 changes: 1 addition & 1 deletion anastruct/fem/examples/ex_7_rotational_spring.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""

ss = SystemElements()
ss.add_element([[0, 0], [3.5, 0]])
ss.add_element([[0.0, 0.0], [3.5, 0.0]])
ss.add_element([7, 0], spring={1: 100})
ss.add_support_fixed([1])
ss.add_support_hinged(3)
Expand Down
22 changes: 15 additions & 7 deletions anastruct/fem/node.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations
from typing import Dict, TYPE_CHECKING

from typing import TYPE_CHECKING, Dict, Optional

from anastruct.vertex import Vertex

if TYPE_CHECKING:
Expand All @@ -13,9 +15,9 @@ def __init__(
Fx: float = 0.0,
Fz: float = 0.0,
Ty: float = 0.0,
ux: float = 0.0,
uz: float = 0.0,
phi_y: float = 0,
ux: Optional[float] = 0.0,
uz: Optional[float] = 0.0,
phi_y: Optional[float] = 0,
vertex: Vertex = Vertex(0, 0),
hinge: bool = False,
):
Expand Down Expand Up @@ -47,7 +49,7 @@ def __init__(
def Fy(self) -> float:
return -self.Fz

def __str__(self):
def __str__(self) -> str:
if self.vertex:
return (
f"[id = {self.id}, Fx = {self.Fx}, Fz = {self.Fz}, Ty = {self.Ty}, ux = {self.ux}, "
Expand Down Expand Up @@ -99,14 +101,20 @@ def __sub__(self, other: Node) -> Node:
hinge=self.hinge,
)

def reset(self):
def reset(self) -> None:
self.Fx = self.Fz = self.Ty = self.ux = self.uz = self.phi_y = 0
self.hinge = False

def add_results(self, other: Node):
def add_results(self, other: Node) -> None:
assert (
self.id == other.id
), "Cannot add nodes as the ID's don't match. The nodes positions don't match."
assert self.phi_y is not None
assert self.ux is not None
assert self.uz is not None
assert other.phi_y is not None
assert other.ux is not None
assert other.uz is not None
self.Fx = self.Fx + other.Fx
self.Fz = self.Fz + other.Fz
self.Ty = self.Ty + other.Ty
Expand Down
Loading

0 comments on commit ba6c6b7

Please sign in to comment.