1010import warnings
1111from dataclasses import dataclass , field
1212from functools import lru_cache
13- from typing import TYPE_CHECKING
13+ from typing import TYPE_CHECKING , Any , Callable
1414
1515import numpy as np
1616import numpy .typing as npt
17- from numba import njit
18- from numba .core .errors import NumbaPerformanceWarning
1917
2018
2119if TYPE_CHECKING :
2220 from sectionproperties .pre .pre import Material
2321
2422
25- @njit (cache = True , nogil = True ) # type: ignore
23+ # numba is an optional dependency
24+ try :
25+ from numba import njit
26+ from numba .core .errors import NumbaPerformanceWarning
27+
28+ USE_NUMBA = True
29+ except ImportError :
30+
31+ def njit () -> None :
32+ """Assigns empty function to njit if numba isn't installed.
33+
34+ Returns:
35+ None
36+ """
37+ return None
38+
39+ USE_NUMBA = False
40+
41+
42+ def conditional_decorator (
43+ dec : Callable [[Any ], Any ],
44+ condition : bool ,
45+ ) -> Callable [[Any ], Any ]:
46+ """A decorator that applies a decorator only if a condition is True.
47+
48+ Args:
49+ dec: Decorator to apply
50+ condition: Apply decorator if this is true
51+
52+ Returns:
53+ Decorator wrapper
54+ """
55+
56+ def decorator (func : Callable [[Any ], Any ]) -> Callable [[Any ], Any ]:
57+ """Decorator wrapper.
58+
59+ Args:
60+ func: Function decorator operates on.
61+
62+ Returns:
63+ Original or decorated function.
64+ """
65+ if not condition :
66+ return func
67+
68+ return dec (func ) # type: ignore
69+
70+ return decorator
71+
72+
73+ @conditional_decorator (njit , USE_NUMBA )
2674def _assemble_torsion (
2775 k_el : npt .NDArray [np .float64 ],
2876 f_el : npt .NDArray [np .float64 ],
@@ -55,7 +103,7 @@ def _assemble_torsion(
55103 return k_el , f_el , c_el
56104
57105
58- @njit ( cache = True , nogil = True ) # type: ignore
106+ @conditional_decorator ( njit , USE_NUMBA )
59107def _shear_parameter (
60108 nx : float , ny : float , ixx : float , iyy : float , ixy : float
61109) -> tuple [float , float , float , float , float , float ]:
@@ -81,7 +129,7 @@ def _shear_parameter(
81129 return r , q , d1 , d2 , h1 , h2
82130
83131
84- @njit ( cache = True , nogil = True ) # type: ignore
132+ @conditional_decorator ( njit , USE_NUMBA )
85133def _assemble_shear_load (
86134 f_psi : npt .NDArray [np .float64 ],
87135 f_phi : npt .NDArray [np .float64 ],
@@ -126,7 +174,7 @@ def _assemble_shear_load(
126174 return f_psi , f_phi
127175
128176
129- @njit ( cache = True , nogil = True ) # type: ignore
177+ @conditional_decorator ( njit , USE_NUMBA )
130178def _assemble_shear_coefficients (
131179 kappa_x : float ,
132180 kappa_y : float ,
@@ -648,7 +696,9 @@ def element_stress(
648696
649697 # extrapolate results to nodes, ignore numba warnings about performance
650698 with warnings .catch_warnings ():
651- warnings .simplefilter ("ignore" , category = NumbaPerformanceWarning )
699+ if USE_NUMBA :
700+ warnings .simplefilter ("ignore" , category = NumbaPerformanceWarning )
701+
652702 sig_zz_mxx = extrapolate_to_nodes (w = sig_zz_mxx_gp )
653703 sig_zz_myy = extrapolate_to_nodes (w = sig_zz_myy_gp )
654704 sig_zz_m11 = extrapolate_to_nodes (w = sig_zz_m11_gp )
@@ -951,7 +1001,7 @@ def gauss_points(*, n: int) -> npt.NDArray[np.float64]:
9511001
9521002
9531003@lru_cache (maxsize = None )
954- @njit ( cache = True , nogil = True ) # type: ignore
1004+ @conditional_decorator ( njit , USE_NUMBA )
9551005def __shape_function_cached (
9561006 coords : tuple [float , ...],
9571007 gauss_point : tuple [float , float , float ],
@@ -1039,7 +1089,7 @@ def shape_function(
10391089
10401090
10411091@lru_cache (maxsize = None )
1042- @njit ( cache = True , nogil = True ) # type: ignore
1092+ @conditional_decorator ( njit , USE_NUMBA )
10431093def shape_function_only (p : tuple [float , float , float ]) -> npt .NDArray [np .float64 ]:
10441094 """The values of the ``Tri6`` shape function at a point ``p``.
10451095
@@ -1117,7 +1167,7 @@ def shape_function_only(p: tuple[float, float, float]) -> npt.NDArray[np.float64
11171167)
11181168
11191169
1120- @njit ( cache = True , nogil = True ) # type: ignore
1170+ @conditional_decorator ( njit , USE_NUMBA )
11211171def extrapolate_to_nodes (w : npt .NDArray [np .float64 ]) -> npt .NDArray [np .float64 ]:
11221172 """Extrapolates results at six Gauss points to the six nodes of a ``Tri6`` element.
11231173
@@ -1130,7 +1180,7 @@ def extrapolate_to_nodes(w: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
11301180 return h_inv @ w
11311181
11321182
1133- @njit ( cache = True , nogil = True ) # type: ignore
1183+ @conditional_decorator ( njit , USE_NUMBA )
11341184def principal_coordinate (
11351185 phi : float ,
11361186 x : float ,
@@ -1153,7 +1203,7 @@ def principal_coordinate(
11531203 return x * cos_phi + y * sin_phi , y * cos_phi - x * sin_phi
11541204
11551205
1156- @njit ( cache = True , nogil = True ) # type: ignore
1206+ @conditional_decorator ( njit , USE_NUMBA )
11571207def global_coordinate (
11581208 phi : float ,
11591209 x11 : float ,
@@ -1176,7 +1226,7 @@ def global_coordinate(
11761226 return x11 * cos_phi - y22 * sin_phi , x11 * sin_phi + y22 * cos_phi
11771227
11781228
1179- @njit ( cache = True , nogil = True ) # type: ignore
1229+ @conditional_decorator ( njit , USE_NUMBA )
11801230def point_above_line (
11811231 u : npt .NDArray [np .float64 ],
11821232 px : float ,
0 commit comments