11from operator import itemgetter
2+ from typing import TYPE_CHECKING
23from typing import Dict
34from typing import List
45from typing import Optional
2122from compas_fea2 .results import ShellStressResult
2223from compas_fea2 .results import SolidStressResult
2324
25+ if TYPE_CHECKING :
26+ from compas_fea2 .problem import Step
27+
28+ from .model import Model
29+ from .nodes import Node
30+ from .parts import _Part
31+ from .sections import _Section
32+ from .shapes import Shape
33+
2434
2535class _Element (FEAData ):
2636 """Initialises a base Element object.
@@ -75,7 +85,7 @@ class _Element(FEAData):
7585
7686 """
7787
78- def __init__ (self , nodes : List ["Node" ], section : "_Section" , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ): # noqa: F821
88+ def __init__ (self , nodes : List ["Node" ], section : "_Section" , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ):
7989 super ().__init__ (** kwargs )
8090 self ._part_key = None
8191 self ._nodes = self ._check_nodes (nodes )
@@ -108,23 +118,23 @@ def __from_data__(cls, data):
108118 return cls (nodes , section , implementation = data .get ("implementation" ), rigid = data .get ("rigid" ))
109119
110120 @property
111- def part (self ) -> "_Part" : # noqa: F821
121+ def part (self ) -> "_Part" :
112122 return self ._registration
113123
114124 @property
115- def model (self ) -> "Model" : # noqa: F821
125+ def model (self ) -> "Model" :
116126 return self .part .model
117127
118128 @property
119129 def results_cls (self ) -> Result :
120130 raise NotImplementedError ("The results_cls property must be implemented in the subclass" )
121131
122132 @property
123- def nodes (self ) -> List ["Node" ]: # noqa: F821
133+ def nodes (self ) -> List ["Node" ]:
124134 return self ._nodes
125135
126136 @nodes .setter
127- def nodes (self , value : List ["Node" ]): # noqa: F821
137+ def nodes (self , value : List ["Node" ]):
128138 self ._nodes = self ._check_nodes (value )
129139
130140 @property
@@ -140,11 +150,11 @@ def points(self) -> List["Point"]:
140150 return [node .point for node in self .nodes ]
141151
142152 @property
143- def section (self ) -> "_Section" : # noqa: F821
153+ def section (self ) -> "_Section" :
144154 return self ._section
145155
146156 @section .setter
147- def section (self , value : "_Section" ): # noqa: F821
157+ def section (self , value : "_Section" ):
148158 self ._section = value
149159
150160 @property
@@ -163,7 +173,7 @@ def on_boundary(self) -> Optional[bool]:
163173 def on_boundary (self , value : bool ):
164174 self ._on_boundary = value
165175
166- def _check_nodes (self , nodes : List ["Node" ]) -> List ["Node" ]: # noqa: F821
176+ def _check_nodes (self , nodes : List ["Node" ]) -> List ["Node" ]:
167177 if len (set ([node ._registration for node in nodes ])) != 1 :
168178 raise ValueError ("At least one of node is registered to a different part or not registered" )
169179 return nodes
@@ -225,15 +235,15 @@ def __from_data__(cls, data):
225235class _Element0D (_Element ):
226236 """Element with 1 dimension."""
227237
228- def __init__ (self , nodes : List ["Node" ], frame : Frame , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ): # noqa: F821
238+ def __init__ (self , nodes : List ["Node" ], frame : Frame , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ):
229239 super ().__init__ (nodes , section = None , implementation = implementation , rigid = rigid , ** kwargs )
230240 self ._frame = frame
231241 self ._ndim = 0
232242
233243 @property
234244 def __data__ (self ):
235- data = super ().__data__ ()
236- data ["frame" ] = self .frame . __data__
245+ data = super ().__data__
246+ data ["frame" ] = self .frame
237247 return data
238248
239249
@@ -247,7 +257,7 @@ class SpringElement(_Element0D):
247257
248258 """
249259
250- def __init__ (self , nodes : List ["Node" ], section : "_Section" , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ): # noqa: F821
260+ def __init__ (self , nodes : List ["Node" ], section : "_Section" , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ):
251261 super ().__init__ (nodes , section = section , implementation = implementation , rigid = rigid , ** kwargs )
252262
253263
@@ -260,7 +270,7 @@ class LinkElement(_Element0D):
260270 use :class:`compas_fea2.model.connectors.RigidLinkConnector`.
261271 """
262272
263- def __init__ (self , nodes : List ["Node" ], section : "_Section" , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ): # noqa: F821
273+ def __init__ (self , nodes : List ["Node" ], section : "_Section" , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ):
264274 super ().__init__ (nodes , section = section , implementation = implementation , rigid = rigid , ** kwargs )
265275
266276
@@ -291,7 +301,7 @@ class _Element1D(_Element):
291301 The volume of the element.
292302 """
293303
294- def __init__ (self , nodes : List ["Node" ], section : "_Section" , frame : Optional [Frame ] = None , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ): # noqa: F821
304+ def __init__ (self , nodes : List ["Node" ], section : "_Section" , frame : Optional [Frame ] = None , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ):
295305 super ().__init__ (nodes , section , implementation = implementation , rigid = rigid , ** kwargs )
296306 if not frame :
297307 raise ValueError ("Frame is required for 1D elements" )
@@ -332,7 +342,7 @@ def frame(self) -> Frame:
332342 return self ._frame
333343
334344 @property
335- def shape (self ) -> Optional ["Shape" ]: # noqa: F821
345+ def shape (self ) -> Optional ["Shape" ]:
336346 return self ._shape
337347
338348 @property
@@ -346,7 +356,7 @@ def volume(self) -> float:
346356 def plot_section (self ):
347357 self .section .plot ()
348358
349- def plot_stress_distribution (self , step : "_Step " , end : str = "end_1" , nx : int = 100 , ny : int = 100 , * args , ** kwargs ): # noqa: F821
359+ def plot_stress_distribution (self , step : "Step " , end : str = "end_1" , nx : int = 100 , ny : int = 100 , * args , ** kwargs ):
350360 """Plot the stress distribution along the element.
351361
352362 Parameters
@@ -369,7 +379,7 @@ def plot_stress_distribution(self, step: "_Step", end: str = "end_1", nx: int =
369379 r = step .section_forces_field .get_element_forces (self )
370380 r .plot_stress_distribution (* args , ** kwargs )
371381
372- def section_forces_result (self , step : "Step" ) -> "Result" : # noqa: F821
382+ def section_forces_result (self , step : "Step" ) -> "Result" :
373383 """Get the section forces result for the element.
374384 Parameters
375385 ----------
@@ -386,7 +396,7 @@ def section_forces_result(self, step: "Step") -> "Result": # noqa: F821
386396 raise ValueError ("The step does not have a section_forces_field" )
387397 return step .section_forces_field .get_result_at (self )
388398
389- def forces (self , step : "Step" ) -> "Result" : # noqa: F821
399+ def forces (self , step : "Step" ) -> "Result" :
390400 """Get the forces result for the element.
391401
392402 Parameters
@@ -402,7 +412,7 @@ def forces(self, step: "Step") -> "Result": # noqa: F821
402412 r = self .section_forces_result (step )
403413 return r .forces
404414
405- def moments (self , step : "_Step " ) -> "Result" : # noqa: F821
415+ def moments (self , step : "Step " ) -> "Result" :
406416 """Get the moments result for the element.
407417
408418 Parameters
@@ -433,7 +443,7 @@ class BeamElement(_Element1D):
433443class TrussElement (_Element1D ):
434444 """A 1D element that resists axial loads."""
435445
436- def __init__ (self , nodes : List ["Node" ], section : "_Section" , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ): # noqa: F821
446+ def __init__ (self , nodes : List ["Node" ], section : "_Section" , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ):
437447 super ().__init__ (nodes , section , frame = [1 , 1 , 1 ], implementation = implementation , rigid = rigid , ** kwargs )
438448
439449
@@ -476,7 +486,7 @@ class Face(FEAData):
476486
477487 """
478488
479- def __init__ (self , nodes : List ["Node" ], tag : str , element : Optional ["_Element" ] = None , ** kwargs ): # noqa: F821
489+ def __init__ (self , nodes : List ["Node" ], tag : str , element : Optional ["_Element" ] = None , ** kwargs ):
480490 super ().__init__ (** kwargs )
481491 self ._nodes = nodes
482492 self ._tag = tag
@@ -506,7 +516,7 @@ def __from_data__(cls, data):
506516 return cls (nodes , data ["tag" ], element = element )
507517
508518 @property
509- def nodes (self ) -> List ["Node" ]: # noqa: F821
519+ def nodes (self ) -> List ["Node" ]:
510520 return self ._nodes
511521
512522 @property
@@ -522,11 +532,11 @@ def element(self) -> Optional["_Element"]:
522532 return self ._registration
523533
524534 @property
525- def part (self ) -> "_Part" : # noqa: F821
535+ def part (self ) -> "_Part" :
526536 return self .element .part
527537
528538 @property
529- def model (self ) -> "Model" : # noqa: F821
539+ def model (self ) -> "Model" :
530540 return self .element .model
531541
532542 @property
@@ -578,7 +588,7 @@ class _Element2D(_Element):
578588 {'s1': (0,1,2), ...}
579589 """
580590
581- def __init__ (self , nodes : List ["Node" ], section : Optional ["_Section" ] = None , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ): # noqa: F821
591+ def __init__ (self , nodes : List ["Node" ], section : Optional ["_Section" ] = None , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ):
582592 super ().__init__ (
583593 nodes = nodes ,
584594 section = section ,
@@ -592,11 +602,11 @@ def __init__(self, nodes: List["Node"], section: Optional["_Section"] = None, im
592602 self ._ndim = 2
593603
594604 @property
595- def nodes (self ) -> List ["Node" ]: # noqa: F821
605+ def nodes (self ) -> List ["Node" ]:
596606 return self ._nodes
597607
598608 @nodes .setter
599- def nodes (self , value : List ["Node" ]): # noqa: F821
609+ def nodes (self , value : List ["Node" ]):
600610 self ._nodes = self ._check_nodes (value )
601611 self ._faces = self ._construct_faces (self ._face_indices )
602612
@@ -636,7 +646,7 @@ def _construct_faces(self, face_indices: Dict[str, Tuple[int]]) -> List[Face]:
636646 """
637647 return [Face (nodes = itemgetter (* indices )(self .nodes ), tag = name , element = self ) for name , indices in face_indices .items ()]
638648
639- def stress_results (self , step : "_Step " ) -> "Result" : # noqa: F821
649+ def stress_results (self , step : "Step " ) -> "Result" :
640650 """Get the stress results for the element.
641651
642652 Parameters
@@ -662,7 +672,7 @@ class ShellElement(_Element2D):
662672
663673 """
664674
665- def __init__ (self , nodes : List ["Node" ], section : Optional ["_Section" ] = None , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ): # noqa: F821
675+ def __init__ (self , nodes : List ["Node" ], section : Optional ["_Section" ] = None , implementation : Optional [str ] = None , rigid : bool = False , ** kwargs ):
666676 super ().__init__ (
667677 nodes = nodes ,
668678 section = section ,
@@ -704,7 +714,7 @@ class _Element3D(_Element):
704714
705715 """
706716
707- def __init__ (self , nodes : List ["Node" ], section : "_Section" , implementation : Optional [str ] = None , ** kwargs ): # noqa: F821
717+ def __init__ (self , nodes : List ["Node" ], section : "_Section" , implementation : Optional [str ] = None , ** kwargs ):
708718 super ().__init__ (
709719 nodes = nodes ,
710720 section = section ,
@@ -725,11 +735,11 @@ def frame(self) -> Frame:
725735 return self ._frame
726736
727737 @property
728- def nodes (self ) -> List ["Node" ]: # noqa: F821
738+ def nodes (self ) -> List ["Node" ]:
729739 return self ._nodes
730740
731741 @nodes .setter
732- def nodes (self , value : List ["Node" ]): # noqa: F821
742+ def nodes (self , value : List ["Node" ]):
733743 self ._nodes = value
734744 self ._faces = self ._construct_faces (self ._face_indices )
735745
@@ -744,7 +754,7 @@ def faces(self) -> Optional[List[Face]]:
744754 @property
745755 def edges (self ):
746756 seen = set ()
747- for _ , face in self ._faces .itmes ():
757+ for _ , face in self ._faces .items ():
748758 for u , v in pairwise (face + face [:1 ]):
749759 if (u , v ) not in seen :
750760 seen .add ((u , v ))
@@ -781,7 +791,7 @@ def area(self) -> float:
781791 return self ._area
782792
783793 @classmethod
784- def from_polyhedron (cls , polyhedron : Polyhedron , section : "_Section" , implementation : Optional [str ] = None , ** kwargs ) -> "_Element3D" : # noqa: F821
794+ def from_polyhedron (cls , polyhedron : Polyhedron , section : "_Section" , implementation : Optional [str ] = None , ** kwargs ) -> "_Element3D" :
785795 from compas_fea2 .model import Node
786796
787797 element = cls ([Node (vertex ) for vertex in polyhedron .vertices ], section , implementation , ** kwargs )
@@ -823,8 +833,8 @@ class TetrahedronElement(_Element3D):
823833
824834 def __init__ (
825835 self ,
826- nodes : List ["Node" ], # noqa: F821
827- section : "_Section" , # noqa: F821
836+ nodes : List ["Node" ],
837+ section : "_Section" ,
828838 implementation : Optional [str ] = None ,
829839 ** kwargs ,
830840 ):
@@ -899,7 +909,7 @@ class PentahedronElement(_Element3D):
899909class HexahedronElement (_Element3D ):
900910 """A Solid cuboid element with 6 faces (extruded rectangle)."""
901911
902- def __init__ (self , nodes : List ["Node" ], section : "_Section" , implementation : Optional [str ] = None , ** kwargs ): # noqa: F821
912+ def __init__ (self , nodes : List ["Node" ], section : "_Section" , implementation : Optional [str ] = None , ** kwargs ):
903913 super ().__init__ (
904914 nodes = nodes ,
905915 section = section ,
0 commit comments