From da221f638011b8ed2ea6d5fadd4438975d166b30 Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Thu, 29 Jan 2026 12:52:12 +1100 Subject: [PATCH 01/18] Add base of continuous beam generator code --- anastruct/preprocess/beam.py | 324 +++++++++++++++++++++++++++++ anastruct/preprocess/beam_class.py | 322 ++++++++++++++++++++++++++++ 2 files changed, 646 insertions(+) create mode 100644 anastruct/preprocess/beam.py create mode 100644 anastruct/preprocess/beam_class.py diff --git a/anastruct/preprocess/beam.py b/anastruct/preprocess/beam.py new file mode 100644 index 0000000..62c124c --- /dev/null +++ b/anastruct/preprocess/beam.py @@ -0,0 +1,324 @@ +from typing import Any, Literal, Optional + +import numpy as np + +from anastruct.preprocess.beam_class import Beam +from anastruct.types import SectionProps +from anastruct.vertex import Vertex + + +class SimpleBeam(Beam): + """Simple beam with a pin support at one end, and a roller support at the other.""" + + def __init__( + self, + length: float, + angle: float = 0.0, + section: Optional[SectionProps] = None, + ) -> None: + super().__init__( + length=length, + angle=angle, + section=section, + ) + + @property + def type(self) -> str: + return "Simple Beam" + + def define_nodes(self) -> None: + self.nodes.append(Vertex(0.0, 0.0)) + self.nodes.append(Vertex(self.dx * self.length, self.dy * self.length)) + + def define_supports(self) -> None: + self.support_definitions[0] = "pinned" + self.support_definitions[1] = "roller" + + +class CantileverBeam(Beam): + """Cantilever beam with a fixed support at one end, and free at the other.""" + + def __init__( + self, + length: float, + cantilever_side: Literal["left", "right"] = "right", + angle: float = 0.0, + section: Optional[SectionProps] = None, + ) -> None: + super().__init__( + length=length, + angle=angle, + section=section, + ) + self.cantilever_side = cantilever_side.lower() + if self.cantilever_side not in ["left", "right"]: + raise ValueError( + "cantilever_side must be either 'left' or 'right', " + f"got '{cantilever_side}'" + ) + + @property + def type(self) -> str: + return "Cantilever Beam" + + def define_nodes(self) -> None: + self.nodes.append(Vertex(0.0, 0.0)) + self.nodes.append(Vertex(self.dx * self.length, self.dy * self.length)) + + def define_supports(self) -> None: + self.support_definitions[1 if self.cantilever_side == "left" else 0] = "fixed" + + +class RightCantileverBeam(CantileverBeam): + """Cantilever beam with a fixed support at the left end, and free at the right.""" + + def __init__( + self, + length: float, + angle: float = 0.0, + section: Optional[SectionProps] = None, + ) -> None: + super().__init__( + length=length, + cantilever_side="right", + angle=angle, + section=section, + ) + + @property + def type(self) -> str: + return "Right Cantilever Beam" + + +class LeftCantileverBeam(CantileverBeam): + """Cantilever beam with a free support at the left end, and fixed at the right.""" + + def __init__( + self, + length: float, + angle: float = 0.0, + section: Optional[SectionProps] = None, + ) -> None: + super().__init__( + length=length, + cantilever_side="left", + angle=angle, + section=section, + ) + + @property + def type(self) -> str: + return "Left Cantilever Beam" + + +class MultiSpanBeam(Beam): + """Simply supported multi-span beam. Assumes equal spans unless span_lengths provided.""" + + def __init__( + self, + length: Optional[float] = None, + num_spans: Optional[int] = None, + span_lengths: Optional[list[float]] = None, + cantilevers: Optional[Literal["left", "right", "both"]] = None, + angle: float = 0.0, + section: Optional[SectionProps] = None, + ) -> None: + if span_lengths is None and num_spans is None: + raise ValueError("Either num_spans or span_lengths must be provided.") + if span_lengths is not None and num_spans is not None: + raise ValueError("Only one of num_spans or span_lengths may be provided.") + if num_spans is not None and length is None: + raise ValueError("If num_spans is provided, length must also be provided.") + if num_spans is not None and length is not None: + span_lengths = [length / num_spans] * num_spans + + super().__init__( + length=sum(span_lengths) if span_lengths else num_spans, + span_lengths=span_lengths, + angle=angle, + section=section, + ) + self.num_spans = num_spans + if cantilevers not in [None, "left", "right", "both"]: + raise ValueError( + "cantilevers must be either None, 'left', 'right', or 'both', " + f"got '{cantilevers}'" + ) + self.cantilevers = cantilevers + + @property + def type(self) -> str: + return "Multi-Span Beam" + + def define_nodes(self) -> None: + current_length = 0.0 + self.nodes.append(Vertex(0.0, 0.0)) + for span in self.span_lengths: + current_length += span + self.nodes.append( + Vertex( + self.dx * current_length, + self.dy * current_length, + ) + ) + + def define_supports(self) -> None: + first_support = 0 if self.cantilevers in [None, "right"] else 1 + last_support = ( + len(self.span_lengths) + if self.cantilevers in [None, "left"] + else len(self.span_lengths) - 1 + ) + self.support_definitions[first_support] = "pinned" + for i in range(first_support + 1, last_support): + self.support_definitions[i] = "roller" + + +class TwoSpanBeam(MultiSpanBeam): + """Simply supported two-span beam with equal spans.""" + + def __init__( + self, + length: float, + angle: float = 0.0, + section: Optional[SectionProps] = None, + ) -> None: + super().__init__( + length=length, + num_spans=2, + angle=angle, + section=section, + ) + + @property + def type(self) -> str: + return "Two-Span Beam" + + +class ThreeSpanBeam(MultiSpanBeam): + """Simply supported three-span beam with equal spans.""" + + def __init__( + self, + length: float, + angle: float = 0.0, + section: Optional[SectionProps] = None, + ) -> None: + super().__init__( + length=length, + num_spans=3, + angle=angle, + section=section, + ) + + @property + def type(self) -> str: + return "Three-Span Beam" + + +class FourSpanBeam(MultiSpanBeam): + """Simply supported four-span beam with equal spans.""" + + def __init__( + self, + length: float, + angle: float = 0.0, + section: Optional[SectionProps] = None, + ) -> None: + super().__init__( + length=length, + num_spans=4, + angle=angle, + section=section, + ) + + @property + def type(self) -> str: + return "Four-Span Beam" + + +def create_beam(beam_type: str, **kwargs: Any) -> Beam: + """Factory function to create beam instances by type name. + + Provides a convenient way to create beams without importing specific classes. + Type names are case-insensitive and can use underscores or hyphens as separators. + + Args: + truss_type (str): Name of the truss type. Supported types: + Flat trusses: "howe", "pratt", "warren" + Roof trusses: "king_post", "queen_post", "fink", "howe_roof", "pratt_roof", + "fan", "modified_queen_post", "double_fink", "double_howe", + "modified_fan", "attic" + **kwargs: Arguments to pass to the truss constructor + + Returns: + Truss: An instance of the requested truss type + + Raises: + ValueError: If truss_type is not recognized + + Examples: + >>> truss = create_truss("howe", width=20, height=2.5, unit_width=2.0) + >>> truss = create_truss("king-post", width=10, roof_pitch_deg=30) + """ + # Normalize the truss type name + normalized = truss_type.lower().replace("-", "_").replace(" ", "_") + + # Map of normalized names to classes + truss_map = { + # Flat trusses + "howe": HoweFlatTruss, + "howe_flat": HoweFlatTruss, + "pratt": PrattFlatTruss, + "pratt_flat": PrattFlatTruss, + "warren": WarrenFlatTruss, + "warren_flat": WarrenFlatTruss, + # Roof trusses + "king_post": KingPostRoofTruss, + "kingpost": KingPostRoofTruss, + "queen_post": QueenPostRoofTruss, + "queenpost": QueenPostRoofTruss, + "fink": FinkRoofTruss, + "howe_roof": HoweRoofTruss, + "pratt_roof": PrattRoofTruss, + "fan": FanRoofTruss, + "modified_queen_post": ModifiedQueenPostRoofTruss, + "modified_queenpost": ModifiedQueenPostRoofTruss, + "double_fink": DoubleFinkRoofTruss, + "doublefink": DoubleFinkRoofTruss, + "double_howe": DoubleHoweRoofTruss, + "doublehowe": DoubleHoweRoofTruss, + "modified_fan": ModifiedFanRoofTruss, + "modifiedfan": ModifiedFanRoofTruss, + "attic": AtticRoofTruss, + "attic_roof": AtticRoofTruss, + } + + if normalized not in truss_map: + available = sorted(set(truss_map.keys())) + raise ValueError( + f"Unknown truss type '{truss_type}'. Available types: {', '.join(available)}" + ) + + truss_class = truss_map[normalized] + assert issubclass(truss_class, Truss) + return truss_class(**kwargs) + + +__all__ = [ + "HoweFlatTruss", + "PrattFlatTruss", + "WarrenFlatTruss", + "KingPostRoofTruss", + "QueenPostRoofTruss", + "FinkRoofTruss", + "HoweRoofTruss", + "PrattRoofTruss", + "FanRoofTruss", + "ModifiedQueenPostRoofTruss", + "DoubleFinkRoofTruss", + "DoubleHoweRoofTruss", + "ModifiedFanRoofTruss", + "AtticRoofTruss", + "create_truss", +] diff --git a/anastruct/preprocess/beam_class.py b/anastruct/preprocess/beam_class.py new file mode 100644 index 0000000..5906bb0 --- /dev/null +++ b/anastruct/preprocess/beam_class.py @@ -0,0 +1,322 @@ +from abc import ABC, abstractmethod +from typing import Iterable, Literal, Optional, Sequence, Union, overload + +import numpy as np + +from anastruct.fem.system import SystemElements +from anastruct.fem.system_components.util import add_node +from anastruct.types import LoadDirection, SectionProps +from anastruct.vertex import Vertex + +DEFAULT_BEAM_SECTION: SectionProps = { + "EI": 1e6, + "EA": 1e8, + "g": 0.0, +} + + +class Beam(ABC): + """Abstract base class for 2D beam structures. + + Provides a framework for creating parametric beam geometries with automated + node generation, connectivity, and support definitions. Subclasses implement + specific beam types (simple, cantilever, etc.). + + The beam generation follows a three-phase process: + 1. define_nodes() - Generate node coordinates + 2. define_connectivity() - Define which nodes connect to form elements + 3. define_supports() - Define support locations and types + + Attributes: + length (float): Total length of the beam (length units) + angle (float): Angle of the beam (degrees; 0 = horizontal, positive = CCW); defauts to 0.0 + section (SectionProps): Section properties for all beam elements; defaults to DEFAULT_BEAM_SECTION + supports_type (Literal["simple", "pinned", "fixed"]): Type of supports to apply; defaults to "simple" + system (SystemElements): The FEM system containing all nodes, elements, and supports; initialized after adding elements + """ + + # Common geometry + length: float + span_lengths: list[float] + angle: float + + # Material properties + section: SectionProps + + # Defined by subclass (initialized in define_* methods) + nodes: list[Vertex] + node_ids: dict[int, list[int]] + support_definitions: dict[int, Literal["fixed", "pinned", "roller"]] + + # Defined by main class (initialized in add_elements) + element_ids: dict[int, list[int]] + + # System + system: SystemElements + + def __init__( + self, + length: Optional[float] = None, + span_lengths: Optional[list[float]] = None, + angle: float = 0.0, + section: Optional[SectionProps] = None, + ): + """Initialize a truss structure. + + Args: + length (float): Total length of the beam (length units). Must be positive. Either length or span_lengths must be provided. + span_lengths (list[float]): List of span lengths for each span. Must be positive. Either length or span_lengths must be provided. + angle (float): Angle of the truss (degrees; 0 = horizontal, positive = CCW); defaults to 0.0 + section (SectionProps): Section properties for all beam elements; defaults to DEFAULT_BEAM_SECTION + + Raises: + ValueError: If width or height is not positive. + """ + if length is None and span_lengths is None: + raise ValueError("Either length or span_lengths must be provided.") + if length is not None and span_lengths is not None: + raise ValueError("Only one of length or span_lengths may be provided.") + if span_lengths is not None: + if any(l <= 0 for l in span_lengths): + raise ValueError( + f"All span lengths must be positive, got {span_lengths}" + ) + self.span_lengths = span_lengths + self.length = sum(span_lengths) + if length is not None: + if length <= 0: + raise ValueError(f"length must be positive, got {length}") + self.length = length + self.span_lengths = [length] + + if angle > -np.pi / 2 and angle < np.pi / 2: + print( + f"Warning: A very small angle was provided ({angle}). Please ensure input units are degrees." + ) + if angle < 0 or angle >= 360: + angle = angle % 360 + + self.angle = angle + self.section = section or DEFAULT_BEAM_SECTION + + self.dx = np.cos(self.angle * np.pi / 180) + self.dy = np.sin(self.angle * np.pi / 180) + + # Initialize mutable attributes (prevents sharing between instances) + self.nodes = [] + self.node_ids = {} + self.support_definitions = {} + self.element_ids = {} + + self.define_nodes() + self.define_supports() + + self.system = SystemElements() + self.add_nodes() + self.add_elements() + self.add_supports() + + @property + @abstractmethod + def type(self) -> str: + """Return the human-readable name of the beam type.""" + + @abstractmethod + def define_nodes(self) -> None: + """Generate node coordinates and populate self.nodes list. + + Must be implemented by subclasses. Should create Vertex objects + representing all node locations in the beam. + """ + + @abstractmethod + def define_supports(self) -> None: + """Define support locations and types by populating self.support_definitions. + + Must be implemented by subclasses. Should also populate + self.node_ids dictionary mapping spanwise node indices to global node IDs. + """ + + def add_nodes(self) -> None: + """Add all nodes from self.nodes to the SystemElements.""" + for i, vertex in enumerate(self.nodes): + add_node(self.system, point=vertex, node_id=i) + + def add_elements(self) -> None: + """Create elements from connectivity definitions and add to SystemElements. + + Populates element ID list self.element_ids. + """ + + def add_span_elements( + node_pairs: Iterable[tuple[int, int]], + section: SectionProps, + ) -> list[int]: + """Helper to add a sequence of connected elements. + + Args: + node_pairs (Iterable[tuple[int, int]]): Pairs of node IDs to connect + section (SectionProps): Section properties for the elements + + Returns: + list[int]: Element IDs of created elements + """ + element_ids = [] + for i, j in node_pairs: + element_ids.append( + self.system.add_element( + location=(self.nodes[i], self.nodes[j]), + EA=section["EA"], + EI=section["EI"], + g=section["g"], + spring=None, + ) + ) + return element_ids + + # Element creation per span + self.element_ids = {} + for span, span_node_ids in self.node_ids.items(): + self.element_ids[span] = add_span_elements( + node_pairs=zip(span_node_ids[:-1], span_node_ids[1:]), + section=self.section, + ) + + def add_supports(self) -> None: + """Add supports from self.support_definitions to the SystemElements.""" + for node_id, support_type in self.support_definitions.items(): + if support_type == "fixed": + self.system.add_support_fixed(node_id=node_id) + elif support_type == "pinned": + self.system.add_support_hinged(node_id=node_id) + elif support_type == "roller": + self.system.add_support_roll(node_id=node_id) + + def get_element_ids_of_spans( + self, spans: Optional[Union[int, Sequence[int]]] + ) -> list[int]: + """Get element IDs for a span. + + Args: + span_ids (int, sequence, None): The ID of the span to query. If None, returns + element IDs for all spans. If a sequence, returns IDs for all specified spans. + + Returns: + list[int]: Element IDs of the requested span + + Raises: + KeyError: If span_id does not exist + """ + # Normalize spans to a list + if spans is None: + # Assume all spans by default + spans = list(self.element_ids.keys()) + + elif isinstance(spans, int): + spans = [spans] + + element_ids: list[int] = [] + for span in spans: + if span not in self.element_ids: + available = list(self.element_ids.keys()) + raise KeyError( + f"span number '{span}' not found. " f"Available spans: {available}" + ) + element_ids.extend(self.element_ids[span]) + return element_ids + + def apply_q_load_to_spans( + self, + q: Union[float, Sequence[float]], + direction: Union[LoadDirection, Sequence[LoadDirection]] = "element", + rotation: Optional[Union[float, Sequence[float]]] = None, + q_perp: Optional[Union[float, Sequence[float]]] = None, + spans: Optional[Union[int, Sequence[int]]] = None, + ) -> None: + """Apply distributed load to all elements within one or more spans. + + Args: + q (Union[float, Sequence[float]]): Load magnitude (force/length units) + direction (Union[LoadDirection, Sequence[LoadDirection]]): Load direction. + Options: "element", "x", "y", "parallel", "perpendicular", "angle" + rotation (Optional[Union[float, Sequence[float]]]): Rotation angle in degrees + (used with direction="angle") + q_perp (Optional[Union[float, Sequence[float]]]): Perpendicular load component + chord_segment (Optional[str]): If specified, apply load only to this segment + (for trusses with segmented chords like roof trusses) + """ + element_ids = self.get_element_ids_of_spans(spans=spans) + for el_id in element_ids: + self.system.q_load( + element_id=el_id, + q=q, + direction=direction, + rotation=rotation, + q_perp=q_perp, + ) + + def validate(self) -> bool: + """Validate truss geometry and connectivity. + + Checks for common truss definition issues: + - All node IDs in span lists reference valid nodes + - No duplicate nodes at the same location + - All elements have non-zero length + + Returns: + bool: True if validation passes + + Raises: + ValueError: If validation fails with description of the issue + """ + # Check that all node IDs in connectivity are valid + max_node_id = len(self.nodes) - 1 + + # Validate node ID list + for span, span_node_ids in self.node_ids.items(): + for node_id in span_node_ids: + if node_id < 0 or node_id > max_node_id: + raise ValueError( + f"Span number '{span}' references invalid node ID {node_id}. " + f"Valid range: 0-{max_node_id}" + ) + + # Check for duplicate node locations (within tolerance) + tolerance = 1e-6 + for i, node_i in enumerate(self.nodes): + for j in range(i + 1, len(self.nodes)): + node_j = self.nodes[j] + dx = abs(node_i.x - node_j.x) + dy = abs(node_i.y - node_j.y) + if dx < tolerance and dy < tolerance: + raise ValueError( + f"Duplicate nodes at position ({node_i.x:.6f}, {node_i.y:.6f}): " + f"node {i} and node {j}" + ) + + # Check for zero-length elements + def check_element_length( + node_a_id: int, node_b_id: int, element_type: str + ) -> None: + node_a = self.nodes[node_a_id] + node_b = self.nodes[node_b_id] + dx = node_b.x - node_a.x + dy = node_b.y - node_a.y + length = np.sqrt(dx**2 + dy**2) + if length < tolerance: + raise ValueError( + f"Zero-length element in {element_type}: nodes {node_a_id} and {node_b_id} " + f"at position ({node_a.x:.6f}, {node_a.y:.6f})" + ) + + # Check span elements + for span, span_node_ids in self.node_ids.items(): + for i in range(len(span_node_ids) - 1): + node_a = span_node_ids[i] + node_b = span_node_ids[i + 1] + check_element_length(node_a, node_b, f"span {span}") + return True + + def show_structure(self) -> None: + """Display the truss structure using matplotlib.""" + self.system.show_structure() From 6c02b370b67fcd6662120e294d261e0cef7954f4 Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Thu, 29 Jan 2026 16:20:43 +1100 Subject: [PATCH 02/18] Return important info from system insert_node() --- anastruct/fem/system.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/anastruct/fem/system.py b/anastruct/fem/system.py index 2184693..06df16d 100644 --- a/anastruct/fem/system.py +++ b/anastruct/fem/system.py @@ -646,7 +646,7 @@ def insert_node( element_id: int, location: Optional["VertexLike"] = None, factor: Optional[float] = None, - ) -> None: + ) -> dict[str, int]: """Insert a node into an existing structure. This can be done by adding a new Vertex at any given location, or by setting a factor of the elements length. E.g. if you want a node at 40% of the elements @@ -658,6 +658,13 @@ def insert_node( Defaults to None. factor (Optional[float], optional): Fraction of distance from start to end of elmeent on which to divide the element. Must be between 0 and 1. Defaults to None. + + Returns: + dict[str, int]: Dictionary with keys: + 'new_node_id': ID of the newly created node + 'new_element_id1': ID of the first new element created + 'new_element_id2': ID of the second new element created + 'old_element_id': ID of the old element that was split """ element_id_to_split = _negative_index_to_id(element_id, self.element_map) element_to_split = self.element_map[element_id_to_split] @@ -753,6 +760,13 @@ def insert_node( # Remove the old element from everywhere it's referenced self.remove_element(element_id_to_split) + return { + "new_node_id": self.id_last_node, + "new_element_id1": element_id1, + "new_element_id2": element_id2, + "old_element_id": element_id_to_split, + } + def insert_node_old( self, element_id: int, @@ -2114,12 +2128,14 @@ def get_node_result_range(self, unit: Literal["ux", "uy", "phi_z"]) -> List[floa return [node.phi_z for node in self.node_map.values()] raise NotImplementedError - def find_node_id(self, vertex: Union[Vertex, Sequence[float]]) -> Optional[int]: + def find_node_id( + self, vertex: Union[Vertex, Sequence[float]], tolerance: float = 1e-9 + ) -> Optional[int]: """Find the ID of a certain location. Args: vertex (Union[Vertex, Sequence[float]]): Vertex_xz, [x, y], (x, y) - + tolerance (float): Tolerance for matching existing node locations (length units). Defaults to 1e-9. Raises: TypeError: vertex must be a list, tuple or Vertex @@ -2128,11 +2144,10 @@ def find_node_id(self, vertex: Union[Vertex, Sequence[float]]) -> Optional[int]: """ vertex_v = Vertex(vertex) try: - tol = 1e-9 return next( filter( - lambda x: math.isclose(x.vertex.x, vertex_v.x, abs_tol=tol) - and math.isclose(x.vertex.y, vertex_v.y, abs_tol=tol), + lambda x: math.isclose(x.vertex.x, vertex_v.x, abs_tol=tolerance) + and math.isclose(x.vertex.y, vertex_v.y, abs_tol=tolerance), self.node_map.values(), ) ).id From d02160e7939c5be61b19c09a1b53d1bd47859af0 Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Thu, 29 Jan 2026 16:21:35 +1100 Subject: [PATCH 03/18] Add factory function --- anastruct/preprocess/beam.py | 186 +++++++++++++++++++++++------------ 1 file changed, 124 insertions(+), 62 deletions(-) diff --git a/anastruct/preprocess/beam.py b/anastruct/preprocess/beam.py index 62c124c..5d5e0e0 100644 --- a/anastruct/preprocess/beam.py +++ b/anastruct/preprocess/beam.py @@ -29,6 +29,7 @@ def type(self) -> str: def define_nodes(self) -> None: self.nodes.append(Vertex(0.0, 0.0)) self.nodes.append(Vertex(self.dx * self.length, self.dy * self.length)) + self.node_ids[0] = [0, 1] def define_supports(self) -> None: self.support_definitions[0] = "pinned" @@ -64,6 +65,7 @@ def type(self) -> str: def define_nodes(self) -> None: self.nodes.append(Vertex(0.0, 0.0)) self.nodes.append(Vertex(self.dx * self.length, self.dy * self.length)) + self.node_ids[0] = [0, 1] def define_supports(self) -> None: self.support_definitions[1 if self.cantilever_side == "left" else 0] = "fixed" @@ -153,7 +155,7 @@ def type(self) -> str: def define_nodes(self) -> None: current_length = 0.0 self.nodes.append(Vertex(0.0, 0.0)) - for span in self.span_lengths: + for i, span in enumerate(self.span_lengths): current_length += span self.nodes.append( Vertex( @@ -161,6 +163,7 @@ def define_nodes(self) -> None: self.dy * current_length, ) ) + self.node_ids[i] = [i, i + 1] def define_supports(self) -> None: first_support = 0 if self.cantilevers in [None, "right"] else 1 @@ -237,6 +240,85 @@ def type(self) -> str: return "Four-Span Beam" +class ProppedBeam(MultiSpanBeam): + """Propped beam with an interior simple span and a cantilever on one side.""" + + def __init__( + self, + interior_length: float, + cantilever_length: float, + cantilever_side: Literal["left", "right"] = "right", + angle: float = 0.0, + section: Optional[SectionProps] = None, + ) -> None: + if cantilever_side.lower() == "left": + span_lengths = [cantilever_length, interior_length] + elif cantilever_side.lower() == "right": + span_lengths = [interior_length, cantilever_length] + else: + raise ValueError( + "cantilever_side must be either 'left' or 'right', " + f"got '{cantilever_side}'" + ) + super().__init__( + span_lengths=span_lengths, + cantilevers=cantilever_side, + angle=angle, + section=section, + ) + self.cantilever_side = cantilever_side.lower() + + @property + def type(self) -> str: + return "Propped Beam" + + +class RightProppedBeam(ProppedBeam): + """Propped beam with an interior simple span and a cantilever on the right side.""" + + def __init__( + self, + interior_length: float, + cantilever_length: float, + angle: float = 0.0, + section: Optional[SectionProps] = None, + ) -> None: + super().__init__( + interior_length=interior_length, + cantilever_length=cantilever_length, + cantilever_side="right", + angle=angle, + section=section, + ) + + @property + def type(self) -> str: + return "Right Propped Beam" + + +class LeftProppedBeam(ProppedBeam): + """Propped beam with an interior simple span and a cantilever on the left side.""" + + def __init__( + self, + interior_length: float, + cantilever_length: float, + angle: float = 0.0, + section: Optional[SectionProps] = None, + ) -> None: + super().__init__( + interior_length=interior_length, + cantilever_length=cantilever_length, + cantilever_side="left", + angle=angle, + section=section, + ) + + @property + def type(self) -> str: + return "Left Propped Beam" + + def create_beam(beam_type: str, **kwargs: Any) -> Beam: """Factory function to create beam instances by type name. @@ -244,81 +326,61 @@ def create_beam(beam_type: str, **kwargs: Any) -> Beam: Type names are case-insensitive and can use underscores or hyphens as separators. Args: - truss_type (str): Name of the truss type. Supported types: - Flat trusses: "howe", "pratt", "warren" - Roof trusses: "king_post", "queen_post", "fink", "howe_roof", "pratt_roof", - "fan", "modified_queen_post", "double_fink", "double_howe", - "modified_fan", "attic" - **kwargs: Arguments to pass to the truss constructor + beam_type (str): The type of beam to create (e.g., "simple", "cantilever", "multi_span") + **kwargs: Arguments to pass to the beam constructor Returns: - Truss: An instance of the requested truss type + Beam: An instance of the requested beam type Raises: - ValueError: If truss_type is not recognized + ValueError: If beam_type is not recognized Examples: - >>> truss = create_truss("howe", width=20, height=2.5, unit_width=2.0) - >>> truss = create_truss("king-post", width=10, roof_pitch_deg=30) + >>> beam = create_beam("simple", length=10, section=section) + >>> beam = create_beam("cantilever", length=5, section=section) """ - # Normalize the truss type name - normalized = truss_type.lower().replace("-", "_").replace(" ", "_") + # Normalize the beam type name + normalized = beam_type.lower().replace("-", "_").replace(" ", "_") # Map of normalized names to classes - truss_map = { - # Flat trusses - "howe": HoweFlatTruss, - "howe_flat": HoweFlatTruss, - "pratt": PrattFlatTruss, - "pratt_flat": PrattFlatTruss, - "warren": WarrenFlatTruss, - "warren_flat": WarrenFlatTruss, - # Roof trusses - "king_post": KingPostRoofTruss, - "kingpost": KingPostRoofTruss, - "queen_post": QueenPostRoofTruss, - "queenpost": QueenPostRoofTruss, - "fink": FinkRoofTruss, - "howe_roof": HoweRoofTruss, - "pratt_roof": PrattRoofTruss, - "fan": FanRoofTruss, - "modified_queen_post": ModifiedQueenPostRoofTruss, - "modified_queenpost": ModifiedQueenPostRoofTruss, - "double_fink": DoubleFinkRoofTruss, - "doublefink": DoubleFinkRoofTruss, - "double_howe": DoubleHoweRoofTruss, - "doublehowe": DoubleHoweRoofTruss, - "modified_fan": ModifiedFanRoofTruss, - "modifiedfan": ModifiedFanRoofTruss, - "attic": AtticRoofTruss, - "attic_roof": AtticRoofTruss, + beam_map = { + # Single-span beams + "simple": SimpleBeam, + "cantilever": CantileverBeam, + "right_cantilever": RightCantileverBeam, + "left_cantilever": LeftCantileverBeam, + # Multi-span beams + "multispan": MultiSpanBeam, + "multi_span": MultiSpanBeam, + "two_span": TwoSpanBeam, + "three_span": ThreeSpanBeam, + "four_span": FourSpanBeam, + "propped": ProppedBeam, + "right_propped": RightProppedBeam, + "left_propped": LeftProppedBeam, } - - if normalized not in truss_map: - available = sorted(set(truss_map.keys())) + if normalized not in beam_map: + available = sorted(set(beam_map.keys())) raise ValueError( - f"Unknown truss type '{truss_type}'. Available types: {', '.join(available)}" + f"Unknown beam type '{beam_type}'. Available types: {', '.join(available)}" ) - truss_class = truss_map[normalized] - assert issubclass(truss_class, Truss) - return truss_class(**kwargs) + beam_class = beam_map[normalized] + assert issubclass(beam_class, Beam) + return beam_class(**kwargs) __all__ = [ - "HoweFlatTruss", - "PrattFlatTruss", - "WarrenFlatTruss", - "KingPostRoofTruss", - "QueenPostRoofTruss", - "FinkRoofTruss", - "HoweRoofTruss", - "PrattRoofTruss", - "FanRoofTruss", - "ModifiedQueenPostRoofTruss", - "DoubleFinkRoofTruss", - "DoubleHoweRoofTruss", - "ModifiedFanRoofTruss", - "AtticRoofTruss", - "create_truss", + "SimpleBeam", + "CantileverBeam", + "RightCantileverBeam", + "LeftCantileverBeam", + "MultiSpanBeam", + "TwoSpanBeam", + "ThreeSpanBeam", + "FourSpanBeam", + "ProppedBeam", + "RightProppedBeam", + "LeftProppedBeam", + "create_beam", ] From 8f6ab68886fad835a5f1c31aceca1314c9d6c04e Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Thu, 29 Jan 2026 16:21:51 +1100 Subject: [PATCH 04/18] Handle point loads on spans --- anastruct/preprocess/beam_class.py | 103 ++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 3 deletions(-) diff --git a/anastruct/preprocess/beam_class.py b/anastruct/preprocess/beam_class.py index 5906bb0..4b5293a 100644 --- a/anastruct/preprocess/beam_class.py +++ b/anastruct/preprocess/beam_class.py @@ -126,15 +126,15 @@ def define_nodes(self) -> None: """Generate node coordinates and populate self.nodes list. Must be implemented by subclasses. Should create Vertex objects - representing all node locations in the beam. + representing all node locations in the beam. Should also populate + self.node_ids dictionary mapping spanwise node indices to global node IDs. """ @abstractmethod def define_supports(self) -> None: """Define support locations and types by populating self.support_definitions. - Must be implemented by subclasses. Should also populate - self.node_ids dictionary mapping spanwise node indices to global node IDs. + Must be implemented by subclasses. """ def add_nodes(self) -> None: @@ -255,6 +255,103 @@ def apply_q_load_to_spans( q_perp=q_perp, ) + def apply_point_load_to_spans( + self, + Fx: Union[float, Sequence[float]] = 0.0, + Fy: Union[float, Sequence[float]] = 0.0, + rotation: Union[float, Sequence[float]] = 0.0, + absolute_location: Optional[float] = None, + relative_location: Optional[float] = None, + spans: Optional[Union[int, Sequence[int]]] = None, + tolerance: Optional[float] = None, + ) -> None: + """Apply point load to elements within one or more spans. + + Args: + Fx (Union[float, Sequence[float]]): Horizontal load component (force units) + Fy (Union[float, Sequence[float]]): Vertical load component (force units) + rotation (Union[float, Sequence[float]]): Rotation angle in degrees + absolute_location (Optional[float]): Absolute location along the beam length (length units). + Either absolute_location or relative_location must be provided. + relative_location (Optional[float]): Relative location along the beam length + (0.0 = start of span, 1.0 = end of span). Either absolute_location or + relative_location must be provided. + spans (Optional[Union[int, Sequence[int]]]): Span(s) to apply the load to. If None, + applies to all spans. + tolerance (float): Tolerance for matching existing node locations (length units). Defaults to beam length * 1e-4. + """ + if spans is None: + spans = list(self.element_ids.keys()) + elif isinstance(spans, int): + spans = [spans] + + if absolute_location is None and relative_location is None: + raise ValueError( + "Either absolute_location or relative_location must be provided." + ) + if absolute_location is not None and relative_location is not None: + raise ValueError( + "Only one of absolute_location or relative_location may be provided." + ) + + if tolerance is None: + tolerance = self.length * 1e-4 + + for span in spans: + span_node_ids = self.node_ids[span] + span_start = self.nodes[span_node_ids[0]] + span_end = self.nodes[span_node_ids[-1]] + span_length = np.sqrt( + (span_end.x - span_start.x) ** 2 + (span_end.y - span_start.y) ** 2 + ) + + if relative_location is not None: + # Check if location is within this span + if relative_location < 0 or relative_location > 1.0: + continue + # Compute absolute location within the span + absolute_location = relative_location * span_length + assert absolute_location is not None + # Compute load location + load_x = span_start.x + self.dx * absolute_location + load_y = span_start.y + self.dy * absolute_location + + # Determine if a node already exists at (or very near to) the load location + node_id = self.system.find_node_id( + vertex=Vertex(load_x, load_y), tolerance=tolerance + ) + + # If no existing node, insert a new node into the appropriate element + if node_id is None: + # Identify the element to insert the node into + elem_start = 0.0 + for i, elem_id in enumerate(self.element_ids[span]): + elem_start_v = self.system.element_map[elem_id].vertex_1 + elem_end_v = self.system.element_map[elem_id].vertex_2 + elem_length = np.sqrt( + (elem_end_v.x - elem_start_v.x) ** 2 + + (elem_end_v.y - elem_start_v.y) ** 2 + ) + elem_end = elem_start + elem_length + + if elem_start <= absolute_location <= elem_end: + # Insert node into this element + result = self.system.insert_node( + element_id=elem_id, location=Vertex(load_x, load_y) + ) + + # Update our internal node and element lists + self.node_ids[span].insert(i + 1, result["new_node_id"]) + self.element_ids[span].remove(elem_id) + self.element_ids[span].insert(i, result["new_element_id1"]) + self.element_ids[span].insert(i + 1, result["new_element_id2"]) + node_id = result["new_node_id"] + break + + # Apply point load at the identified or newly created node + assert node_id is not None + self.system.point_load(node_id=node_id, Fx=Fx, Fy=Fy, rotation=rotation) + def validate(self) -> bool: """Validate truss geometry and connectivity. From 2ab666b3d50dd40fb489078a213d02bb2bf67b1c Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Wed, 4 Feb 2026 15:28:27 +1100 Subject: [PATCH 05/18] Misc bug fixes --- anastruct/preprocess/beam.py | 40 +++++++++++--------- anastruct/preprocess/beam_class.py | 59 +++++++++++++++++------------- 2 files changed, 57 insertions(+), 42 deletions(-) diff --git a/anastruct/preprocess/beam.py b/anastruct/preprocess/beam.py index 5d5e0e0..7e898ca 100644 --- a/anastruct/preprocess/beam.py +++ b/anastruct/preprocess/beam.py @@ -37,7 +37,12 @@ def define_supports(self) -> None: class CantileverBeam(Beam): - """Cantilever beam with a fixed support at one end, and free at the other.""" + """Cantilever beam with a fixed support at one end and free at the other. + + The ``cantilever_side`` parameter specifies which end is the free (unsupported) + end. For example, ``cantilever_side="right"`` means the right end is free and + the left end is fixed. + """ def __init__( self, @@ -46,17 +51,17 @@ def __init__( angle: float = 0.0, section: Optional[SectionProps] = None, ) -> None: - super().__init__( - length=length, - angle=angle, - section=section, - ) self.cantilever_side = cantilever_side.lower() if self.cantilever_side not in ["left", "right"]: raise ValueError( "cantilever_side must be either 'left' or 'right', " f"got '{cantilever_side}'" ) + super().__init__( + length=length, + angle=angle, + section=section, + ) @property def type(self) -> str: @@ -72,7 +77,7 @@ def define_supports(self) -> None: class RightCantileverBeam(CantileverBeam): - """Cantilever beam with a fixed support at the left end, and free at the right.""" + """Cantilever beam with a fixed support at the left end and free (cantilevered) at the right.""" def __init__( self, @@ -93,7 +98,7 @@ def type(self) -> str: class LeftCantileverBeam(CantileverBeam): - """Cantilever beam with a free support at the left end, and fixed at the right.""" + """Cantilever beam with a free (cantilevered) left end and a fixed support at the right.""" def __init__( self, @@ -131,22 +136,23 @@ def __init__( raise ValueError("Only one of num_spans or span_lengths may be provided.") if num_spans is not None and length is None: raise ValueError("If num_spans is provided, length must also be provided.") + if cantilevers not in [None, "left", "right", "both"]: + raise ValueError( + "cantilevers must be either None, 'left', 'right', or 'both', " + f"got '{cantilevers}'" + ) if num_spans is not None and length is not None: span_lengths = [length / num_spans] * num_spans + # Set attributes needed by define_supports() before super().__init__() + self.num_spans = num_spans + self.cantilevers = cantilevers + super().__init__( - length=sum(span_lengths) if span_lengths else num_spans, span_lengths=span_lengths, angle=angle, section=section, ) - self.num_spans = num_spans - if cantilevers not in [None, "left", "right", "both"]: - raise ValueError( - "cantilevers must be either None, 'left', 'right', or 'both', " - f"got '{cantilevers}'" - ) - self.cantilevers = cantilevers @property def type(self) -> str: @@ -173,7 +179,7 @@ def define_supports(self) -> None: else len(self.span_lengths) - 1 ) self.support_definitions[first_support] = "pinned" - for i in range(first_support + 1, last_support): + for i in range(first_support + 1, last_support + 1): self.support_definitions[i] = "roller" diff --git a/anastruct/preprocess/beam_class.py b/anastruct/preprocess/beam_class.py index 4b5293a..265bfb2 100644 --- a/anastruct/preprocess/beam_class.py +++ b/anastruct/preprocess/beam_class.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import Iterable, Literal, Optional, Sequence, Union, overload +from typing import Iterable, Literal, Optional, Sequence, Union import numpy as np @@ -22,14 +22,13 @@ class Beam(ABC): node generation, connectivity, and support definitions. Subclasses implement specific beam types (simple, cantilever, etc.). - The beam generation follows a three-phase process: - 1. define_nodes() - Generate node coordinates - 2. define_connectivity() - Define which nodes connect to form elements - 3. define_supports() - Define support locations and types + The beam generation follows a two-phase process: + 1. define_nodes() - Generate node coordinates and span connectivity + 2. define_supports() - Define support locations and types Attributes: length (float): Total length of the beam (length units) - angle (float): Angle of the beam (degrees; 0 = horizontal, positive = CCW); defauts to 0.0 + angle (float): Angle of the beam (degrees; 0 = horizontal, positive = CCW); defaults to 0.0 section (SectionProps): Section properties for all beam elements; defaults to DEFAULT_BEAM_SECTION supports_type (Literal["simple", "pinned", "fixed"]): Type of supports to apply; defaults to "simple" system (SystemElements): The FEM system containing all nodes, elements, and supports; initialized after adding elements @@ -61,16 +60,21 @@ def __init__( angle: float = 0.0, section: Optional[SectionProps] = None, ): - """Initialize a truss structure. + """Initialize a beam structure. Args: - length (float): Total length of the beam (length units). Must be positive. Either length or span_lengths must be provided. - span_lengths (list[float]): List of span lengths for each span. Must be positive. Either length or span_lengths must be provided. - angle (float): Angle of the truss (degrees; 0 = horizontal, positive = CCW); defaults to 0.0 - section (SectionProps): Section properties for all beam elements; defaults to DEFAULT_BEAM_SECTION + length (float): Total length of the beam (length units). Must be positive. + Either length or span_lengths must be provided. + span_lengths (list[float]): List of span lengths for each span. Must be + positive. Either length or span_lengths must be provided. + angle (float): Angle of the beam (degrees; 0 = horizontal, positive = CCW); + defaults to 0.0 + section (SectionProps): Section properties for all beam elements; defaults + to DEFAULT_BEAM_SECTION Raises: - ValueError: If width or height is not positive. + ValueError: If length or span_lengths are not positive, or if neither + (or both) are provided. """ if length is None and span_lengths is None: raise ValueError("Either length or span_lengths must be provided.") @@ -89,9 +93,13 @@ def __init__( self.length = length self.span_lengths = [length] - if angle > -np.pi / 2 and angle < np.pi / 2: - print( - f"Warning: A very small angle was provided ({angle}). Please ensure input units are degrees." + if angle != 0.0 and -2 * np.pi <= angle <= 2 * np.pi: + import warnings + + warnings.warn( + f"A very small angle was provided ({angle}). " + f"Please ensure input units are degrees, not radians.", + stacklevel=2, ) if angle < 0 or angle >= 360: angle = angle % 360 @@ -242,8 +250,6 @@ def apply_q_load_to_spans( rotation (Optional[Union[float, Sequence[float]]]): Rotation angle in degrees (used with direction="angle") q_perp (Optional[Union[float, Sequence[float]]]): Perpendicular load component - chord_segment (Optional[str]): If specified, apply load only to this segment - (for trusses with segmented chords like roof trusses) """ element_ids = self.get_element_ids_of_spans(spans=spans) for el_id in element_ids: @@ -310,11 +316,14 @@ def apply_point_load_to_spans( if relative_location < 0 or relative_location > 1.0: continue # Compute absolute location within the span - absolute_location = relative_location * span_length - assert absolute_location is not None + span_abs_location = relative_location * span_length + else: + assert absolute_location is not None + span_abs_location = absolute_location + # Compute load location - load_x = span_start.x + self.dx * absolute_location - load_y = span_start.y + self.dy * absolute_location + load_x = span_start.x + self.dx * span_abs_location + load_y = span_start.y + self.dy * span_abs_location # Determine if a node already exists at (or very near to) the load location node_id = self.system.find_node_id( @@ -334,7 +343,7 @@ def apply_point_load_to_spans( ) elem_end = elem_start + elem_length - if elem_start <= absolute_location <= elem_end: + if elem_start <= span_abs_location <= elem_end: # Insert node into this element result = self.system.insert_node( element_id=elem_id, location=Vertex(load_x, load_y) @@ -353,9 +362,9 @@ def apply_point_load_to_spans( self.system.point_load(node_id=node_id, Fx=Fx, Fy=Fy, rotation=rotation) def validate(self) -> bool: - """Validate truss geometry and connectivity. + """Validate beam geometry and connectivity. - Checks for common truss definition issues: + Checks for common beam definition issues: - All node IDs in span lists reference valid nodes - No duplicate nodes at the same location - All elements have non-zero length @@ -415,5 +424,5 @@ def check_element_length( return True def show_structure(self) -> None: - """Display the truss structure using matplotlib.""" + """Display the beam structure using matplotlib.""" self.system.show_structure() From 949602ec4ceb10a795b003f592b141dd3f389810 Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Wed, 4 Feb 2026 16:09:35 +1100 Subject: [PATCH 06/18] Change to 1-based node indexing, to match with SystemElements... --- anastruct/preprocess/beam.py | 18 +- anastruct/preprocess/beam_class.py | 18 +- anastruct/preprocess/truss.py | 284 ++++++++++++++-------------- anastruct/preprocess/truss_class.py | 40 ++-- 4 files changed, 180 insertions(+), 180 deletions(-) diff --git a/anastruct/preprocess/beam.py b/anastruct/preprocess/beam.py index 7e898ca..0fdc77a 100644 --- a/anastruct/preprocess/beam.py +++ b/anastruct/preprocess/beam.py @@ -29,11 +29,11 @@ def type(self) -> str: def define_nodes(self) -> None: self.nodes.append(Vertex(0.0, 0.0)) self.nodes.append(Vertex(self.dx * self.length, self.dy * self.length)) - self.node_ids[0] = [0, 1] + self.node_ids[0] = [1, 2] def define_supports(self) -> None: - self.support_definitions[0] = "pinned" - self.support_definitions[1] = "roller" + self.support_definitions[1] = "pinned" + self.support_definitions[2] = "roller" class CantileverBeam(Beam): @@ -70,10 +70,10 @@ def type(self) -> str: def define_nodes(self) -> None: self.nodes.append(Vertex(0.0, 0.0)) self.nodes.append(Vertex(self.dx * self.length, self.dy * self.length)) - self.node_ids[0] = [0, 1] + self.node_ids[0] = [1, 2] def define_supports(self) -> None: - self.support_definitions[1 if self.cantilever_side == "left" else 0] = "fixed" + self.support_definitions[2 if self.cantilever_side == "left" else 1] = "fixed" class RightCantileverBeam(CantileverBeam): @@ -169,14 +169,14 @@ def define_nodes(self) -> None: self.dy * current_length, ) ) - self.node_ids[i] = [i, i + 1] + self.node_ids[i] = [i + 1, i + 2] def define_supports(self) -> None: - first_support = 0 if self.cantilevers in [None, "right"] else 1 + first_support = 1 if self.cantilevers in [None, "right"] else 2 last_support = ( - len(self.span_lengths) + len(self.span_lengths) + 1 if self.cantilevers in [None, "left"] - else len(self.span_lengths) - 1 + else len(self.span_lengths) ) self.support_definitions[first_support] = "pinned" for i in range(first_support + 1, last_support + 1): diff --git a/anastruct/preprocess/beam_class.py b/anastruct/preprocess/beam_class.py index 265bfb2..bfb5c82 100644 --- a/anastruct/preprocess/beam_class.py +++ b/anastruct/preprocess/beam_class.py @@ -148,7 +148,7 @@ def define_supports(self) -> None: def add_nodes(self) -> None: """Add all nodes from self.nodes to the SystemElements.""" for i, vertex in enumerate(self.nodes): - add_node(self.system, point=vertex, node_id=i) + add_node(self.system, point=vertex, node_id=i + 1) def add_elements(self) -> None: """Create elements from connectivity definitions and add to SystemElements. @@ -173,7 +173,7 @@ def add_span_elements( for i, j in node_pairs: element_ids.append( self.system.add_element( - location=(self.nodes[i], self.nodes[j]), + location=(self.nodes[i - 1], self.nodes[j - 1]), EA=section["EA"], EI=section["EI"], g=section["g"], @@ -305,8 +305,8 @@ def apply_point_load_to_spans( for span in spans: span_node_ids = self.node_ids[span] - span_start = self.nodes[span_node_ids[0]] - span_end = self.nodes[span_node_ids[-1]] + span_start = self.nodes[span_node_ids[0] - 1] + span_end = self.nodes[span_node_ids[-1] - 1] span_length = np.sqrt( (span_end.x - span_start.x) ** 2 + (span_end.y - span_start.y) ** 2 ) @@ -376,15 +376,15 @@ def validate(self) -> bool: ValueError: If validation fails with description of the issue """ # Check that all node IDs in connectivity are valid - max_node_id = len(self.nodes) - 1 + max_node_id = len(self.nodes) # Validate node ID list for span, span_node_ids in self.node_ids.items(): for node_id in span_node_ids: - if node_id < 0 or node_id > max_node_id: + if node_id < 1 or node_id > max_node_id: raise ValueError( f"Span number '{span}' references invalid node ID {node_id}. " - f"Valid range: 0-{max_node_id}" + f"Valid range: 1-{max_node_id}" ) # Check for duplicate node locations (within tolerance) @@ -404,8 +404,8 @@ def validate(self) -> bool: def check_element_length( node_a_id: int, node_b_id: int, element_type: str ) -> None: - node_a = self.nodes[node_a_id] - node_b = self.nodes[node_b_id] + node_a = self.nodes[node_a_id - 1] + node_b = self.nodes[node_b_id - 1] dx = node_b.x - node_a.x dy = node_b.y - node_a.y length = np.sqrt(dx**2 + dy**2) diff --git a/anastruct/preprocess/truss.py b/anastruct/preprocess/truss.py index 41e93f0..f7bb245 100644 --- a/anastruct/preprocess/truss.py +++ b/anastruct/preprocess/truss.py @@ -47,11 +47,11 @@ def define_connectivity(self) -> None: ) # Bottom chord connectivity - self.bottom_chord_node_ids = list(range(0, n_bottom_nodes)) + self.bottom_chord_node_ids = list(range(1, n_bottom_nodes + 1)) # Top chord connectivity self.top_chord_node_ids = list( - range(n_bottom_nodes, n_bottom_nodes + n_top_nodes) + range(n_bottom_nodes + 1, n_bottom_nodes + n_top_nodes + 1) ) # Web diagonals connectivity @@ -61,9 +61,9 @@ def define_connectivity(self) -> None: end_top = None if self.end_type == "triangle_up": # special case: end diagonal slopes in the opposite direction - self.web_node_pairs.append((0, n_bottom_nodes)) + self.web_node_pairs.append((1, n_bottom_nodes + 1)) self.web_node_pairs.append( - (n_bottom_nodes - 1, n_bottom_nodes + n_top_nodes - 1) + (n_bottom_nodes, n_bottom_nodes + n_top_nodes) ) start_top = 2 end_top = -3 @@ -141,11 +141,11 @@ def define_connectivity(self) -> None: ) # Bottom chord connectivity - self.bottom_chord_node_ids = list(range(0, n_bottom_nodes)) + self.bottom_chord_node_ids = list(range(1, n_bottom_nodes + 1)) # Top chord connectivity self.top_chord_node_ids = list( - range(n_bottom_nodes, n_bottom_nodes + n_top_nodes) + range(n_bottom_nodes + 1, n_bottom_nodes + n_top_nodes + 1) ) # Web diagonals connectivity @@ -155,9 +155,9 @@ def define_connectivity(self) -> None: end_top = None if self.end_type == "triangle_down": # special case: end diagonal slopes in the opposite direction - self.web_node_pairs.append((n_bottom_nodes, 0)) + self.web_node_pairs.append((n_bottom_nodes + 1, 1)) self.web_node_pairs.append( - (n_bottom_nodes + n_top_nodes - 1, n_bottom_nodes - 1) + (n_bottom_nodes + n_top_nodes, n_bottom_nodes) ) start_bot = 2 end_bot = -3 @@ -293,11 +293,11 @@ def define_connectivity(self) -> None: n_top_nodes = int(self.n_units) + (1 if self.end_type == "triangle_up" else 0) # Bottom chord connectivity - self.bottom_chord_node_ids = list(range(0, n_bottom_nodes)) + self.bottom_chord_node_ids = list(range(1, n_bottom_nodes + 1)) # Top chord connectivity self.top_chord_node_ids = list( - range(n_bottom_nodes, n_bottom_nodes + n_top_nodes) + range(n_bottom_nodes + 1, n_bottom_nodes + n_top_nodes + 1) ) # Web diagonals connectivity @@ -354,18 +354,18 @@ def define_nodes(self) -> None: def define_connectivity(self) -> None: # Bottom chord connectivity - self.bottom_chord_node_ids = [0, 1, 2] - left_v = 0 - right_v = 2 + self.bottom_chord_node_ids = [1, 2, 3] + left_v = 1 + right_v = 3 # Top chord connectivity (left and right slopes stored separately) - self.top_chord_node_ids = {"left": [left_v, 3], "right": [3, right_v]} + self.top_chord_node_ids = {"left": [left_v, 4], "right": [4, right_v]} if self.overhang_length > 0: - self.top_chord_node_ids["left"].insert(0, 4) # left overhang - self.top_chord_node_ids["right"].append(5) # right overhang + self.top_chord_node_ids["left"].insert(0, 5) # left overhang + self.top_chord_node_ids["right"].append(6) # right overhang # Web verticals connectivity - self.web_verticals_node_pairs.append((1, 3)) # center vertical + self.web_verticals_node_pairs.append((2, 4)) # center vertical class QueenPostRoofTruss(RoofTruss): @@ -408,27 +408,27 @@ def define_nodes(self) -> None: def define_connectivity(self) -> None: # Bottom chord connectivity - self.bottom_chord_node_ids = [0, 1, 2] - left_v = 0 - right_v = 2 + self.bottom_chord_node_ids = [1, 2, 3] + left_v = 1 + right_v = 3 # Top chord connectivity (left and right slopes stored separately) - self.top_chord_node_ids = {"left": [left_v, 3, 4], "right": [4, 5, right_v]} + self.top_chord_node_ids = {"left": [left_v, 4, 5], "right": [5, 6, right_v]} if self.overhang_length > 0: - self.top_chord_node_ids["left"].insert(0, 6) # left overhang - self.top_chord_node_ids["right"].append(7) # right overhang + self.top_chord_node_ids["left"].insert(0, 7) # left overhang + self.top_chord_node_ids["right"].append(8) # right overhang # Web diagonals connectivity self.web_node_pairs.append( - (1, 3) + (2, 4) ) # left diagonal from center bottom to left quarter top self.web_node_pairs.append( - (1, 5) + (2, 6) ) # right diagonal from center bottom to right quarter top - # Web verticals connectivity - Fixed: should connect to peak (node 4), not node 3 + # Web verticals connectivity - Fixed: should connect to peak (node 5), not node 4 self.web_verticals_node_pairs.append( - (1, 4) + (2, 5) ) # center vertical from center bottom to peak @@ -473,21 +473,21 @@ def define_nodes(self) -> None: def define_connectivity(self) -> None: # Bottom chord connectivity - self.bottom_chord_node_ids = [0, 1, 2, 3] - left_v = 0 - right_v = 3 + self.bottom_chord_node_ids = [1, 2, 3, 4] + left_v = 1 + right_v = 4 # Top chord connectivity (left and right slopes stored separately) - self.top_chord_node_ids = {"left": [left_v, 4, 5], "right": [5, 6, right_v]} + self.top_chord_node_ids = {"left": [left_v, 5, 6], "right": [6, 7, right_v]} if self.overhang_length > 0: - self.top_chord_node_ids["left"].insert(0, 7) # left overhang - self.top_chord_node_ids["right"].append(8) # right overhang + self.top_chord_node_ids["left"].insert(0, 8) # left overhang + self.top_chord_node_ids["right"].append(9) # right overhang # Web diagonals connectivity - self.web_node_pairs.append((1, 4)) - self.web_node_pairs.append((1, 5)) self.web_node_pairs.append((2, 5)) self.web_node_pairs.append((2, 6)) + self.web_node_pairs.append((3, 6)) + self.web_node_pairs.append((3, 7)) class HoweRoofTruss(RoofTruss): @@ -532,24 +532,24 @@ def define_nodes(self) -> None: def define_connectivity(self) -> None: # Bottom chord connectivity - self.bottom_chord_node_ids = [0, 1, 2, 3, 4] - left_v = 0 - right_v = 4 + self.bottom_chord_node_ids = [1, 2, 3, 4, 5] + left_v = 1 + right_v = 5 # Top chord connectivity (left and right slopes stored separately) - self.top_chord_node_ids = {"left": [left_v, 5, 6], "right": [6, 7, right_v]} + self.top_chord_node_ids = {"left": [left_v, 6, 7], "right": [7, 8, right_v]} if self.overhang_length > 0: - self.top_chord_node_ids["left"].insert(0, 8) # left overhang - self.top_chord_node_ids["right"].append(9) # right overhang + self.top_chord_node_ids["left"].insert(0, 9) # left overhang + self.top_chord_node_ids["right"].append(10) # right overhang # Web diagonals connectivity - self.web_node_pairs.append((2, 5)) # left diagonal - self.web_node_pairs.append((2, 7)) # right diagonal + self.web_node_pairs.append((3, 6)) # left diagonal + self.web_node_pairs.append((3, 8)) # right diagonal # Web verticals connectivity - self.web_verticals_node_pairs.append((1, 5)) # left vertical - self.web_verticals_node_pairs.append((2, 6)) # centre vertical - self.web_verticals_node_pairs.append((3, 7)) # right vertical + self.web_verticals_node_pairs.append((2, 6)) # left vertical + self.web_verticals_node_pairs.append((3, 7)) # centre vertical + self.web_verticals_node_pairs.append((4, 8)) # right vertical class PrattRoofTruss(RoofTruss): @@ -594,24 +594,24 @@ def define_nodes(self) -> None: def define_connectivity(self) -> None: # Bottom chord connectivity - self.bottom_chord_node_ids = [0, 1, 2, 3, 4] - left_v = 0 - right_v = 4 + self.bottom_chord_node_ids = [1, 2, 3, 4, 5] + left_v = 1 + right_v = 5 # Top chord connectivity (left and right slopes stored separately) - self.top_chord_node_ids = {"left": [left_v, 5, 6], "right": [6, 7, right_v]} + self.top_chord_node_ids = {"left": [left_v, 6, 7], "right": [7, 8, right_v]} if self.overhang_length > 0: - self.top_chord_node_ids["left"].insert(0, 8) # left overhang - self.top_chord_node_ids["right"].append(9) # right overhang + self.top_chord_node_ids["left"].insert(0, 9) # left overhang + self.top_chord_node_ids["right"].append(10) # right overhang # Web diagonals connectivity - self.web_node_pairs.append((1, 6)) # left diagonal - self.web_node_pairs.append((3, 6)) # right diagonal + self.web_node_pairs.append((2, 7)) # left diagonal + self.web_node_pairs.append((4, 7)) # right diagonal # Web verticals connectivity - self.web_verticals_node_pairs.append((1, 5)) # left vertical - self.web_verticals_node_pairs.append((2, 6)) # centre vertical - self.web_verticals_node_pairs.append((3, 7)) # right vertical + self.web_verticals_node_pairs.append((2, 6)) # left vertical + self.web_verticals_node_pairs.append((3, 7)) # centre vertical + self.web_verticals_node_pairs.append((4, 8)) # right vertical class FanRoofTruss(RoofTruss): @@ -657,28 +657,28 @@ def define_nodes(self) -> None: def define_connectivity(self) -> None: # Bottom chord connectivity - self.bottom_chord_node_ids = [0, 1, 2, 3] - left_v = 0 - right_v = 3 + self.bottom_chord_node_ids = [1, 2, 3, 4] + left_v = 1 + right_v = 4 # Top chord connectivity (left and right slopes stored separately) self.top_chord_node_ids = { - "left": [left_v, 4, 5, 6], - "right": [6, 7, 8, right_v], + "left": [left_v, 5, 6, 7], + "right": [7, 8, 9, right_v], } if self.overhang_length > 0: - self.top_chord_node_ids["left"].insert(0, 9) # left overhang - self.top_chord_node_ids["right"].append(10) # right overhang + self.top_chord_node_ids["left"].insert(0, 10) # left overhang + self.top_chord_node_ids["right"].append(11) # right overhang # Web diagonals connectivity - self.web_node_pairs.append((1, 4)) - self.web_node_pairs.append((1, 6)) - self.web_node_pairs.append((2, 6)) - self.web_node_pairs.append((2, 8)) + self.web_node_pairs.append((2, 5)) + self.web_node_pairs.append((2, 7)) + self.web_node_pairs.append((3, 7)) + self.web_node_pairs.append((3, 9)) # Web verticals connectivity - self.web_verticals_node_pairs.append((1, 5)) - self.web_verticals_node_pairs.append((2, 7)) + self.web_verticals_node_pairs.append((2, 6)) + self.web_verticals_node_pairs.append((3, 8)) class ModifiedQueenPostRoofTruss(RoofTruss): @@ -725,29 +725,29 @@ def define_nodes(self) -> None: def define_connectivity(self) -> None: # Bottom chord connectivity - self.bottom_chord_node_ids = [0, 1, 2, 3, 4] - left_v = 0 - right_v = 4 + self.bottom_chord_node_ids = [1, 2, 3, 4, 5] + left_v = 1 + right_v = 5 # Top chord connectivity (left and right slopes stored separately) self.top_chord_node_ids = { - "left": [left_v, 5, 6, 7], - "right": [7, 8, 9, right_v], + "left": [left_v, 6, 7, 8], + "right": [8, 9, 10, right_v], } if self.overhang_length > 0: - self.top_chord_node_ids["left"].insert(0, 10) # left overhang - self.top_chord_node_ids["right"].append(11) # right overhang + self.top_chord_node_ids["left"].insert(0, 11) # left overhang + self.top_chord_node_ids["right"].append(12) # right overhang # Web diagonals connectivity - self.web_node_pairs.append((1, 5)) - self.web_node_pairs.append((1, 6)) self.web_node_pairs.append((2, 6)) - self.web_node_pairs.append((2, 8)) - self.web_node_pairs.append((3, 8)) + self.web_node_pairs.append((2, 7)) + self.web_node_pairs.append((3, 7)) self.web_node_pairs.append((3, 9)) + self.web_node_pairs.append((4, 9)) + self.web_node_pairs.append((4, 10)) # Web verticals connectivity - self.web_verticals_node_pairs.append((2, 7)) # center vertical + self.web_verticals_node_pairs.append((3, 8)) # center vertical class DoubleFinkRoofTruss(RoofTruss): @@ -795,28 +795,28 @@ def define_nodes(self) -> None: def define_connectivity(self) -> None: # Bottom chord connectivity - self.bottom_chord_node_ids = [0, 1, 2, 3, 4, 5] - left_v = 0 - right_v = 5 + self.bottom_chord_node_ids = [1, 2, 3, 4, 5, 6] + left_v = 1 + right_v = 6 # Top chord connectivity (left and right slopes stored separately) self.top_chord_node_ids = { - "left": [left_v, 6, 7, 8], - "right": [8, 9, 10, right_v], + "left": [left_v, 7, 8, 9], + "right": [9, 10, 11, right_v], } if self.overhang_length > 0: - self.top_chord_node_ids["left"].insert(0, 11) # left overhang - self.top_chord_node_ids["right"].append(12) # right overhang + self.top_chord_node_ids["left"].insert(0, 12) # left overhang + self.top_chord_node_ids["right"].append(13) # right overhang # Web diagonals connectivity - self.web_node_pairs.append((1, 6)) - self.web_node_pairs.append((1, 7)) self.web_node_pairs.append((2, 7)) self.web_node_pairs.append((2, 8)) self.web_node_pairs.append((3, 8)) self.web_node_pairs.append((3, 9)) self.web_node_pairs.append((4, 9)) self.web_node_pairs.append((4, 10)) + self.web_node_pairs.append((5, 10)) + self.web_node_pairs.append((5, 11)) class DoubleHoweRoofTruss(RoofTruss): @@ -865,31 +865,31 @@ def define_nodes(self) -> None: def define_connectivity(self) -> None: # Bottom chord connectivity - self.bottom_chord_node_ids = [0, 1, 2, 3, 4, 5, 6] - left_v = 0 - right_v = 6 + self.bottom_chord_node_ids = [1, 2, 3, 4, 5, 6, 7] + left_v = 1 + right_v = 7 # Top chord connectivity (left and right slopes stored separately) self.top_chord_node_ids = { - "left": [left_v, 7, 8, 9], - "right": [9, 10, 11, right_v], + "left": [left_v, 8, 9, 10], + "right": [10, 11, 12, right_v], } if self.overhang_length > 0: - self.top_chord_node_ids["left"].insert(0, 12) # left overhang - self.top_chord_node_ids["right"].append(13) # right overhang + self.top_chord_node_ids["left"].insert(0, 13) # left overhang + self.top_chord_node_ids["right"].append(14) # right overhang # Web diagonals connectivity - self.web_node_pairs.append((2, 7)) self.web_node_pairs.append((3, 8)) - self.web_node_pairs.append((3, 10)) + self.web_node_pairs.append((4, 9)) self.web_node_pairs.append((4, 11)) + self.web_node_pairs.append((5, 12)) # Web verticals connectivity - self.web_verticals_node_pairs.append((1, 7)) self.web_verticals_node_pairs.append((2, 8)) - self.web_verticals_node_pairs.append((3, 9)) # center vertical - self.web_verticals_node_pairs.append((4, 10)) + self.web_verticals_node_pairs.append((3, 9)) + self.web_verticals_node_pairs.append((4, 10)) # center vertical self.web_verticals_node_pairs.append((5, 11)) + self.web_verticals_node_pairs.append((6, 12)) class ModifiedFanRoofTruss(RoofTruss): @@ -938,31 +938,31 @@ def define_nodes(self) -> None: def define_connectivity(self) -> None: # Bottom chord connectivity - self.bottom_chord_node_ids = [0, 1, 2, 3, 4] - left_v = 0 - right_v = 4 + self.bottom_chord_node_ids = [1, 2, 3, 4, 5] + left_v = 1 + right_v = 5 # Top chord connectivity (left and right slopes stored separately) self.top_chord_node_ids = { - "left": [left_v, 5, 6, 7, 8], - "right": [8, 9, 10, 11, right_v], + "left": [left_v, 6, 7, 8, 9], + "right": [9, 10, 11, 12, right_v], } if self.overhang_length > 0: - self.top_chord_node_ids["left"].insert(0, 12) # left overhang - self.top_chord_node_ids["right"].append(13) # right overhang + self.top_chord_node_ids["left"].insert(0, 13) # left overhang + self.top_chord_node_ids["right"].append(14) # right overhang # Web diagonals connectivity - self.web_node_pairs.append((1, 5)) - self.web_node_pairs.append((1, 7)) - self.web_node_pairs.append((2, 7)) - self.web_node_pairs.append((2, 9)) - self.web_node_pairs.append((3, 9)) - self.web_node_pairs.append((3, 11)) + self.web_node_pairs.append((2, 6)) + self.web_node_pairs.append((2, 8)) + self.web_node_pairs.append((3, 8)) + self.web_node_pairs.append((3, 10)) + self.web_node_pairs.append((4, 10)) + self.web_node_pairs.append((4, 12)) # Web verticals connectivity - self.web_verticals_node_pairs.append((1, 6)) - self.web_verticals_node_pairs.append((2, 8)) # center vertical - self.web_verticals_node_pairs.append((3, 10)) + self.web_verticals_node_pairs.append((2, 7)) + self.web_verticals_node_pairs.append((3, 9)) # center vertical + self.web_verticals_node_pairs.append((4, 11)) class AtticRoofTruss(RoofTruss): @@ -1142,53 +1142,53 @@ def define_nodes(self) -> None: def define_connectivity(self) -> None: # Bottom chord connectivity - self.bottom_chord_node_ids = [0, 1, 2, 3] - left_v = 0 - right_v = 3 + self.bottom_chord_node_ids = [1, 2, 3, 4] + left_v = 1 + right_v = 4 if self.wall_ceiling_intersect: # Top chord connectivity (left and right slopes stored separately) self.top_chord_node_ids = { - "left": [left_v, 4, 5, 6], - "right": [6, 7, 8, right_v], - "ceiling": [5, 9, 7], # attic ceiling + "left": [left_v, 5, 6, 7], + "right": [7, 8, 9, right_v], + "ceiling": [6, 10, 8], # attic ceiling } if self.overhang_length > 0: - self.top_chord_node_ids["left"].insert(0, 10) # left overhang - self.top_chord_node_ids["right"].append(11) # right overhang + self.top_chord_node_ids["left"].insert(0, 11) # left overhang + self.top_chord_node_ids["right"].append(12) # right overhang # Web diagonals connectivity - self.web_node_pairs.append((1, 4)) + self.web_node_pairs.append((2, 5)) self.web_node_pairs.append( - (9, 6) + (10, 7) ) # special case: this is actually the center vertical post - self.web_node_pairs.append((2, 8)) + self.web_node_pairs.append((3, 9)) # Web verticals connectivity - self.web_verticals_node_pairs.append((1, 5)) - self.web_verticals_node_pairs.append((2, 7)) + self.web_verticals_node_pairs.append((2, 6)) + self.web_verticals_node_pairs.append((3, 8)) else: # Top chord connectivity (left and right slopes stored separately) self.top_chord_node_ids = { - "left": [left_v, 4, 5, 6, 7], - "right": [7, 8, 9, 10, right_v], - "ceiling": [6, 11, 8], # attic ceiling + "left": [left_v, 5, 6, 7, 8], + "right": [8, 9, 10, 11, right_v], + "ceiling": [7, 12, 9], # attic ceiling } if self.overhang_length > 0: - self.top_chord_node_ids["left"].insert(0, 12) # left overhang - self.top_chord_node_ids["right"].append(13) # right overhang + self.top_chord_node_ids["left"].insert(0, 13) # left overhang + self.top_chord_node_ids["right"].append(14) # right overhang # Web diagonals connectivity - self.web_node_pairs.append((1, 4)) + self.web_node_pairs.append((2, 5)) self.web_node_pairs.append( - (11, 7) + (12, 8) ) # special case: this is actually the center vertical post - self.web_node_pairs.append((2, 10)) + self.web_node_pairs.append((3, 11)) # Web verticals connectivity - self.web_verticals_node_pairs.append((1, 5)) - self.web_verticals_node_pairs.append((2, 9)) + self.web_verticals_node_pairs.append((2, 6)) + self.web_verticals_node_pairs.append((3, 10)) def create_truss(truss_type: str, **kwargs: Any) -> "Truss": diff --git a/anastruct/preprocess/truss_class.py b/anastruct/preprocess/truss_class.py index 399325c..75def6e 100644 --- a/anastruct/preprocess/truss_class.py +++ b/anastruct/preprocess/truss_class.py @@ -176,7 +176,7 @@ def define_supports(self) -> None: def add_nodes(self) -> None: """Add all nodes from self.nodes to the SystemElements.""" for i, vertex in enumerate(self.nodes): - add_node(self.system, point=vertex, node_id=i) + add_node(self.system, point=vertex, node_id=i + 1) def add_elements(self) -> None: """Create elements from connectivity definitions and add to SystemElements. @@ -207,7 +207,7 @@ def add_segment_elements( for i, j in node_pairs: element_ids.append( self.system.add_element( - location=(self.nodes[i], self.nodes[j]), + location=(self.nodes[i - 1], self.nodes[j - 1]), EA=section["EA"], EI=section["EI"], g=section["g"], @@ -433,8 +433,8 @@ def validate(self) -> bool: Raises: ValueError: If validation fails with description of the issue """ - # Check that all node IDs in connectivity are valid - max_node_id = len(self.nodes) - 1 + # Check that all node IDs in connectivity are valid (1-based) + max_node_id = len(self.nodes) # Helper to validate node ID list def validate_node_ids( @@ -443,44 +443,44 @@ def validate_node_ids( if isinstance(node_ids, dict): for segment_name, ids in node_ids.items(): for node_id in ids: - if node_id < 0 or node_id > max_node_id: + if node_id < 1 or node_id > max_node_id: raise ValueError( f"{name} segment '{segment_name}' references invalid node ID {node_id}. " - f"Valid range: 0-{max_node_id}" + f"Valid range: 1-{max_node_id}" ) else: for node_id in node_ids: - if node_id < 0 or node_id > max_node_id: + if node_id < 1 or node_id > max_node_id: raise ValueError( f"{name} references invalid node ID {node_id}. " - f"Valid range: 0-{max_node_id}" + f"Valid range: 1-{max_node_id}" ) validate_node_ids(self.top_chord_node_ids, "top_chord_node_ids") validate_node_ids(self.bottom_chord_node_ids, "bottom_chord_node_ids") for i, (node_a, node_b) in enumerate(self.web_node_pairs): - if node_a < 0 or node_a > max_node_id: + if node_a < 1 or node_a > max_node_id: raise ValueError( f"web_node_pairs[{i}] references invalid node ID {node_a}. " - f"Valid range: 0-{max_node_id}" + f"Valid range: 1-{max_node_id}" ) - if node_b < 0 or node_b > max_node_id: + if node_b < 1 or node_b > max_node_id: raise ValueError( f"web_node_pairs[{i}] references invalid node ID {node_b}. " - f"Valid range: 0-{max_node_id}" + f"Valid range: 1-{max_node_id}" ) for i, (node_a, node_b) in enumerate(self.web_verticals_node_pairs): - if node_a < 0 or node_a > max_node_id: + if node_a < 1 or node_a > max_node_id: raise ValueError( f"web_verticals_node_pairs[{i}] references invalid node ID {node_a}. " - f"Valid range: 0-{max_node_id}" + f"Valid range: 1-{max_node_id}" ) - if node_b < 0 or node_b > max_node_id: + if node_b < 1 or node_b > max_node_id: raise ValueError( f"web_verticals_node_pairs[{i}] references invalid node ID {node_b}. " - f"Valid range: 0-{max_node_id}" + f"Valid range: 1-{max_node_id}" ) # Check for duplicate node locations (within tolerance) @@ -500,8 +500,8 @@ def validate_node_ids( def check_element_length( node_a_id: int, node_b_id: int, element_type: str ) -> None: - node_a = self.nodes[node_a_id] - node_b = self.nodes[node_b_id] + node_a = self.nodes[node_a_id - 1] + node_b = self.nodes[node_b_id - 1] dx = node_b.x - node_a.x dy = node_b.y - node_a.y length = np.sqrt(dx**2 + dy**2) @@ -675,7 +675,7 @@ def define_supports(self) -> None: """ assert isinstance(self.bottom_chord_node_ids, list) assert isinstance(self.top_chord_node_ids, list) - bottom_left = 0 + bottom_left = 1 bottom_right = max(self.bottom_chord_node_ids) top_left = min(self.top_chord_node_ids) top_right = max(self.top_chord_node_ids) @@ -784,7 +784,7 @@ def define_supports(self) -> None: """ assert isinstance(self.bottom_chord_node_ids, list) - bottom_left = 0 + bottom_left = 1 bottom_right = max(self.bottom_chord_node_ids) self.support_definitions[bottom_left] = self._resolve_support_type( is_primary=True From cb1b768bc845c655f4213b28ebf5b0d99e6c9ba7 Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Wed, 4 Feb 2026 16:10:06 +1100 Subject: [PATCH 07/18] Update truss tests --- tests/test_truss.py | 95 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/tests/test_truss.py b/tests/test_truss.py index 3137e16..d012495 100644 --- a/tests/test_truss.py +++ b/tests/test_truss.py @@ -184,12 +184,13 @@ def it_has_center_vertical_to_peak(): # Get the center vertical connection center_vertical = truss.web_verticals_node_pairs[0] - # Node 1 is center bottom, node 4 is peak - assert center_vertical == (1, 4) + # Node 2 is center bottom, node 5 is peak (1-based IDs) + assert center_vertical == (2, 5) # Verify these nodes are actually center bottom and peak - center_bottom = truss.nodes[1] - peak = truss.nodes[4] + # Node IDs are 1-based, so we access nodes list with index-1 + center_bottom = truss.nodes[1] # Node ID 2 at index 1 + peak = truss.nodes[4] # Node ID 5 at index 4 assert center_bottom.x == approx(truss.width / 2) assert center_bottom.y == approx(0) @@ -486,10 +487,11 @@ def it_catches_invalid_node_ids_in_connectivity(): def it_catches_duplicate_nodes(): truss = HoweFlatTruss(width=20, height=2.5, unit_width=2.0) - # Add duplicate node at same location as node 0 + # Add duplicate node at same location as node ID 1 (index 0) original = truss.nodes[0] truss.nodes.append(Vertex(original.x, original.y)) - truss.web_node_pairs.append((0, len(truss.nodes) - 1)) + # Node IDs are 1-based, so new node ID is len(truss.nodes) + truss.web_node_pairs.append((1, len(truss.nodes))) with raises(ValueError, match="Duplicate nodes"): truss.validate() @@ -667,3 +669,84 @@ def it_creates_multiple_independent_instances(): # Should not affect the other assert len(truss1.nodes) != len(truss2.nodes) assert truss2.validate() + + +def describe_solve_tests(): + """Solve tests - verify trusses can be solved and produce valid reactions.""" + + def describe_king_post_roof_truss_solve(): + def it_solves_with_top_chord_load(): + truss = KingPostRoofTruss(width=10, roof_pitch_deg=30) + + # Apply distributed load to top chord + truss.apply_q_load_to_top_chord(q=-5, direction="y") + + # Solve the system + truss.system.solve() + + # Get support node IDs (1-based) + support_node_ids = list(truss.support_definitions.keys()) + assert len(support_node_ids) == 2 + + # Check that reactions are non-zero at support nodes + for node_id in support_node_ids: + reaction = truss.system.get_node_results_system(node_id=node_id)["Fy"] + assert abs(reaction) > 0, f"Node {node_id} should have non-zero reaction" + + # Verify total vertical reaction equals applied load + total_reaction = sum( + truss.system.get_node_results_system(node_id=node_id)["Fy"] + for node_id in support_node_ids + ) + + # Applied load = q * length of top chord + # For king post, top chord has 2 segments from ends to peak + top_chord_length = 0 + top_chord_el_ids = truss.get_element_ids_of_chord("top") + for el_id in top_chord_el_ids: + element = truss.system.element_map[el_id] + top_chord_length += element.l + + expected_total_load = -5 * top_chord_length + + assert total_reaction == approx( + expected_total_load, abs=0.1 + ), "Total reactions should equal total applied load" + + def describe_howe_flat_truss_solve(): + def it_solves_with_bottom_chord_load(): + truss = HoweFlatTruss(width=20, height=2.5, unit_width=2.0) + + # Apply distributed load to bottom chord + truss.apply_q_load_to_bottom_chord(q=-10, direction="y") + + # Solve the system + truss.system.solve() + + # Get support node IDs (1-based) + support_node_ids = list(truss.support_definitions.keys()) + assert len(support_node_ids) == 2 + + # Check that reactions are non-zero at support nodes + for node_id in support_node_ids: + reaction = truss.system.get_node_results_system(node_id=node_id)["Fy"] + assert abs(reaction) > 0, f"Node {node_id} should have non-zero reaction" + + # Verify total vertical reaction equals applied load + total_reaction = sum( + truss.system.get_node_results_system(node_id=node_id)["Fy"] + for node_id in support_node_ids + ) + + # Applied load = q * length of bottom chord + bottom_chord_length = 0 + bottom_chord_el_ids = truss.get_element_ids_of_chord("bottom") + for el_id in bottom_chord_el_ids: + element = truss.system.element_map[el_id] + bottom_chord_length += element.l + + expected_total_load = -10 * bottom_chord_length + + assert total_reaction == approx( + expected_total_load, abs=0.1 + ), "Total reactions should equal total applied load" From 4f5ce4c2a46927179cb5259fd52217b3474fc167 Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Wed, 4 Feb 2026 16:10:13 +1100 Subject: [PATCH 08/18] Add beam tests --- tests/test_beam.py | 672 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 672 insertions(+) create mode 100644 tests/test_beam.py diff --git a/tests/test_beam.py b/tests/test_beam.py new file mode 100644 index 0000000..d8f9c50 --- /dev/null +++ b/tests/test_beam.py @@ -0,0 +1,672 @@ +"""Tests for beam generator functionality. + +Tests cover: +- Unit tests for each beam type (geometry, supports, connectivity) +- Integration tests (load application and solve) +- Factory function +- Validation method +- Edge cases and error handling +""" + +import warnings + +import numpy as np +from pytest import approx, raises + +from anastruct.preprocess.beam import ( + CantileverBeam, + FourSpanBeam, + LeftCantileverBeam, + LeftProppedBeam, + MultiSpanBeam, + ProppedBeam, + RightCantileverBeam, + RightProppedBeam, + SimpleBeam, + ThreeSpanBeam, + TwoSpanBeam, + create_beam, +) +from anastruct.vertex import Vertex + + +def describe_simple_beam(): + def it_creates_valid_geometry(): + beam = SimpleBeam(length=10) + + assert beam.type == "Simple Beam" + assert beam.length == 10 + assert len(beam.nodes) == 2 + assert beam.validate() + + def it_has_correct_supports(): + beam = SimpleBeam(length=10) + + assert beam.support_definitions[1] == "pinned" + assert beam.support_definitions[2] == "roller" + assert len(beam.support_definitions) == 2 + + def it_has_one_span(): + beam = SimpleBeam(length=10) + + assert len(beam.node_ids) == 1 + assert beam.node_ids[0] == [1, 2] + assert len(beam.element_ids) == 1 + assert len(beam.element_ids[0]) == 1 + + def it_has_correct_node_positions(): + beam = SimpleBeam(length=10) + + assert beam.nodes[0].x == approx(0.0) + assert beam.nodes[0].y == approx(0.0) + assert beam.nodes[1].x == approx(10.0) + assert beam.nodes[1].y == approx(0.0) + + def it_creates_system_elements(): + beam = SimpleBeam(length=10) + + assert len(beam.system.element_map) == 1 + + def it_validates_positive_length(): + with raises(ValueError, match="must be positive"): + SimpleBeam(length=-5) + + with raises(ValueError, match="must be positive"): + SimpleBeam(length=0) + + +def describe_cantilever_beam(): + def it_creates_valid_geometry(): + beam = CantileverBeam(length=5) + + assert beam.type == "Cantilever Beam" + assert beam.length == 5 + assert len(beam.nodes) == 2 + assert beam.validate() + + def it_defaults_to_right_cantilever(): + beam = CantileverBeam(length=5) + + # Default cantilever_side="right" means free end on the right, fixed on left + assert beam.cantilever_side == "right" + assert beam.support_definitions[1] == "fixed" + assert len(beam.support_definitions) == 1 + + def it_supports_left_cantilever(): + beam = CantileverBeam(length=5, cantilever_side="left") + + # Free end on the left, fixed on right + assert beam.cantilever_side == "left" + assert beam.support_definitions[2] == "fixed" + assert len(beam.support_definitions) == 1 + + def it_validates_cantilever_side(): + with raises(ValueError, match="cantilever_side"): + CantileverBeam(length=5, cantilever_side="middle") + + +def describe_right_cantilever_beam(): + def it_creates_valid_geometry(): + beam = RightCantileverBeam(length=5) + + assert beam.type == "Right Cantilever Beam" + assert beam.cantilever_side == "right" + assert beam.validate() + + def it_has_fixed_support_on_left(): + beam = RightCantileverBeam(length=5) + + assert beam.support_definitions[1] == "fixed" + assert 2 not in beam.support_definitions + + +def describe_left_cantilever_beam(): + def it_creates_valid_geometry(): + beam = LeftCantileverBeam(length=5) + + assert beam.type == "Left Cantilever Beam" + assert beam.cantilever_side == "left" + assert beam.validate() + + def it_has_fixed_support_on_right(): + beam = LeftCantileverBeam(length=5) + + assert beam.support_definitions[2] == "fixed" + assert 1 not in beam.support_definitions + + +def describe_multi_span_beam(): + def it_creates_with_num_spans(): + beam = MultiSpanBeam(length=30, num_spans=3) + + assert beam.type == "Multi-Span Beam" + assert beam.length == approx(30) + assert len(beam.nodes) == 4 + assert len(beam.node_ids) == 3 + assert beam.validate() + + def it_creates_with_span_lengths(): + beam = MultiSpanBeam(span_lengths=[4, 6, 5]) + + assert beam.length == approx(15) + assert len(beam.nodes) == 4 + assert len(beam.node_ids) == 3 + + def it_has_supports_at_all_interior_and_end_nodes(): + beam = MultiSpanBeam(length=30, num_spans=3) + + # Node 1 = pinned, nodes 2, 3, 4 = roller + assert beam.support_definitions[1] == "pinned" + assert beam.support_definitions[2] == "roller" + assert beam.support_definitions[3] == "roller" + assert beam.support_definitions[4] == "roller" + assert len(beam.support_definitions) == 4 + + def it_supports_left_cantilever(): + beam = MultiSpanBeam(span_lengths=[3, 5, 5], cantilevers="left") + + # Left cantilever: first span is unsupported on the left + assert 1 not in beam.support_definitions + assert beam.support_definitions[2] == "pinned" + assert beam.support_definitions[3] == "roller" + assert beam.support_definitions[4] == "roller" + + def it_supports_right_cantilever(): + beam = MultiSpanBeam(span_lengths=[5, 5, 3], cantilevers="right") + + # Right cantilever: last span is unsupported on the right + assert beam.support_definitions[1] == "pinned" + assert beam.support_definitions[2] == "roller" + assert 4 not in beam.support_definitions + + def it_supports_both_cantilevers(): + beam = MultiSpanBeam(span_lengths=[3, 5, 5, 3], cantilevers="both") + + # Both cantilevers: first and last spans unsupported at ends + assert 1 not in beam.support_definitions + assert beam.support_definitions[2] == "pinned" + assert beam.support_definitions[3] == "roller" + assert 5 not in beam.support_definitions + + def it_has_one_element_per_span(): + beam = MultiSpanBeam(length=30, num_spans=3) + + for span in range(3): + assert len(beam.element_ids[span]) == 1 + + def it_validates_input_combinations(): + with raises(ValueError, match="Either num_spans or span_lengths"): + MultiSpanBeam() + + with raises(ValueError, match="Only one of"): + MultiSpanBeam(span_lengths=[5, 5], num_spans=2) + + with raises(ValueError, match="length must also be provided"): + MultiSpanBeam(num_spans=3) + + def it_validates_cantilevers_parameter(): + with raises(ValueError, match="cantilevers must be"): + MultiSpanBeam(length=20, num_spans=2, cantilevers="top") + + def it_creates_equal_spans_from_num_spans(): + beam = MultiSpanBeam(length=30, num_spans=3) + + assert beam.span_lengths == [approx(10), approx(10), approx(10)] + + +def describe_two_span_beam(): + def it_creates_valid_geometry(): + beam = TwoSpanBeam(length=20) + + assert beam.type == "Two-Span Beam" + assert beam.length == approx(20) + assert len(beam.nodes) == 3 + assert len(beam.node_ids) == 2 + assert beam.validate() + + def it_has_correct_supports(): + beam = TwoSpanBeam(length=20) + + assert beam.support_definitions[1] == "pinned" + assert beam.support_definitions[2] == "roller" + assert beam.support_definitions[3] == "roller" + + +def describe_three_span_beam(): + def it_creates_valid_geometry(): + beam = ThreeSpanBeam(length=30) + + assert beam.type == "Three-Span Beam" + assert beam.length == approx(30) + assert len(beam.nodes) == 4 + assert len(beam.node_ids) == 3 + assert beam.validate() + + def it_has_support_at_every_node(): + beam = ThreeSpanBeam(length=30) + + assert len(beam.support_definitions) == 4 + assert beam.support_definitions[1] == "pinned" + for i in range(2, 5): + assert beam.support_definitions[i] == "roller" + + +def describe_four_span_beam(): + def it_creates_valid_geometry(): + beam = FourSpanBeam(length=40) + + assert beam.type == "Four-Span Beam" + assert beam.length == approx(40) + assert len(beam.nodes) == 5 + assert len(beam.node_ids) == 4 + assert beam.validate() + + def it_has_support_at_every_node(): + beam = FourSpanBeam(length=40) + + assert len(beam.support_definitions) == 5 + + +def describe_propped_beam(): + def it_creates_right_propped(): + beam = ProppedBeam( + interior_length=8, cantilever_length=3, cantilever_side="right" + ) + + assert beam.type == "Propped Beam" + assert beam.length == approx(11) + assert beam.cantilever_side == "right" + assert beam.validate() + + def it_creates_left_propped(): + beam = ProppedBeam( + interior_length=8, cantilever_length=3, cantilever_side="left" + ) + + assert beam.length == approx(11) + assert beam.cantilever_side == "left" + assert beam.validate() + + def it_has_supports_on_interior_span_only(): + beam = ProppedBeam( + interior_length=8, cantilever_length=3, cantilever_side="right" + ) + + # Right cantilever: support at nodes 1 and 2, not at node 3 + assert beam.support_definitions[1] == "pinned" + assert beam.support_definitions[2] == "roller" + assert 3 not in beam.support_definitions + + def it_validates_cantilever_side(): + with raises(ValueError, match="cantilever_side"): + ProppedBeam(interior_length=8, cantilever_length=3, cantilever_side="up") + + +def describe_right_propped_beam(): + def it_creates_valid_geometry(): + beam = RightProppedBeam(interior_length=8, cantilever_length=3) + + assert beam.type == "Right Propped Beam" + assert beam.cantilever_side == "right" + assert beam.validate() + + def it_has_no_support_at_right_end(): + beam = RightProppedBeam(interior_length=8, cantilever_length=3) + + last_node = len(beam.nodes) + assert last_node not in beam.support_definitions + + +def describe_left_propped_beam(): + def it_creates_valid_geometry(): + beam = LeftProppedBeam(interior_length=8, cantilever_length=3) + + assert beam.type == "Left Propped Beam" + assert beam.cantilever_side == "left" + assert beam.validate() + + def it_has_no_support_at_left_end(): + beam = LeftProppedBeam(interior_length=8, cantilever_length=3) + + assert 1 not in beam.support_definitions + + +def describe_factory_function(): + """Tests for create_beam factory function.""" + + def it_creates_beam_by_name(): + beam = create_beam("simple", length=10) + + assert isinstance(beam, SimpleBeam) + assert beam.type == "Simple Beam" + + def it_handles_case_insensitive_names(): + beams = [ + create_beam("simple", length=10), + create_beam("SIMPLE", length=10), + create_beam("Simple", length=10), + ] + + for beam in beams: + assert isinstance(beam, SimpleBeam) + + def it_handles_different_name_separators(): + beam_underscore = create_beam("two_span", length=20) + beam_hyphen = create_beam("two-span", length=20) + beam_space = create_beam("two span", length=20) + + assert isinstance(beam_underscore, TwoSpanBeam) + assert isinstance(beam_hyphen, TwoSpanBeam) + assert isinstance(beam_space, TwoSpanBeam) + + def it_creates_all_beam_types(): + beams = { + "simple": {"length": 10}, + "cantilever": {"length": 5}, + "right_cantilever": {"length": 5}, + "left_cantilever": {"length": 5}, + "multi_span": {"length": 20, "num_spans": 2}, + "two_span": {"length": 20}, + "three_span": {"length": 30}, + "four_span": {"length": 40}, + "propped": {"interior_length": 8, "cantilever_length": 3}, + "right_propped": {"interior_length": 8, "cantilever_length": 3}, + "left_propped": {"interior_length": 8, "cantilever_length": 3}, + } + + for name, kwargs in beams.items(): + beam = create_beam(name, **kwargs) + assert beam.validate() + + def it_raises_error_for_invalid_type(): + with raises(ValueError, match="Unknown beam type"): + create_beam("nonexistent", length=10) + + def it_provides_helpful_error_with_available_types(): + with raises(ValueError, match="Available types"): + create_beam("invalid_type", length=10) + + +def describe_validate_method(): + def it_validates_correct_geometry(): + beam = SimpleBeam(length=10) + assert beam.validate() + + def it_catches_invalid_node_ids(): + beam = SimpleBeam(length=10) + + # Inject an invalid node ID + beam.node_ids[0] = [1, 99] + + with raises(ValueError, match="invalid node ID"): + beam.validate() + + def it_catches_duplicate_nodes(): + beam = SimpleBeam(length=10) + + # Make both nodes at the same position + beam.nodes[1] = Vertex(0.0, 0.0) + + with raises(ValueError, match="Duplicate nodes"): + beam.validate() + + +def describe_integration_tests(): + """Integration tests with load application.""" + + def describe_distributed_loads(): + def it_applies_q_load_to_simple_beam(): + beam = SimpleBeam(length=10) + beam.apply_q_load_to_spans(q=-5, direction="y") + + # Verify load was applied to the element + assert beam.system.loads_q is not None + assert len(beam.system.loads_q) > 0 + + def it_applies_q_load_to_specific_span(): + beam = TwoSpanBeam(length=20) + # Only load span 0 + beam.apply_q_load_to_spans(q=-10, direction="y", spans=0) + + # Only the element in span 0 should have a load + loaded_element_id = beam.element_ids[0][0] + assert loaded_element_id in beam.system.loads_q + + def it_applies_q_load_to_multiple_spans(): + beam = ThreeSpanBeam(length=30) + beam.apply_q_load_to_spans(q=-5, direction="y", spans=[0, 2]) + + # Elements in spans 0 and 2 should be loaded + for span in [0, 2]: + el_id = beam.element_ids[span][0] + assert el_id in beam.system.loads_q + + def it_applies_q_load_to_all_spans_by_default(): + beam = ThreeSpanBeam(length=30) + beam.apply_q_load_to_spans(q=-5, direction="y") + + # All elements should be loaded + for span in range(3): + el_id = beam.element_ids[span][0] + assert el_id in beam.system.loads_q + + def describe_point_loads(): + def it_applies_point_load_at_existing_node(): + beam = SimpleBeam(length=10) + # Load at start node (absolute_location=0 is at node 1) + beam.apply_point_load_to_spans(Fy=-100, absolute_location=0.0) + + assert len(beam.system.loads_point) > 0 + + def it_inserts_node_for_point_load(): + beam = SimpleBeam(length=10) + original_elements = len(beam.system.element_map) + + beam.apply_point_load_to_spans(Fy=-100, absolute_location=3.0) + + # Should have split the element, creating 2 elements from 1 + assert len(beam.system.element_map) == original_elements + 1 + + def it_updates_internal_ids_after_node_insertion(): + beam = SimpleBeam(length=10) + + beam.apply_point_load_to_spans(Fy=-100, absolute_location=3.0) + + # node_ids for span 0 should now have 3 nodes + assert len(beam.node_ids[0]) == 3 + # element_ids for span 0 should now have 2 elements + assert len(beam.element_ids[0]) == 2 + + def it_validates_location_arguments(): + beam = SimpleBeam(length=10) + + with raises(ValueError, match="Either absolute_location or relative_location"): + beam.apply_point_load_to_spans(Fy=-100) + + with raises(ValueError, match="Only one of"): + beam.apply_point_load_to_spans( + Fy=-100, absolute_location=5.0, relative_location=0.5 + ) + + def it_applies_load_at_relative_location(): + beam = SimpleBeam(length=10) + + beam.apply_point_load_to_spans(Fy=-100, relative_location=0.5) + + # Should have inserted a node at midpoint and applied load + assert len(beam.node_ids[0]) == 3 + assert len(beam.system.loads_point) > 0 + + def describe_cantilever_loads(): + def it_applies_tip_load_to_cantilever(): + beam = RightCantileverBeam(length=5) + beam.apply_point_load_to_spans(Fy=-100, relative_location=1.0) + + # Load should be applied at the tip node + assert len(beam.system.loads_point) > 0 + + def it_applies_distributed_load_to_cantilever(): + beam = LeftCantileverBeam(length=8) + beam.apply_q_load_to_spans(q=-10, direction="y") + + assert len(beam.system.loads_q) > 0 + + def describe_solve_integration_tests(): + """Solve-based integration tests to verify reactions.""" + + def it_solves_simple_beam_with_udl(): + # Simple beam with UDL: q=-5, direction="y" on length=10 + # Reactions at each end = |q|*L/2 = 5*10/2 = 25 (upward) + beam = SimpleBeam(length=10) + beam.apply_q_load_to_spans(q=-5, direction="y") + beam.system.solve() + + # Node IDs are 1-based: left node=1, right node=2 + left_reaction = beam.system.get_node_results_system(node_id=1)["Fy"] + right_reaction = beam.system.get_node_results_system(node_id=2)["Fy"] + + # get_node_results_system returns reaction in system sign convention + assert abs(left_reaction) == approx(25, abs=1e-6) + assert abs(right_reaction) == approx(25, abs=1e-6) + + def it_solves_two_span_beam_with_udl(): + # Two-span beam with UDL: verify solve works for indeterminate structure + beam = TwoSpanBeam(length=20) + beam.apply_q_load_to_spans(q=-10, direction="y") + beam.system.solve() + + # Total load = 10 * 20 = 200, sum of reactions must equal 200 + total_reaction = sum( + abs(beam.system.get_node_results_system(node_id=i)["Fy"]) + for i in range(1, 4) + ) + assert total_reaction == approx(200, abs=1e-3) + + def it_solves_right_cantilever_with_tip_load(): + # RightCantileverBeam length=5, Fy=-100 at tip + # Fixed end reaction magnitude = 100 + beam = RightCantileverBeam(length=5) + beam.apply_point_load_to_spans(Fy=-100, relative_location=1.0) + beam.system.solve() + + # Fixed support is at left node (node_id=1) + fixed_reaction = beam.system.get_node_results_system(node_id=1)["Fy"] + + assert abs(fixed_reaction) == approx(100, abs=1e-6) + + def it_solves_left_cantilever_with_udl(): + # LeftCantileverBeam length=8, q=-10 + # Fixed end reaction magnitude = 80 + beam = LeftCantileverBeam(length=8) + beam.apply_q_load_to_spans(q=-10, direction="y") + beam.system.solve() + + # Fixed support is at right node (node_id=2) + fixed_reaction = beam.system.get_node_results_system(node_id=2)["Fy"] + + assert abs(fixed_reaction) == approx(80, abs=1e-6) + + +def describe_span_element_ids(): + """Tests for get_element_ids_of_spans.""" + + def it_gets_all_elements_when_none(): + beam = ThreeSpanBeam(length=30) + + all_ids = beam.get_element_ids_of_spans(spans=None) + assert len(all_ids) == 3 + + def it_gets_single_span(): + beam = ThreeSpanBeam(length=30) + + span_ids = beam.get_element_ids_of_spans(spans=1) + assert len(span_ids) == 1 + + def it_gets_multiple_spans(): + beam = ThreeSpanBeam(length=30) + + span_ids = beam.get_element_ids_of_spans(spans=[0, 2]) + assert len(span_ids) == 2 + + def it_raises_for_invalid_span(): + beam = ThreeSpanBeam(length=30) + + with raises(KeyError, match="span number"): + beam.get_element_ids_of_spans(spans=99) + + +def describe_angled_beams(): + """Tests for beams at non-zero angles.""" + + def it_creates_angled_simple_beam(): + beam = SimpleBeam(length=10, angle=45) + + expected_x = 10 * np.cos(np.radians(45)) + expected_y = 10 * np.sin(np.radians(45)) + assert beam.nodes[1].x == approx(expected_x) + assert beam.nodes[1].y == approx(expected_y) + assert beam.validate() + + def it_creates_vertical_beam(): + beam = SimpleBeam(length=10, angle=90) + + assert beam.nodes[1].x == approx(0.0, abs=1e-10) + assert beam.nodes[1].y == approx(10.0) + + def it_warns_for_radian_like_angle(): + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + SimpleBeam(length=10, angle=1.5) + + assert len(w) == 1 + assert "degrees, not radians" in str(w[0].message) + + def it_does_not_warn_for_zero_angle(): + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + SimpleBeam(length=10, angle=0) + + assert len(w) == 0 + + def it_does_not_warn_for_normal_angle(): + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + SimpleBeam(length=10, angle=45) + + assert len(w) == 0 + + def it_normalizes_negative_angle(): + beam = SimpleBeam(length=10, angle=-90) + assert beam.angle == approx(270) + + +def describe_edge_cases(): + def it_creates_multiple_independent_instances(): + beam1 = SimpleBeam(length=10) + beam2 = SimpleBeam(length=20) + + # Instances should be independent + assert beam1.length != beam2.length + assert len(beam1.nodes) == len(beam2.nodes) + assert beam1.nodes[1].x != beam2.nodes[1].x + + def it_handles_very_short_beam(): + beam = SimpleBeam(length=0.001) + assert beam.validate() + + def it_handles_very_long_beam(): + beam = SimpleBeam(length=1e6) + assert beam.validate() + + def it_handles_unequal_span_lengths(): + beam = MultiSpanBeam(span_lengths=[3, 7, 5, 2]) + + assert beam.length == approx(17) + assert len(beam.nodes) == 5 + assert beam.validate() + + def it_handles_custom_section(): + section = {"EI": 2e6, "EA": 3e8, "g": 5.0} + beam = SimpleBeam(length=10, section=section) + + assert beam.section == section From d5be0b56fb58d739f2d2dd28f6bb4a650f705e3f Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Sat, 30 May 2026 20:52:32 +1000 Subject: [PATCH 09/18] Rename types.py -> _types.py to avoid collision with builtin --- anastruct/_types.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 anastruct/_types.py diff --git a/anastruct/_types.py b/anastruct/_types.py new file mode 100644 index 0000000..90f596f --- /dev/null +++ b/anastruct/_types.py @@ -0,0 +1,26 @@ +from typing import TYPE_CHECKING, Dict, Literal, Sequence, TypedDict, Union + +import numpy as np + +if TYPE_CHECKING: + from anastruct.vertex import Vertex + +AxisNumber = Literal[1, 2, 3] +Dimension = Literal["x", "y", "y_neg", "both"] +ElementType = Literal["general", "truss"] +LoadDirection = Literal["element", "x", "y", "parallel", "perpendicular", "angle"] +MpType = Dict[Literal[1, 2], float] +NumberLike = Union[float, int, np.number] +OrientAxis = Literal["y", "z"] +Spring = Dict[Literal[1, 2], float] +SupportDirection = Literal["x", "y", "1", "2", 1, 2] +VertexLike = Union[Sequence[Union[float, int]], np.ndarray, "Vertex"] + +SectionProps = TypedDict( + "SectionProps", + { + "EI": float, + "EA": float, + "g": float, + }, +) From e18ab5a95eb0f33b56f0494eb8ddf4dc49e6a00f Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Tue, 2 Jun 2026 20:09:44 +1000 Subject: [PATCH 10/18] Merge master --- anastruct/fem/elements.py | 2 +- anastruct/fem/system.py | 4 ++-- anastruct/fem/system_components/assembly.py | 2 +- anastruct/fem/system_components/util.py | 2 +- anastruct/preprocess/beam.py | 2 +- anastruct/preprocess/beam_class.py | 2 +- anastruct/preprocess/truss.py | 10 +++----- anastruct/preprocess/truss_class.py | 2 +- anastruct/types.py | 26 --------------------- anastruct/vertex.py | 2 +- 10 files changed, 12 insertions(+), 42 deletions(-) delete mode 100644 anastruct/types.py diff --git a/anastruct/fem/elements.py b/anastruct/fem/elements.py index d47d2b4..b204c41 100644 --- a/anastruct/fem/elements.py +++ b/anastruct/fem/elements.py @@ -10,9 +10,9 @@ from anastruct.basic import FEMException if TYPE_CHECKING: + from anastruct._types import ElementType from anastruct.fem.node import Node from anastruct.fem.system import Spring - from anastruct.types import ElementType from anastruct.vertex import Vertex try: diff --git a/anastruct/fem/system.py b/anastruct/fem/system.py index 06df16d..ae30419 100644 --- a/anastruct/fem/system.py +++ b/anastruct/fem/system.py @@ -30,8 +30,7 @@ if TYPE_CHECKING: from matplotlib.figure import Figure - from anastruct.fem.node import Node - from anastruct.types import ( + from anastruct._types import ( AxisNumber, Dimension, LoadDirection, @@ -40,6 +39,7 @@ SupportDirection, VertexLike, ) + from anastruct.fem.node import Node class SystemElements: diff --git a/anastruct/fem/system_components/assembly.py b/anastruct/fem/system_components/assembly.py index 7cf830e..a8625af 100644 --- a/anastruct/fem/system_components/assembly.py +++ b/anastruct/fem/system_components/assembly.py @@ -6,9 +6,9 @@ from anastruct.fem.elements import det_axial, det_moment, det_shear if TYPE_CHECKING: + from anastruct._types import AxisNumber from anastruct.fem.elements import Element from anastruct.fem.system import SystemElements - from anastruct.types import AxisNumber def set_force_vector( diff --git a/anastruct/fem/system_components/util.py b/anastruct/fem/system_components/util.py index 4dd0b3f..3c35765 100644 --- a/anastruct/fem/system_components/util.py +++ b/anastruct/fem/system_components/util.py @@ -7,8 +7,8 @@ from anastruct.vertex import Vertex if TYPE_CHECKING: + from anastruct._types import VertexLike from anastruct.fem.system import MpType, Spring, SystemElements - from anastruct.types import VertexLike def check_internal_hinges(system: "SystemElements", node_id: int) -> None: diff --git a/anastruct/preprocess/beam.py b/anastruct/preprocess/beam.py index 0fdc77a..cdca379 100644 --- a/anastruct/preprocess/beam.py +++ b/anastruct/preprocess/beam.py @@ -2,8 +2,8 @@ import numpy as np +from anastruct._types import SectionProps from anastruct.preprocess.beam_class import Beam -from anastruct.types import SectionProps from anastruct.vertex import Vertex diff --git a/anastruct/preprocess/beam_class.py b/anastruct/preprocess/beam_class.py index bfb5c82..d693fa5 100644 --- a/anastruct/preprocess/beam_class.py +++ b/anastruct/preprocess/beam_class.py @@ -3,9 +3,9 @@ import numpy as np +from anastruct._types import LoadDirection, SectionProps from anastruct.fem.system import SystemElements from anastruct.fem.system_components.util import add_node -from anastruct.types import LoadDirection, SectionProps from anastruct.vertex import Vertex DEFAULT_BEAM_SECTION: SectionProps = { diff --git a/anastruct/preprocess/truss.py b/anastruct/preprocess/truss.py index f7bb245..8424f6f 100644 --- a/anastruct/preprocess/truss.py +++ b/anastruct/preprocess/truss.py @@ -2,8 +2,8 @@ import numpy as np +from anastruct._types import SectionProps from anastruct.preprocess.truss_class import FlatTruss, RoofTruss, Truss -from anastruct.types import SectionProps from anastruct.vertex import Vertex @@ -62,9 +62,7 @@ def define_connectivity(self) -> None: if self.end_type == "triangle_up": # special case: end diagonal slopes in the opposite direction self.web_node_pairs.append((1, n_bottom_nodes + 1)) - self.web_node_pairs.append( - (n_bottom_nodes, n_bottom_nodes + n_top_nodes) - ) + self.web_node_pairs.append((n_bottom_nodes, n_bottom_nodes + n_top_nodes)) start_top = 2 end_top = -3 elif self.end_type == "flat": @@ -156,9 +154,7 @@ def define_connectivity(self) -> None: if self.end_type == "triangle_down": # special case: end diagonal slopes in the opposite direction self.web_node_pairs.append((n_bottom_nodes + 1, 1)) - self.web_node_pairs.append( - (n_bottom_nodes + n_top_nodes, n_bottom_nodes) - ) + self.web_node_pairs.append((n_bottom_nodes + n_top_nodes, n_bottom_nodes)) start_bot = 2 end_bot = -3 elif self.end_type == "flat": diff --git a/anastruct/preprocess/truss_class.py b/anastruct/preprocess/truss_class.py index 75def6e..beb1663 100644 --- a/anastruct/preprocess/truss_class.py +++ b/anastruct/preprocess/truss_class.py @@ -3,9 +3,9 @@ import numpy as np +from anastruct._types import LoadDirection, SectionProps from anastruct.fem.system import SystemElements from anastruct.fem.system_components.util import add_node -from anastruct.types import LoadDirection, SectionProps from anastruct.vertex import Vertex DEFAULT_TRUSS_SECTION: SectionProps = { diff --git a/anastruct/types.py b/anastruct/types.py deleted file mode 100644 index 90f596f..0000000 --- a/anastruct/types.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import TYPE_CHECKING, Dict, Literal, Sequence, TypedDict, Union - -import numpy as np - -if TYPE_CHECKING: - from anastruct.vertex import Vertex - -AxisNumber = Literal[1, 2, 3] -Dimension = Literal["x", "y", "y_neg", "both"] -ElementType = Literal["general", "truss"] -LoadDirection = Literal["element", "x", "y", "parallel", "perpendicular", "angle"] -MpType = Dict[Literal[1, 2], float] -NumberLike = Union[float, int, np.number] -OrientAxis = Literal["y", "z"] -Spring = Dict[Literal[1, 2], float] -SupportDirection = Literal["x", "y", "1", "2", 1, 2] -VertexLike = Union[Sequence[Union[float, int]], np.ndarray, "Vertex"] - -SectionProps = TypedDict( - "SectionProps", - { - "EI": float, - "EA": float, - "g": float, - }, -) diff --git a/anastruct/vertex.py b/anastruct/vertex.py index 458985b..679efb5 100644 --- a/anastruct/vertex.py +++ b/anastruct/vertex.py @@ -6,7 +6,7 @@ import numpy as np if TYPE_CHECKING: - from anastruct.types import NumberLike, VertexLike + from anastruct._types import NumberLike, VertexLike class Vertex: From 40212468daccb7527c50a5c79c2a26173ba9372c Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Sat, 6 Jun 2026 15:34:12 +1000 Subject: [PATCH 11/18] Make beam available in base import --- anastruct/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/anastruct/__init__.py b/anastruct/__init__.py index 028b3d9..6e5fdc0 100644 --- a/anastruct/__init__.py +++ b/anastruct/__init__.py @@ -1,4 +1,4 @@ from anastruct.fem.system import SystemElements from anastruct.fem.util.load import LoadCase, LoadCombination -from anastruct.preprocess import truss +from anastruct.preprocess import beam, truss from anastruct.vertex import Vertex From 6ae9e9b26585651312bcd3bd67163b6c3bb3a5ca Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Sat, 6 Jun 2026 15:35:32 +1000 Subject: [PATCH 12/18] Allow incomplete section properties --- anastruct/preprocess/beam_class.py | 10 +++++++++- anastruct/preprocess/truss_class.py | 13 ++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/anastruct/preprocess/beam_class.py b/anastruct/preprocess/beam_class.py index d693fa5..2d393b3 100644 --- a/anastruct/preprocess/beam_class.py +++ b/anastruct/preprocess/beam_class.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import Iterable, Literal, Optional, Sequence, Union +from typing import Iterable, Literal, Optional, Sequence, Union, cast import numpy as np @@ -107,6 +107,14 @@ def __init__( self.angle = angle self.section = section or DEFAULT_BEAM_SECTION + def ensure_valid_section(section: SectionProps) -> SectionProps: + """Ensure section has all required properties, filling in defaults.""" + valid_section = dict(DEFAULT_BEAM_SECTION) # Start with defaults + valid_section.update(section) # Override with provided values + return cast(SectionProps, valid_section) + + self.section = ensure_valid_section(self.section) + self.dx = np.cos(self.angle * np.pi / 180) self.dy = np.sin(self.angle * np.pi / 180) diff --git a/anastruct/preprocess/truss_class.py b/anastruct/preprocess/truss_class.py index beb1663..83fd859 100644 --- a/anastruct/preprocess/truss_class.py +++ b/anastruct/preprocess/truss_class.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import Iterable, Literal, Optional, Sequence, Union, overload +from typing import Iterable, Literal, Optional, Sequence, Union, cast, overload import numpy as np @@ -125,6 +125,17 @@ def __init__( self.bottom_chord_continuous = bottom_chord_continuous self.supports_type = supports_type + def ensure_valid_section(section: SectionProps) -> SectionProps: + """Ensure section has all required properties, filling in defaults.""" + valid_section = dict(DEFAULT_TRUSS_SECTION) # Start with defaults + valid_section.update(section) # Override with provided values + return cast(SectionProps, valid_section) + + self.top_chord_section = ensure_valid_section(self.top_chord_section) + self.bottom_chord_section = ensure_valid_section(self.bottom_chord_section) + self.web_section = ensure_valid_section(self.web_section) + self.web_verticals_section = ensure_valid_section(self.web_verticals_section) + # Initialize mutable attributes (prevents sharing between instances) self.nodes = [] self.web_node_pairs = [] From 33e8291017be8080d4858e94e33f802ce61aae42 Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Sat, 6 Jun 2026 15:35:43 +1000 Subject: [PATCH 13/18] Bump version --- anastruct/_version.py | 2 +- poetry.lock | 282 ++++++++++++++++++++++++++++++++++-------- pyproject.toml | 2 +- 3 files changed, 231 insertions(+), 55 deletions(-) diff --git a/anastruct/_version.py b/anastruct/_version.py index 51bbb3f..14d9d2f 100644 --- a/anastruct/_version.py +++ b/anastruct/_version.py @@ -1 +1 @@ -__version__ = "1.6.2" +__version__ = "1.7.0" diff --git a/poetry.lock b/poetry.lock index 54803ef..16833a8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,12 +1,13 @@ -# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand. [[package]] name = "alabaster" version = "1.0.0" description = "A light, configurable Sphinx theme" -optional = false +optional = true python-versions = ">=3.10" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b"}, {file = "alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e"}, @@ -18,11 +19,12 @@ version = "4.0.1" description = "An abstract syntax tree for Python with inference support." optional = false python-versions = ">=3.10.0" -groups = ["test"] +groups = ["main", "test"] files = [ {file = "astroid-4.0.1-py3-none-any.whl", hash = "sha256:37ab2f107d14dc173412327febf6c78d39590fdafcb44868f03b6c03452e3db0"}, {file = "astroid-4.0.1.tar.gz", hash = "sha256:0d778ec0def05b935e198412e62f9bcca8b3b5c39fdbe50b0ba074005e477aab"}, ] +markers = {main = "extra == \"docs\""} [package.dependencies] typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} @@ -47,9 +49,10 @@ test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"] name = "babel" version = "2.17.0" description = "Internationalization utilities" -optional = false +optional = true python-versions = ">=3.8" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"}, {file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"}, @@ -116,9 +119,10 @@ uvloop = ["uvloop (>=0.15.2)"] name = "certifi" version = "2025.10.5" description = "Python package for providing Mozilla's CA Bundle." -optional = false +optional = true python-versions = ">=3.7" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de"}, {file = "certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43"}, @@ -128,9 +132,10 @@ files = [ name = "charset-normalizer" version = "3.4.4" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = false +optional = true python-versions = ">=3.7" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d"}, {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8"}, @@ -268,12 +273,12 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["docs", "test"] +groups = ["main", "test"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -markers = {docs = "sys_platform == \"win32\"", test = "sys_platform == \"win32\" or platform_system == \"Windows\""} +markers = {main = "sys_platform == \"win32\" and extra == \"docs\"", test = "sys_platform == \"win32\" or platform_system == \"Windows\""} [[package]] name = "contourpy" @@ -282,7 +287,6 @@ description = "Python library for calculating contours of 2D quadrilateral grids optional = false python-versions = ">=3.10" groups = ["main", "dev"] -markers = "python_version == \"3.10\"" files = [ {file = "contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934"}, {file = "contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989"}, @@ -342,6 +346,7 @@ files = [ {file = "contourpy-1.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8c5acb8dddb0752bf252e01a3035b21443158910ac16a3b0d20e7fed7d534ce5"}, {file = "contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54"}, ] +markers = {main = "python_version == \"3.10\" and extra == \"plot\"", dev = "python_version == \"3.10\""} [package.dependencies] numpy = ">=1.23" @@ -360,7 +365,6 @@ description = "Python library for calculating contours of 2D quadrilateral grids optional = false python-versions = ">=3.11" groups = ["main", "dev"] -markers = "python_version >= \"3.11\"" files = [ {file = "contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1"}, {file = "contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381"}, @@ -435,6 +439,7 @@ files = [ {file = "contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77"}, {file = "contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880"}, ] +markers = {main = "python_version >= \"3.11\" and extra == \"plot\"", dev = "python_version >= \"3.11\""} [package.dependencies] numpy = ">=1.25" @@ -565,6 +570,7 @@ files = [ {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, ] +markers = {main = "extra == \"plot\""} [package.extras] docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] @@ -602,9 +608,10 @@ profile = ["gprof2dot (>=2022.7.29)"] name = "docutils" version = "0.21.2" description = "Docutils -- Python Documentation Utilities" -optional = false +optional = true python-versions = ">=3.9" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, @@ -703,6 +710,7 @@ files = [ {file = "fonttools-4.61.0-py3-none-any.whl", hash = "sha256:276f14c560e6f98d24ef7f5f44438e55ff5a67f78fa85236b218462c9f5d0635"}, {file = "fonttools-4.61.0.tar.gz", hash = "sha256:ec520a1f0c7758d7a858a00f090c1745f6cde6a7c5e76fb70ea4044a15f712e7"}, ] +markers = {main = "extra == \"plot\""} [package.extras] all = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\"", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.45.0)", "unicodedata2 (>=17.0.0) ; python_version <= \"3.14\"", "xattr ; sys_platform == \"darwin\"", "zopfli (>=0.1.4)"] @@ -721,9 +729,10 @@ woff = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "bro name = "idna" version = "3.15" description = "Internationalized Domain Names in Applications (IDNA)" -optional = false +optional = true python-versions = ">=3.8" -groups = ["dev", "docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "idna-3.15-py3-none-any.whl", hash = "sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8"}, {file = "idna-3.15.tar.gz", hash = "sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc"}, @@ -736,9 +745,10 @@ all = ["mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] name = "imagesize" version = "1.4.1" description = "Getting image size from png/jpeg/jpeg2000/gif file" -optional = false +optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, @@ -885,9 +895,10 @@ testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"] name = "jinja2" version = "3.1.6" description = "A very fast and expressive template engine." -optional = false +optional = true python-versions = ">=3.7" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, @@ -1009,14 +1020,16 @@ files = [ {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:fb940820c63a9590d31d88b815e7a3aa5915cad3ce735ab45f0c730b39547de1"}, {file = "kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d"}, ] +markers = {main = "extra == \"plot\""} [[package]] name = "markupsafe" version = "3.0.3" description = "Safely add untrusted strings to HTML/XML markup." -optional = false +optional = true python-versions = ">=3.9" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, @@ -1173,6 +1186,7 @@ files = [ {file = "matplotlib-3.10.7-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3886e47f64611046bc1db523a09dd0a0a6bed6081e6f90e13806dd1d1d1b5e91"}, {file = "matplotlib-3.10.7.tar.gz", hash = "sha256:a06ba7e2a2ef9131c79c49e63dad355d2d878413a0376c1727c8b9335ff731c7"}, ] +markers = {main = "extra == \"plot\""} [package.dependencies] contourpy = ">=1.0.1" @@ -1362,11 +1376,12 @@ version = "25.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" -groups = ["main", "dev", "docs", "test"] +groups = ["main", "dev", "test"] files = [ {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, ] +markers = {main = "extra == \"plot\" or extra == \"docs\""} [[package]] name = "parso" @@ -1512,6 +1527,7 @@ files = [ {file = "pillow-12.2.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bfa9c230d2fe991bed5318a5f119bd6780cda2915cca595393649fc118ab895e"}, {file = "pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5"}, ] +markers = {main = "extra == \"plot\""} [package.extras] docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] @@ -1603,11 +1619,12 @@ version = "2.20.0" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.9" -groups = ["docs", "test"] +groups = ["main", "test"] files = [ {file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"}, {file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"}, ] +markers = {main = "extra == \"docs\""} [package.extras] windows-terminal = ["colorama (>=0.4.6)"] @@ -1629,8 +1646,8 @@ astroid = ">=4.0.1,<=4.1.dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, - {version = ">=0.3.6", markers = "python_version == \"3.11\""}, ] isort = ">=5,<5.13 || >5.13,<8" mccabe = ">=0.6,<0.8" @@ -1653,6 +1670,7 @@ files = [ {file = "pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e"}, {file = "pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6"}, ] +markers = {main = "extra == \"plot\""} [package.extras] diagrams = ["jinja2", "railroad-diagrams"] @@ -1745,6 +1763,7 @@ files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] +markers = {main = "extra == \"plot\""} [package.dependencies] six = ">=1.5" @@ -1764,13 +1783,98 @@ files = [ [package.extras] dev = ["black", "build", "mypy", "pytest", "pytest-cov", "setuptools", "tox", "twine", "wheel"] +[[package]] +name = "pyyaml" +version = "6.0.3" +description = "YAML parser and emitter for Python" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"docs\"" +files = [ + {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, + {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, + {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, + {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, + {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, + {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, + {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, + {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, + {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, + {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, + {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, + {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, + {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, +] + [[package]] name = "requests" version = "2.33.0" description = "Python HTTP for Humans." -optional = false +optional = true python-versions = ">=3.10" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "requests-2.33.0-py3-none-any.whl", hash = "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b"}, {file = "requests-2.33.0.tar.gz", hash = "sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652"}, @@ -1862,14 +1966,16 @@ files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] +markers = {main = "extra == \"plot\""} [[package]] name = "snowballstemmer" version = "3.0.1" description = "This package provides 32 stemmers for 30 languages generated from Snowball algorithms." -optional = false +optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064"}, {file = "snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895"}, @@ -1879,9 +1985,10 @@ files = [ name = "sphinx" version = "8.1.3" description = "Python documentation generator" -optional = false +optional = true python-versions = ">=3.10" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2"}, {file = "sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927"}, @@ -1911,13 +2018,36 @@ docs = ["sphinxcontrib-websupport"] lint = ["flake8 (>=6.0)", "mypy (==1.11.1)", "pyright (==1.1.384)", "pytest (>=6.0)", "ruff (==0.6.9)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-Pillow (==10.2.0.20240822)", "types-Pygments (==2.18.0.20240506)", "types-colorama (==0.4.15.20240311)", "types-defusedxml (==0.7.0.20240218)", "types-docutils (==0.21.0.20241005)", "types-requests (==2.32.0.20240914)", "types-urllib3 (==1.26.25.14)"] test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] +[[package]] +name = "sphinx-autoapi" +version = "3.6.0" +description = "Sphinx API documentation generator" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"docs\"" +files = [ + {file = "sphinx_autoapi-3.6.0-py3-none-any.whl", hash = "sha256:f3b66714493cab140b0e896d33ce7137654a16ac1edb6563edcbd47bf975f711"}, + {file = "sphinx_autoapi-3.6.0.tar.gz", hash = "sha256:c685f274e41d0842ae7e199460c322c4bd7fec816ccc2da8d806094b4f64af06"}, +] + +[package.dependencies] +astroid = [ + {version = ">=2.7", markers = "python_version < \"3.12\""}, + {version = ">=3", markers = "python_version >= \"3.12\""}, +] +Jinja2 = "*" +PyYAML = "*" +sphinx = ">=7.4.0" + [[package]] name = "sphinx-autodoc-typehints" version = "3.0.1" description = "Type hints (PEP 484) support for the Sphinx autodoc extension" -optional = false +optional = true python-versions = ">=3.10" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "sphinx_autodoc_typehints-3.0.1-py3-none-any.whl", hash = "sha256:4b64b676a14b5b79cefb6628a6dc8070e320d4963e8ff640a2f3e9390ae9045a"}, {file = "sphinx_autodoc_typehints-3.0.1.tar.gz", hash = "sha256:b9b40dd15dee54f6f810c924f863f9cf1c54f9f3265c495140ea01be7f44fa55"}, @@ -1930,13 +2060,35 @@ sphinx = ">=8.1.3" docs = ["furo (>=2024.8.6)"] testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "defusedxml (>=0.7.1)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "sphobjinv (>=2.3.1.2)", "typing-extensions (>=4.12.2)"] +[[package]] +name = "sphinx-rtd-theme" +version = "3.1.0" +description = "Read the Docs theme for Sphinx" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"docs\"" +files = [ + {file = "sphinx_rtd_theme-3.1.0-py2.py3-none-any.whl", hash = "sha256:1785824ae8e6632060490f67cf3a72d404a85d2d9fc26bce3619944de5682b89"}, + {file = "sphinx_rtd_theme-3.1.0.tar.gz", hash = "sha256:b44276f2c276e909239a4f6c955aa667aaafeb78597923b1c60babc76db78e4c"}, +] + +[package.dependencies] +docutils = ">0.18,<0.23" +sphinx = ">=6,<10" +sphinxcontrib-jquery = ">=4,<5" + +[package.extras] +dev = ["bump2version", "transifex-client", "twine", "wheel"] + [[package]] name = "sphinxcontrib-applehelp" version = "2.0.0" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" -optional = false +optional = true python-versions = ">=3.9" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, @@ -1951,9 +2103,10 @@ test = ["pytest"] name = "sphinxcontrib-devhelp" version = "2.0.0" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" -optional = false +optional = true python-versions = ">=3.9" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, @@ -1968,9 +2121,10 @@ test = ["pytest"] name = "sphinxcontrib-htmlhelp" version = "2.1.0" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" -optional = false +optional = true python-versions = ">=3.9" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, @@ -1981,13 +2135,30 @@ lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["html5lib", "pytest"] +[[package]] +name = "sphinxcontrib-jquery" +version = "4.1" +description = "Extension to include jQuery on newer Sphinx releases" +optional = true +python-versions = ">=2.7" +groups = ["main"] +markers = "extra == \"docs\"" +files = [ + {file = "sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a"}, + {file = "sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"}, +] + +[package.dependencies] +Sphinx = ">=1.8" + [[package]] name = "sphinxcontrib-jsmath" version = "1.0.1" description = "A sphinx extension which renders display math in HTML via JavaScript" -optional = false +optional = true python-versions = ">=3.5" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, @@ -2000,9 +2171,10 @@ test = ["flake8", "mypy", "pytest"] name = "sphinxcontrib-qthelp" version = "2.0.0" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" -optional = false +optional = true python-versions = ">=3.9" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, @@ -2017,9 +2189,10 @@ test = ["defusedxml (>=0.7.1)", "pytest"] name = "sphinxcontrib-serializinghtml" version = "2.0.0" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" -optional = false +optional = true python-versions = ">=3.9" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, @@ -2068,8 +2241,7 @@ version = "2.3.0" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" -groups = ["docs", "test"] -markers = "python_version == \"3.10\"" +groups = ["main", "test"] files = [ {file = "tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45"}, {file = "tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba"}, @@ -2114,6 +2286,7 @@ files = [ {file = "tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b"}, {file = "tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549"}, ] +markers = {main = "extra == \"docs\" and python_version == \"3.10\"", test = "python_version == \"3.10\""} [[package]] name = "tomlkit" @@ -2149,19 +2322,21 @@ version = "4.15.0" description = "Backported and Experimental Type Hints for Python 3.9+" optional = false python-versions = ">=3.9" -groups = ["test"] +groups = ["main", "test"] files = [ {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, ] +markers = {main = "extra == \"docs\" and python_version == \"3.10\""} [[package]] name = "urllib3" version = "2.7.0" description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false +optional = true python-versions = ">=3.10" -groups = ["docs"] +groups = ["main"] +markers = "extra == \"docs\"" files = [ {file = "urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897"}, {file = "urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c"}, @@ -2186,9 +2361,10 @@ files = [ ] [extras] +docs = ["sphinx", "sphinx-autoapi", "sphinx-autodoc-typehints", "sphinx-rtd-theme"] plot = ["matplotlib"] [metadata] lock-version = "2.1" python-versions = ">=3.10" -content-hash = "87a9ed1ffb1f3f518a442609a884b7d48039a9c5ea7b1a310e3d5431b15999fe" +content-hash = "8f394b3ef9613f8640270c3afc07a72b275f81d6d8d929596c473f8577fe6549" diff --git a/pyproject.toml b/pyproject.toml index d6e721d..dae71e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "anastruct" -version = "1.6.2" +version = "1.7.0" authors = ["Ritchie Vink "] maintainers = ["Brooks Smith "] description = "Finite element analysis of 2D structures" From 57b48bf5e0be5ebae286ae912c86f4d72bbd7fae Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Sat, 6 Jun 2026 16:21:58 +1000 Subject: [PATCH 14/18] Add documentation for beam and truss preprocessor --- .../preprocessing_beams/four_span_beam.png | Bin 0 -> 9776 bytes .../left_cantilever_beam.png | Bin 0 -> 9096 bytes .../preprocessing_beams/left_propped_beam.png | Bin 0 -> 8579 bytes .../preprocessing_beams/multi_span_beam.png | Bin 0 -> 8036 bytes .../right_cantilever_beam.png | Bin 0 -> 9091 bytes .../right_propped_beam.png | Bin 0 -> 8555 bytes .../img/preprocessing_beams/simple_beam.png | Bin 0 -> 6823 bytes .../preprocessing_beams/three_span_beam.png | Bin 0 -> 7863 bytes .../img/preprocessing_beams/two_span_beam.png | Bin 0 -> 9859 bytes .../attic_roof_truss.png | Bin 0 -> 20134 bytes .../double_fink_roof_truss.png | Bin 0 -> 31180 bytes .../double_howe_roof_truss.png | Bin 0 -> 27900 bytes .../preprocessing_trusses/fan_roof_truss.png | Bin 0 -> 32551 bytes .../preprocessing_trusses/fink_roof_truss.png | Bin 0 -> 29206 bytes .../preprocessing_trusses/howe_flat_truss.png | Bin 0 -> 22623 bytes .../preprocessing_trusses/howe_roof_truss.png | Bin 0 -> 26697 bytes .../king_post_roof_truss.png | Bin 0 -> 23033 bytes .../modified_fan_roof_truss.png | Bin 0 -> 29854 bytes .../modified_queen_post_roof_truss.png | Bin 0 -> 29926 bytes .../pratt_flat_truss.png | Bin 0 -> 21251 bytes .../pratt_roof_truss.png | Bin 0 -> 28202 bytes .../queen_post_roof_truss.png | Bin 0 -> 25855 bytes .../warren_flat_truss.png | Bin 0 -> 21615 bytes docs/source/index.rst | 4 + docs/source/preprocessing_beams.rst | 191 ++++++++++++ docs/source/preprocessing_trusses.rst | 286 ++++++++++++++++++ 26 files changed, 481 insertions(+) create mode 100644 docs/source/img/preprocessing_beams/four_span_beam.png create mode 100644 docs/source/img/preprocessing_beams/left_cantilever_beam.png create mode 100644 docs/source/img/preprocessing_beams/left_propped_beam.png create mode 100644 docs/source/img/preprocessing_beams/multi_span_beam.png create mode 100644 docs/source/img/preprocessing_beams/right_cantilever_beam.png create mode 100644 docs/source/img/preprocessing_beams/right_propped_beam.png create mode 100644 docs/source/img/preprocessing_beams/simple_beam.png create mode 100644 docs/source/img/preprocessing_beams/three_span_beam.png create mode 100644 docs/source/img/preprocessing_beams/two_span_beam.png create mode 100644 docs/source/img/preprocessing_trusses/attic_roof_truss.png create mode 100644 docs/source/img/preprocessing_trusses/double_fink_roof_truss.png create mode 100644 docs/source/img/preprocessing_trusses/double_howe_roof_truss.png create mode 100644 docs/source/img/preprocessing_trusses/fan_roof_truss.png create mode 100644 docs/source/img/preprocessing_trusses/fink_roof_truss.png create mode 100644 docs/source/img/preprocessing_trusses/howe_flat_truss.png create mode 100644 docs/source/img/preprocessing_trusses/howe_roof_truss.png create mode 100644 docs/source/img/preprocessing_trusses/king_post_roof_truss.png create mode 100644 docs/source/img/preprocessing_trusses/modified_fan_roof_truss.png create mode 100644 docs/source/img/preprocessing_trusses/modified_queen_post_roof_truss.png create mode 100644 docs/source/img/preprocessing_trusses/pratt_flat_truss.png create mode 100644 docs/source/img/preprocessing_trusses/pratt_roof_truss.png create mode 100644 docs/source/img/preprocessing_trusses/queen_post_roof_truss.png create mode 100644 docs/source/img/preprocessing_trusses/warren_flat_truss.png create mode 100644 docs/source/preprocessing_beams.rst create mode 100644 docs/source/preprocessing_trusses.rst diff --git a/docs/source/img/preprocessing_beams/four_span_beam.png b/docs/source/img/preprocessing_beams/four_span_beam.png new file mode 100644 index 0000000000000000000000000000000000000000..465dbffc3608b073b43798299ac2fb461f429730 GIT binary patch literal 9776 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 I?A2TU2U7Jb+5i9m literal 0 HcmV?d00001 diff --git a/docs/source/img/preprocessing_beams/left_cantilever_beam.png b/docs/source/img/preprocessing_beams/left_cantilever_beam.png new file mode 100644 index 0000000000000000000000000000000000000000..44bea53c4be8823244901be56443c92229fba457 GIT binary patch literal 9096 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 R4g3UUxyNdE!FNCW_@7YTATs~} literal 0 HcmV?d00001 diff --git a/docs/source/img/preprocessing_beams/left_propped_beam.png b/docs/source/img/preprocessing_beams/left_propped_beam.png new file mode 100644 index 0000000000000000000000000000000000000000..eec053dfdd81acd1facaa628db1102c746b7e778 GIT binary patch literal 8579 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 literal 0 HcmV?d00001 diff --git a/docs/source/img/preprocessing_beams/multi_span_beam.png b/docs/source/img/preprocessing_beams/multi_span_beam.png new file mode 100644 index 0000000000000000000000000000000000000000..3c59b43741d506f8c993f8afecc51f384b34874d GIT binary patch literal 8036 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 literal 0 HcmV?d00001 diff --git a/docs/source/img/preprocessing_beams/right_cantilever_beam.png b/docs/source/img/preprocessing_beams/right_cantilever_beam.png new file mode 100644 index 0000000000000000000000000000000000000000..cbb2844f70da5da47fc0ac42fc6b906975108630 GIT binary patch literal 9091 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 E0H2y45C8xG literal 0 HcmV?d00001 diff --git a/docs/source/img/preprocessing_beams/two_span_beam.png b/docs/source/img/preprocessing_beams/two_span_beam.png new file mode 100644 index 0000000000000000000000000000000000000000..22c180501d4ed716e13eed9c896a779431e82b0e GIT binary patch literal 9859 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 X%GmUdn&1U92plu9#N-_Q?fSm~h&s5> literal 0 HcmV?d00001 diff --git a/docs/source/img/preprocessing_trusses/attic_roof_truss.png b/docs/source/img/preprocessing_trusses/attic_roof_truss.png new file mode 100644 index 0000000000000000000000000000000000000000..c0419d05c024f4207363caf73c713ca5b1dbcb6c GIT binary patch literal 20134 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 literal 0 HcmV?d00001 diff --git a/docs/source/img/preprocessing_trusses/double_fink_roof_truss.png b/docs/source/img/preprocessing_trusses/double_fink_roof_truss.png new file mode 100644 index 0000000000000000000000000000000000000000..d26545c05af0d2803555b61046cd27797a78042c GIT binary patch literal 31180 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≺sd0~m=bB1A>z14Qt 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 literal 0 HcmV?d00001 diff --git a/docs/source/img/preprocessing_trusses/fan_roof_truss.png b/docs/source/img/preprocessing_trusses/fan_roof_truss.png new file mode 100644 index 0000000000000000000000000000000000000000..41ef7501ddf117c491c3946baad975310e4389ce GIT binary patch literal 32551 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 MY_>AtY@$c~19gP;djJ3c literal 0 HcmV?d00001 diff --git a/docs/source/img/preprocessing_trusses/fink_roof_truss.png b/docs/source/img/preprocessing_trusses/fink_roof_truss.png new file mode 100644 index 0000000000000000000000000000000000000000..98ababa2f00dd5c02f5282ac9e03fe2cb9b8b18a GIT binary patch literal 29206 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%0D6&iiWEB#3eb28w}2j>vG0ws zqM^KS#1XGR4!Xdlr=wx0UQ6f4FpU1VQ4<1_9mSb1_(F&r3~{q3tjR6WMQG{S|G*-}@^s~2war3=03 z`VkZZ(g}RJZ6CoU2glrD%)^)_Sg0@%nU=w@jZqIf+#B77w1-@hbiW_loDlJWAgilC z`@^vYN(XXAK}aP#G4}fs=(h!eqikQ1l2J9dvK{7qHB1N;F-<29cuCEO=r&H z_J2499r4RajA7Bl1x{085Tz^8iL6Yk4PJFPKvEb5_P!&C=%M;SqCG{NpFMUL6LZY%s?{rMl{9$>UXj zo5<#BRgJ3LAUQVg!$52B#SESM~BjMp!X|UY6prgN?;}ekdSrk`Z zT`xU8-R`Dj$F#&Jn0epJ)!&8tiBFIrtW{W zZVP!?tGZTPK)pOWaxKBu2>twnq;J~hhi-WttBYT?z>^R0R0y|UVVE)o3lP+o5zyc; zMW3B+K!Lqh(>y?c=Q!KNtpYP(A%n0ggzKh80X5noUH#sAupJx_soC>FSa0l3HI0dTtR39xMH zy7M2n*Z(7Mjn_qB^Pb_dXC-J^H0VGU;4z6NFElRA-vvCX!_(V)F>v+{xQgh3d4IL+ z`TH^pmpGRJPdO}snnd|c8DJmP42;YC;Ri@=k( z>i&Fm2i6iZ4U^eGll!29WPr=A9Nnkz%?1`hZooY@pw0Ue^(BGLl}A7~FgyV6wOkJD z^Z`%(m;h|*6@!jFUmdOwnymy5wXX!OLp&%e0XJs7xzS7O=JMc>2Ue*})vUIuQB z0i6*BS`Y`E0SE2Y0;M%zY%c@eg=XldBMaJO(GR?$;orl@``2mh>3i;vXbWV6$0-Po zdHkt=dt)Q;GDU_13iYoI-{|+W2!VLr0Zc$LLC_1t(Q)Dgk`1mJj6iAwhbl-+Y#|Gf iJfH-;;gNwM0;0*A<@qxAyz0lHATdu@KbLh*2~7Y!xeBrX literal 0 HcmV?d00001 diff --git a/docs/source/img/preprocessing_trusses/howe_flat_truss.png b/docs/source/img/preprocessing_trusses/howe_flat_truss.png new file mode 100644 index 0000000000000000000000000000000000000000..798f4e733e5bf1e26eacf4387c5706484126f6a1 GIT binary patch literal 22623 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 D-sWkg literal 0 HcmV?d00001 diff --git a/docs/source/img/preprocessing_trusses/modified_fan_roof_truss.png b/docs/source/img/preprocessing_trusses/modified_fan_roof_truss.png new file mode 100644 index 0000000000000000000000000000000000000000..c315727afd2975815db59ac2d4cfb85c76c358c6 GIT binary patch literal 29854 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℞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 literal 0 HcmV?d00001 diff --git a/docs/source/img/preprocessing_trusses/pratt_flat_truss.png b/docs/source/img/preprocessing_trusses/pratt_flat_truss.png new file mode 100644 index 0000000000000000000000000000000000000000..a5fd87ebec87b36b6a0301d3ca4c097bf0419992 GIT binary patch literal 21251 zcmeIaXH-?$wl2EVGJ#4N5J3?GsDK2OAV@NS3y_?n0m+hsWXc=?mk0<5k~65}j9L~b z0+L0NC`b}eqU84taGzc0-QCW;x82k3dq4JSZMRL~VumsM=)HfT&s$0gGHdBr=qMD* zTI#72Diq3Z{uIiR@>MJFn=sjzCHOxnhm%?ks@BF1&S&i|P)?t9u(7muurxcj!|8&Z zy_vPuA>IT0yu#c@#`Y!$_U|xtaImo#<>R~fAK&A(wlm?os?QLIW39G1rEO24Y;Yj| zTheCCc8Nk!F{7S1s&*-Kpw-R2YHWV~$F$pCqXTgwci#I5nb7Pj*Kc5>xj*y`at}Rz zZqKdgXn7V7j{C=G{@XM=H`#yqQOmVKq*LtOhqhwLnejOt`wtdbjpc3m`h0={K#a3T2ko#fT{^`m#eHL2B$zrFtZz9kDkmHfVxWARs8 zjy?Hp@u%afusY;(X4M}X7Jpi^Q)%hKPu@F!lU@83|DP3oO9x-)+IMeaW=^=x$ek$l z$5M^JWefl6w^zT=Rb9qsn{v8wMQ2x+V`FJ|uN3FOgDU!Y4$tz|EFL26sd+t@<6z5V zs_!9jrQ5e}t7vHjISqV_vG1--P>GRs{rbp6z`Sms`1g`!*L~EVojXYtp8H^4pV%dx zyLbczz5@r8aY$Pu9_RDsPd07cnk0RX({KT6#Z*-oWyOyYt!bLT2dLA=3)z9bg zv*U)S+juf=(%6`~_&5Azb?R*`t*so?lXo^(JZ&v6m*eH-9sd5EKYiQcH;k?%{Grlb zXx^Z?(V{@}^TU(oP0R6%ly>&}1jRO`B>ut#|sKlk28hY;BIe&c4PLB^Xb5I$%)c(Fa zs%_WTZjI&D&x?2LZ(xyd&yfw-pTK&=spp<>n_qEp@yBdyYh#hcTP$0lDzi^~vh%^m z9NVbdn>ZsQj^9Ycg-`wb;yd>F4qx95Hc!7BH*P%YTKxWwt@5l9>{K3|45d4pdER;I zEdILlcO2%|5)bYEAA|bpf9DSQ_rWOt+gatGYo@hf-^JEEbyiUarDx|}tHmqrR8KR| zPb(Y`W{g>Um?b-e)5C4B%lm5Md|gL-BCr+T)YhsN&rK!yupTjX;{1=;Sr!u|<7-~x zy~Op$YbM6++Xp|iMV_QTRQ~Hg;{1+pn`b6R9D8dx?lB+w>s{RPg@2J+cTiAis^bQm zTEQjT*QKRN#udSK_Vy35v$I#M+ZIpH#M@%q{$Q^n*PcClUMZeC7fF4%xB+%N?p1B$ zH7rUVY|Xc5$*~O_+i)RHt(ta7bSow}LlJQQ|T7w61#=%qDZ zSUm5iJ+TTd+{%$x*%K}{XEA4GTelm~GMtCnng{y_22#Aez1K+AC#shho?F}mHgeei zM~@!OZn4U4w%+vRocTZZ+s06<);ub$Xm-4LO><+aJ~!3;!_$brZLooey4cfONz%a* zXyCG0ge>F3z2>yfo;}<5;aL=mu$ARM_it@?5RYz_{HyD0Yq3}3kq|5fTXM;^58yMj z`rEUT*+*50ICf3o;zxngAwm`3;z*fBgzfayl$5Oe64D=dk~&fRd=|XgmsZ3@V$p_TpoutikVD4%<8l7P^?&kfN*m&)@G? z(kZy~Y}fAH*sxaWzgm~F6~f$Mqn&RaAlQOXt77RGxr|)GRpS&cdccatk{Xg>(hO_T-(%ugB}<+KD<3hO%>VaGaz$47P~m z=I1Bbbi8~tJ~locfc)^NYw^B6ZI-|Ic6OrOtN+hi8-qpcW6?!?{i&VjkbuG$eeU(` z1nf@ZfM31W6;v&?Sb64)Z3QB=<7Tz7q-SdPoK8V$H2YicA(e3E#bxuh0+-kUBq9H# zq<)^EUlo1!bseYmuUniRyd!0XE<;vU_W3`$E~6J7>;Iz!?)Y~J{O{<6|2OhQtS(}j zOFfZYQ&TfHC#TFf{Y`znx`BZKi=er`imGY~?|O>O%7lc3;DZ-#|e1 zs(*w&X*s2Hk8lzizQe_Jb!zGfDkssDqeXuDbcSQkoXUNy?%RLaCS3aHkjd!#;|$oD9IwV-UZYRK@e&OR^S(Ld zfByV=bga>kTSTPkM^L&+RU+0@)c)&TF)^`sysQ*IIr+8zLKi*0qkgvfn)|^#&ad|nZ(o6=Ij>gD7eEas;@+lMSioRZHA zsG=ZVzH-H}7u$HZ@ZEV9@N||`pME>#`l;xmQm(*^71N_`mox!c=klx$Z(sm8XIb#52*c6P*5OXRQCJ8hiAvp z|N9L5`0;}*7^mPeid}fZZvU_E9zEz_W2Bllran$oPl`=YjZ3^x9zcLV*@Y^}dH3t< zmmm<;uB=!)m}dx7m*GBXH#s>eGS0?-M(R3)0EJ@jFw`dgYCutPR_!6TW>LQ>+s?yP~4vtc$?S5X6 z=IiSl=Gwy$ z0q4ZzNOvYOalVg&sLQZX?Df=Jw{GQXvrs;5Z*8$g^SGT0@fI-~?lG>NqV?>h?ew$K z?W*^8owQ4qFls1pu}_jK8@W3^+94>+l$Lz}`;6I2a{62P^>JrgTjim)LP5`&OVmhC zQOe=<<;!ATTv^#)6C>y2Wn{HiOiT|A(;oHZl(N;rUQc;dWAAp%&gUwssnv-$UOjT2 z>-OZOii+3$9@esfycaKpf76>^LYa`1TNXpMaIK)A0% zN#WBbOCP0PJO_b-dC7?c^`yc|DE%T=S!y|A$2H5h7n7#tjYHuz(8l+0ST z-A5X|C?&I1#@VK`bx)u2pAHtFrWMcS8Mt&kv}E1AXOHwBfBbRV$45g-N@|_vDoT## zH9AHWJGm(f{Af@(;9IJPEIQD zW@U`|@Jc48!2ODD=}ngMOY&B7a&lgetI-*45LV2e6jjN#(noM}mp29=|4jb;+0$s~ z^^iR`FRyQEtUp&}FXdC)mI^JD*T=l#^1%XTDp{}Caph@-#hyOxis2F|c%~*U?aNlK zGg|e4OC$MIkkMstZ%T?m;m5v%-uWL3T+*>YQ+Rh9#;YdAvE5hX6a8Y?6pYv5J ztqu{rEoCj`3@ciNMgzCg5B8j{NlGh9L>r$TzMXO=^6abY7jndn-)*`0;b}+eG_o-J zD?00J(amOrSbmC=q&Bw$jxtv*3@?c@dM#Z5;*C%O~S5+z2#-1*Js>3!|+1jcv6vFeWs=}&maB$E{`Jsy<()G(%ue#7h zAt}nyA~-W>Kjztn^N~HxKb8FPXzARSQr{$WSiuL*OUJ4Q#ccHm*rOPhyytXqPfM;n z^Pojd^et)M?J3dG(JlK~DQA|dy6qFRZkzGBxA9)UF$NAw&b;M^r$=}0+&R@1Xt=Fe zOkCW0vLk}}U=JM~9SsF+9h*e*P|y}+!#sGz_VZP8Qbmc$Kc7{!w;KXz2^=a~>Fioz>+ClEt@_E)DQe5 zRqLlqm(%s2{`fS5-*}%tRFs6TZx~%t;_-v`bP_lB!~9nGC>~3Tmbg(Xm;{Q?)-T`I!;DD1F=_Mu$NLZ zEgH?ozcrEGBLnd+e^zC3xQmpvf#z&QUx}&s=&jtvU~o=@x~a1+o;9vyTS+NX4iM;C zK{@Q(-FVjEKRlaO2rK^QVi^Dm(cdVwkRwrtL{2*k>#;ST#yZ)wrM)SRfbyQS}z zjs9`IAz52iK|#aFD0=DAr3aHgB0s9-IhYkrw7JQiK3&fsIpb$0t9xS|>n5zyk1wU= z*r87O;>Q&krSre;2Q6@q^@zr^XV3cT5*|cv^+;W@mL*z-%|lIDS$VVODieP{zbClD zBosDL?1<>CsvpLO+S5>^Sq4L{=Ia)^X5zd89#anb#h&^gFiD^wHPvHx%d6H9##BGw z>2$dJ@Ga!epa`a*3S(992WU(T7y7GF?cTqbR?JRMXu7)>oacDo*=bZb)t5w82H4DQ zo?!*0a}_9N@3SUVVfEN_bx+S8mx=%W{S|`+a=T8EdoGt+yiMsW+Lpwg9#j27*ZS(f zH~=3}&zT$p*WQ>TgVQJ{rf>Z@MQuKLBi46PQJ|xzMth^cqJ*l4+Z{#AmFYTWo}!ca z_P}dXFcpcq*{Rppu_gio}5)d;nKHji5+&vQ9f=KL{UEM9_ z>ZPt@eP;N(U~#vs+nae@OBc%g?2l45St|974UeL{eBA>@371k2xrbaa2>DZzb3db& zE?dUYx@sev*NpAvGZb&J%is?EF7)2h@$m2%d$E$O%qqM5)vMzh_sAPP~ zz_B$=;{)04T>Sh>gw&Oly=^HJLZ0`}pO?hZX$V}bJc|MvEa8ziGdoKbgetsQY!w4T zBd8YjI0e>PbF-G5XXAsdNz8|gDXsvyjx>E-J9bEsjoK?Hl8>I-;$wyx z?l>Hvo{KsKgk6_zqL_KHS?E=tXG!Y}%AD&|Z(M!E@s%>?zoK+mp!cL>V9*59w?Fm$ zoA6z@ z_Ll0d@<8nJ9Qk`Xf%~;1$NC$~OG`^X({b?e@fFU`P2+5VUqZ%?-&mJ`B;eYY5a-ZY zw*C&cgT#_0OFlloaAz~GUObIMPL@XUKuL+zwd>c7b)GTgG$9cR*ngFuoSHI!eVdUM zz3b%d9_&>6QRCy43o$u9ko2`8gj+~RgVx#I9S54t|~W@QA_@=I-Hvav(s7 zdT||ZGC}6zCR=ry0%5D9!_&OZH4TY{bT$@W{<`O5<^pVMj(#P~YtH4dsN-95d=QqI z=oD~`atsnbpRk*u`jKjOWT+qt#Z6alXR;sQ^K$ylWJ%~Z@AqS8+@~Z3O0)s{1}!8v zi7nK$_wOT)t1tGnay9pQjlksAplx8SeKUMHgz3z8@J8(DC~hs^Lir>ig%$O4@Dehw zSPj;+4vQdo;q4~I{aQ-2(c<~(VqAgxi4#|AYHF}wa&vNX&3fKP+`e;1)pxr%I~5<6 z1Lv-iz`+B=CBAd`RI-HBR;21i)HDt%vahPV{M|kBK~K=XXz4}RKWiS)$+CQe2oQ7| zw~UF2c~enwny+}~IZ$&QI@u(-cLAfzw_q!7+OXl}LePRf@^&B8SV(z8Nzy43LtwF69I8#EwhSZv#7|PB$)~#CP?m~#*{)QA)G&<~5{9ZFk`X2e(V-fqm zKGWR~q0wkW_yZ52D>*xg%GUiSG_6dh0Uh-e9TGlOxUNVvPl@)1U75?L)cd9y@*X4O34Ln!wFLZ^lNA$Q9y<8RaZhq{gYDMdJ zOZT8qZ`SN_M-GdEOoxD=`c&^*zkdDjj~~@IxLIny5y%AWXHN876`>-kfP0Ae`kU)_ zle~ly-|Ad3Gm?jDNYIm@dEI*iEyn`P$KNwTFhyRu!~M=>tgpVd^6`Ii0|lZmtJBCM;$UZww{9;|U~K~sGe<8bd+OBt zLseqCd;eOx1~^#*fkhJi9q!*K-7<*c$ueL)0m~2k^(nfVN1O-!9io)`0}VYB06vmH z?QGUG-3~xs5p>`ljzjx5HCn59h^ORzj_rBz`I(Wa>7imCsH~w(NEn^VgoVvL(4HR>G#{vm zxufd!z+*3Yw&>EHkfwk`*58kve1UG&s`u!=S=*;}n|wgQ?5RFZ3ML3^a99qrQ;y_j zK|xFnm-8|247g$0lB4|M#fxD6vzMX#a8QBQ3$V>bU()lHy}p(mEYgecArcby=Gbc{ z!&9{F?%$7+jD*LQj^mozUTes0UAjg>LLykwOM;%CBE|d3(1l`SS3EO(2U)ed?w-yN zK{7Z{+|{eUf!#5zxu?t&5fPE79CcmD^1~V1Yn5>bLD%lb&KV|E+e>eJ+AZVLlMolC z5~uKZ6bpegGS~^CkI3>QtsxRl<*lzow5ucQDM5$hLFu+^FVY7XsQ=#aiZyDIsB!>G zYgt9rfS&NE3!8aLz7KiLhakdtFhQ#Eevp@|+z-^s_hxcyW?Rw*4%vOXb{#{xvX`$# z%`mLXbF{!Vkwb@&PSQuZ@o7j~r$@e4sG?h7r;@ING_fdFG11ZJ_pAbfgA;K;L#zgA z=h+j`>$vu(WG~#-sB&lMC?n@qLG#X4C(vXh;$qF3o?qZHEGl@-*ydHkbVlphx#bH> zNcxGr{^46Qzg|V%Gy`TKI|Bffg9;w#ADI%Zb1PC37WdAIHCvvbsE!RZYtkIL-ZGND z4iA{$kTFA^7vs6#vf9Ow@&keI#38|+fc-f2HN-mO+-o}Z zWUXpa|8Q<1&3MjEi3H1LTea$-MuKdiMald=SP8Y&x^Qgs!fFvMVXt3Xe0^0_Rdswl z{%NRSM4`wUMHW5&6TYIK$3TA8!;!I{O3WT8tb*w29*esz)NzmynQ$PS4wukp5c}@U z-V0{yA=Uxx1L!Gp+iR0oTCEy!hpcI^w*=Fe7FWS=VGG1Y^VK(k7Ybo~D5C=%7{^`kpYKsErj z$b#{79jOp@L~4L0U`k54udgObc~D~LGQxW&{T|C#;ujj4d~4(0=agj>qh%x^DVtP= zR^Q<(BAS{RIzXD0fcflT{?I7;>)LohrcGRGr$`@y3mSt@LXM^oCYFG{UV+#mz!Z?A zcw@Wksb8JQ7+7;^UUhjKo;3l2xEE_=g)Wp{QqwPAzPzn42^?e!p=!4ZS^DAWkVBxA z?tQa2Tnz}y5v?>;1!V8&NR=eKD%xBs(KpF=@_9=9igs~PK2<`w*x{RtJr5OlUw&&? zgt7%TdkSxLulR7;Zk=M!!T?_V#Df>!o}v-y4`~|RUoWnKQ~^=PzGyHO_qGZvVC9K+ zkt~#jW>ETOmp6Lr!y1kGP6NS!C4i0`2>5Gkh;Xqk zBVT(-_lXBUFh{G|lIwuozP*_g8zxeEZ~O_K06eLHc_9PI;@_H7NfyV#{L11erKd?2 zM};DnF9w@Zu&84qLD(Ros5FJp!x3$TZb^ti6v?MKFAI7>uqa`f2rma?!zr2?a2X1w z9JrM*Q0@Cus)+QbjhsPNJXJ4u7qzcBI}LrbAZl-J&iBo&`-S;R-lymaQ)^IHN5ki5 zWRM+6DCaDj%UtR$wxdwl0;ORLQ70Rz+&>#>S{+G%EiqOh#HlpGrvU(~08%u7q$ElE zC%OhCRKg@718`6YM#bYMpt*FVL(2m40p1|Z1*$I1Dzplau^ItS`dJHlhhuvcLY2ZL zJnEibki)9W(SSfnmxC*O+uYpznQkNvGOZ~Zll>(W$_k|Y5|2R;sgcSS+m)~c7g038 z&~fQx#Iu{>c7`V=8lg=&4tx|ONfC&KP^8C>U54voUr0r)zyGGcmHK*)wnl9FMAW%{ z6bvW%>TeLnux5-KHtd3YMh-y)HHaqe?(P|vew?EUOSh1xhla!aV@3j+Ay$&Y8lX^> zcyM6>A^n=x1f+)BRBFrRU#v*k(uV(luzD)le{AGcGNe{R4c%;2}Ug*Dv>k z4~}+VBeki3Ji_Ka6(VdM5FQ@R&Iv4vV5ps+shaP>1|WOrS9LH0E9djn5lEJxnRky4 zjm)lk2D;(oi4z3K0AtK^Q@OOBJ~8l`bsT6fHpICzP=M{{W?a@XA3Q-?S70@cR;^4M z{H&8{{_uSLv6f=8#GbRRFw_0HKFg}<`AGz`Yu7_fE$<~#MWi8|xQ`>nV~3F6n%4FG zMhHvrk7gjTP$>M^dl9+;$SuIqakwDz_)=3-|3OV9Y4TBpr+gut$pY$C0|a3AvJemf z2uF4aK!h}H6whEEZa%GG_%_|9eWbg2ZIx}&TN6X>7Tru5j+_hF^zFm5+qZ5hqsM`; zx`OQUzIyIgOV?nRmXE$>pmfT(A6()+Ed@pd{Nmy3HMQ~eB9|^*GKH%LJdLBfpBSux z#0`Wb%*n;IfEm$G5Qv&$SZv@cHhh!4_tT3j<{)3DCWeNzc2+m(7hF;X186fkft0=7 zAlELYXl}{^66;u`6vE*@ojfCi2z&1Od_bbrzgZe$`HS^;J zg28(dS+(TYBKKrg*VhS}_ghe(N`eXp)h;<2x*)%Pj?D{laO8S|1y6^GH65TcfrLrc zB%U#VKO8 zsT$7C&Z18i>C&L*Zz;GW?HO)Bzr%}A8h2V+;>Vx^(6F7@qUVJP4bZj7YZXop=97~@ zzfi7qbl(jEnh941P>PMbmn!Npm4Wq2BSJ#SAIng|(>H9~SdW5C`e}5757-H+B$xrE zv#YlkTdlIY*}7Q$%$X;#@{b~sB*0dI7kFPC8vea6(R5P;s=4M6|#b-xr``$-f@thtIrjq)T z;W6!0@%V@)HY0l6&Ma_)gi5IfhuYcS&rK+SPCnG6GaFbkKZk?XVfA=UyaCiH07vyG z>9quA;@mia9*SR>=ad9Xkg*nUU0t!47r}K9 z&ICrP&NikQHewxl5C?>Rr;UEP!q5ke1aLgR?#a<*cet-Mp;SbGOK7)SavkvJy;)r2 zQpylNrQ|mvRuH_&lDTUmGBtzs4s`d;3+XAoUvn^qf z*Bbwp0Dv>wEjfQ5(fgY5B^S~sDdk}MXjc16z7w}7#M@e2S~Ab?6uTv)m5PK#!jx$I zi)d)aE$Nh;Of;JW9}*KTghGzio*T7U7j_Z9!zldoRr>gX{) zJ3%lD91<3`*K!Qi;JQfCOlu%`89j?EjWnugf}WxWj605GnoC$Wi?l-NC=DZRbkt+N z`Yu<9AV4WzbGd{ov}oA>HzVeK zxMz)K_^#iZvtS0NKnxHg6-cgAdDT50a8xg_@!3`vag}V?W^hiPghS!c<}=?%Mrymm zy~6e)BuXSvQKi=9>qj*}9C{zmsQnpxA6f_(BoJ}eQN#o?;j0@Ans5+joG)ERVuF|< zkdTNVCd#6<7jcQ5#~hoe)Ag+>ojAn+c;m5AsWpHS$q<}04BdZRL*+PQ=26*0GA&BF z!KIGnk0m^GXm#+iK=3g|2TzLGYsSx>&PmI+K%9>C!jmK$9BGAs{K2&(5d21^Q+g{r zV(#A40lSC(x6I;gAYU4Q6Y;bVlM6d(wTXCT;Qr&}B4hPf5w!>Q0RsU0SJlmyq|Bhk zlQIM8TD6~0Yv`>|8U?J|#F_@2Tu?v|ZA3;#!z!P$SMrpsYz=sA_&a$Bysf!6&s6;L zGkuDFz6NeT6InqpTi1IhKffPI24+YGHV=^D(8N`K&xj1!nz@IAgBq#KZKnV!#Q_il zwDnua4*-;Go95h23+m1AT(1DF8%HEbJ@3<_)@_-#sg{FIXi2jFBEhgHGTcpUu{laESWF&BhKog zsSnUB4fHe*1Is5NHJLXgKLW2vcD-7%mNKrQ4xETuuH6MHF(Z-8bnWU@B0A>|7odTw zf#HR~hqAI$RFy{uFJw6Ms*wHV+Ie5buFGX49lkoES*iiljv``ZX@o}}XiAqsOl3ud zGuxyMURZLSd<(+8+CwgN2r_%1A`lk#sN!F8M&ht^>5oBT|fr$xE*tVSf7}8 z_wBKWKGZfGvGaf*%55xPEqj)X07pM-<~QmGLT zPd-c+qzV$l17fJ=9>WY6%#V4FNne&p`qhHwxCExBv$vPCcYgDkON7?C>pw^M7WD97 zS=EWt8XhD64lO1=gF2)_0wI&2OzS*1y7kD5&fER2)M}|BA|4XTef8?q+O9L$R-+%z z`w|LL!2DVlY7t?8K#33r2>N0k5@MVC$Z6Pj`qBSC&pQz}@?Xe%dH`G#4l_s)#KhIt zlA8|jvY$%Q6yZ{u(oK?pZYE}gcSNC`CoU;;5H_PvdmGcjiS~fH2FxVHoLdem8`)76 zDkXf=yuH$g2_sp$bPZsv63IOPgZo)Wz|i*rI-upLa4@ChRvK5m(hLp?+OmAb3NBGm z9Z-vyaM|H|2@Qv!@w=ck&A@DRXh?~IPDlN!$HgZ$?%8}!{gYHuE&iCdrjm#>}b&}vZByn8<62byBHXS!<%!& zv44;nO*_l(FKW5nL?$7&BAG)&$)IS0iR}W;6}dcHaRLcOL9^+iaTYNsPRC|H;NZh{ z#7Q2c-aG!=yP+atMb(kE?33i zEUm=Pj@)F1O6Ox>(F@ip0ZQWcx!YC|O&+~I~KFHkN za<&*W*&DB;ZP3LJ76xQbKWnno2n>mfj*b1;T@hl!2T}Tq;C>7T1Q-sDvKh4^A_j01 zl{N;Nsd`P{Ej&lyxAFLfHadGsv0U|T(O(et9cK)3Y|c*KWj^!`=t*Oq*@dogxWyiP zotvp?d~0i~c&$YfLT4Iei&btrcG>`&$LRe+(1^_Aljyik&(TvlFGwHSTw6LUF;=Ha zhERwTkklf;2h}u#!k~Wol1(taIm`_9^(7L=1z3{80dp!kuv(mX6o)bSAOUL~^n(Xz zHmq|%{9r(V5I?9d98}!EvmCDOukardG81J&1(Fmy3?~nghf!m}Ze>8Jd&sLVx-#ic z$;WVq(EhFoI6G(OaDBQC#RhQ^dUl%lmTul$<>KbnZYK%n0J4T6O2ymnVPC&ah*SJ( z;e8|~2K=5ImNd|Hk)#UXPoN>{fIF|`58X(y`-q+*0TQC96$2DE=v8lOipVSz=mXYl zQn5h7b~@ZD5g&ohz9@EZdU<&zmA_&7n~vGk=Q#S;R%=sINx>5Fs@?EP)XRO2AEO}F zCjwPtqZyrpg98}3bO3V;@=Iz5>e37i(ZxBo7-U;Lj*N=3FOa7A$*=P-ni-aZ%TzSD zG6pp}97!l3VqzJk6W*Hu5slLb8Zu@OF$=e4*Uwp$1@If^eHvDFMx((t$2DjK-nRzU z=VE7P*R99}w%}%9@YRc_%SLMu1>4n2_{EwDX9;lfWgPwf+OeZ_t5?5yDpeMF@{V1G z1m#q>@z)1n3W=S{%8EH$Xy3jvTQA63R=H%r>yThD9OdsGA6s%b20~}~4>y1mG!y2g z^HArJohsJLu4R+ZLprajW_kR$wM6uH_&i?4^9NmNY;iC6`jy~?dX7#Py>ffaDZ1yq zaGzV6&O@h81U>fg>Depnz2N3WG`3P&-qlI^~e**FVl?J&1W)VNtu8z%M-BNgWw!_KDmX@1)sj#Bd!qXb0_u3)* zk?Czyy-Uh?Ff>9NJghgOFoB9|6wDPE6ci6DO{ba}B~%Zr{I=qGNE=A@uCePMINQOR zDiZ|uB+@PaYfz406dP9$r~MF2jitnXXg%^HxH}cut`9KJrx_{VhnZFTY<4pv6H|B2 zEq0rTqR8Gld9Hh4pkk#kWg;597TkW1MPo?dK;F@A^MX*$Y?TI4 z4|WR?4MWdQpFh*O5;lNFf)Dmh>*e7kyFG;2aaM|fz5Nf@5MK+IL6TEp%kI>gIS)Pu zT#;44gzw$E@7`Ape4UV__&tEnP#;JOxJqQoH~I+V=;*EDrztzK#W0n|9NP*6-=7E9 zMZmbYW1oMU*StsR07B<7KL!^%bAafG3&*D!>^?C`1;lu$s;VB!Sj~xH9hg}jd=Xsg zZDjX^>|hv|2~cCs0=h3HQ*>y}&R~#cm|0V^aSeAq>tP!yG|%s`3kP%B4ZUV#K!S)$ ztI7&%=wbMwY%QS{X2QT01xW;tw?kbEpRKr>3r+Z;(SvU4PY#M3s z2w8yV0*rYN(uI&HM8;ac)qQ>DnL03Lxy<0)_o30bwo!^#n) z&Wp9X0RfJ%v+#57to0z|4I#XNEIBdaRl8}9Ktf261SV>CEwx!niomj%&=XI7+mY|H zT|6;P)Zu+2+*;;6eR9&SYxMZDb5mM1k2fE3dQhibqe%x*RHq5{wsHc+o$JIC{O>4JjwMtb3!+}_}*SkDmVLMe+TWF zD>N?IKHda}DGB>-S&ykxYq#ns@#Bu2=cWyt47~JHEQKLe@e>;jO$Jd*!aIVD?H|wm=z|846v5$M5ajoKOh#r_p9>5e>{I zORd0G`$Eqj!ZTf}m93zYwZGeZskax@C_gXuy>fg-m#nQTYl_F{S9j=2Vj%j+^CQ7i z#zG;W&QF+Fef|Q* z?+V%IDOMm}rRIL$%6&Q{z`iuS2`+qVcehnI^hOZ&6V-L|o7V4~{dvBUm4PxRi9=WN z@tkJim&)@L@Ai3P>gd%@_}5D_m+$|MVbYPZu&&ggKt$PtGbax+6-BPncH`l5`C zt*Whdb^>D+mO^H4H}w|JS3Lf*tSk@&;op$YqhjqPA?tvE{Rf67 zan!b~vsW@KAGuVSWXqXUo;qI|JP}F>-Arz+^UL{)5sfsfijk!h?}9kH3vi;$ba&0t zd2c)OqMn{2|NUFKN|MG`iMTs=)MD@ERw2a>r<&JCpD&HJXnf~kU~O$5&fu*|t};|l zFWRmvITh1bpDJY^KF?c9Dcc-dus9@E@?Vd?pUx#;E5Xbnb$VP||Mgly3)ysIZT;om zVt7_$#_C;$b@(P`Ge<^>jUsMz;oE{1I{Gi>bHmM-_{A;GB6>dxI=7-^^?U!VOj)^xJ8XSRPguHrmfgBV|x;=k>O0p=of0N804Y3-~;LQ}J$Z$RQJ-g2KW>mSD>M-vcA$OPCyYyjmmqik&(< zI_i%haGz}==ZrbYKOwsJU;?D|?SC58h*o$k`jE`Qp0f&AvG6T#-KSzo#GOdYz3|Mo z|FHcvW}CpZ@C8bXLRMVCMMx7cyUR(!L!94rfEb~Ot_jWB2SS8>X*Zb#bZ~IE9*!Dy zA=`cNPmNTwWcI;Q43EMtIo}lUbFmk}X_8?rqLUCiowNA$?Cc31H<*CQr$n!5oj;j) zf``k*qW#xI1(_t^PAj0b{(8d#hFdgU9z_3(A%lg3OqA8dwg67l!O2FZv&4V=xe=O^ z%=KviSkr$F+2WxQtU((EUE2#QdbvY!tCjHIUrA5{-0;p_bm6F!&ZV_(|Cj}|{`WZi z|DQLe7WUachiU^BV~etEKfOO`JKzvYz(}gb!^P+7ZTWQne;TS)UmQlIJbyuxBKZCG z-Mea+F6A&PB5~v6?e@udd}ElH3o&KXg49xrIJW%wH1H+eFFF2 zF4*kXvIvyD_gvgrdj9lZ@4;zVrW#j3Ha8)y;roB*{*Skn z>_9#Tdw&!LWins^s)Q4i975d!qgSwyy=0vbN2NvaJ2=C>XHT%&ueUeUJd)@dK)LQ~ zE6j({APyv(8T^#LtYn@uKV+ILvvhyGM~44U`SOK8Ea5Raq67!LT!0%Jv7JJqhr>n{ z!)3>g9~Xr2fvSS2@9OA?z!;Djs6&v!^*p}oH*AQ65x|6u-xC(VXhLx@u%(1>Jm?_G zCr+FQ*se>&=mkNvoUb^Zyq#hYKGH(+3K;kw+Juyb7Y65@oqk=7)VeoLPt>w3wc%B4 ze=mWTRFHxfI{*QK*7^CIx!m5xv*0~D;{L?K3LR33jLMT21brw%BSIzFY%S{$OxCm$ z_ErmD_jdCOONlmFcwNx{{OuJzmoV~tpMC0AjqLOWdm0bI!Pz6UB21$F9Xm)mWxTW~ z08s#1M-G!Hs_@SeE)ep@7SV=(z8;CCjmbsPb>ldii3E5hKyU4R?Xn`>CiTUdP!oRo zZkBf?_|MKp`vF|8s9onxhyf5A(()zR>ekEB$oo%-V+Cm`zx%w4iwmJ`M3fkZX}Dd^ z9Xm?;4u0x9TyBWsL1^sX@DKLchirCzvTq#~Mk=GW^1{&mOeXX4MLE()E42fC2v!zjJU zYBC*KUsCz;?RYm(G=hoLE~3sMz!Rz@rr-5F|74Wov{P6Q>L9WB5+^oZ2n9CX3})tXzqfevlA`#SKhe_d>7~Q`>qowM&2@WOx!fBW8xt%x?GypaSwjR*sIZK@ zdRmwd(S*k)6Y{>iZ_bfg>&eaAK?dKE3g8|o`GUl4usn8&lNzQA~wKfAo zWgKu%Y)?}6BX&3xZSEbR?0Tq0YO>p%ytu$nArF4uIBAUJC`r%N(nu5qMQ>9~2uH zEA8yd51Sq$bgZP`gB+(9mSoTbK>c%0YU_TycmQ+W7{SYWa`12zWSe+20K_wagpXF9 zuNQZz5qM3k4?~n6^PSURG-kIIKR!6wog3g|@p0fl*IE}9%=id8^eADdRSy<$CA^Xc z+E4_TETRS~FPIzGyOfbhLX5qcd^9MyWLr8brSR$F@}y|P(wa02VQ!GLm?)?W6HkJ6 z60FY>DsN-+6rKZCj}FkWW0gmSOp$Lt7P@6)DIr$7R6yrmcv}%1#$++VyuvItG-l-Q zRJz=S{)?6%GB9vrF^3aR>_Sd#i>7XbjYpk$){%qX-8i_#DemmdnjbO>9k>?Tl;c)g zCEPDvZw4!d>8s39cq_Ppb82Tx9?J*uABEo~q0Mbbd||5CL$Av3ft7PALh#U14y{VO za}D~UwyPy3H?7>l0|NtL;fRMQCWRasF(UCi8Pnm}+phUb_>XC{doK~WX2JAMDe}Z> zYW8+pm#^=b5s64^kMtOa$+&GIiW@Q2)yM2$SWQn~>(8k=3ZG?vOrU|CWw-0~P^WzR z0jHeUSvH(J)w1b%Uwg5a&$e=_Y`M?6tGB3vspZknQ-hVI>b(rHU(vKGS#y0YnCx^B ztLn(6rH%u}D;c({VFpF*>6xSST*p1ZId^?NHmzZF8abU1o8S(6A8H!Bv0=j!M<01? z;rvo?V1>bw!}rMeGmLfE*?Z=1miXa{xiHnvt&v>zbQavD2Ab6cs|=1>l1XoD1MU$P zvkbc~SvVf5pUpznM}ySeTn8&g_!(_8V{M;6b-RP;0>`@80yS1W=s@CP|oov zImA~|G(C8P$Dlw9vY2tea^{EGyyp1gtqraJWJp)w*eKQ&2-?x9iJkhft zh>-ICD}8ZkKaYm?XLez-Z1He%`OvbJk*ke9gNxdufa}CLT*!s-F7fMf{ck85lhCN!Ss^J4A8s8 z0i1wgIC5kAu*{e^Z-ii<3P4P(ir5*d;FD8$*D74a114425sn1iwh0(8k`~78Ac~tp zStm{&^1>AKIEBb-i8`5yx9WGL}MW4sZp7UP_R3lPyf$u5;N@!pZ`x9`*{YTwF8C^SeBk3 P*FZg~a3b~CnalqVAd$>G literal 0 HcmV?d00001 diff --git a/docs/source/img/preprocessing_trusses/pratt_roof_truss.png b/docs/source/img/preprocessing_trusses/pratt_roof_truss.png new file mode 100644 index 0000000000000000000000000000000000000000..10e4011000a985870c6a7584fb5c263125aac990 GIT binary patch literal 28202 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 Date: Sat, 6 Jun 2026 16:22:08 +1000 Subject: [PATCH 15/18] Fix ug in warren flat truss generator --- anastruct/preprocess/truss.py | 55 +++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/anastruct/preprocess/truss.py b/anastruct/preprocess/truss.py index 8424f6f..289dc31 100644 --- a/anastruct/preprocess/truss.py +++ b/anastruct/preprocess/truss.py @@ -252,41 +252,46 @@ def __init__( self.end_width = (width - self.n_units * unit_width) / 2 + (unit_width / 2) def define_nodes(self) -> None: + # Warren's __init__ overrides self.end_width after super().__init__ returns, but + # define_nodes is called inside that super().__init__. At this point self.end_width + # still holds the FlatTruss value = (width - n_units*unit_width)/2, which equals the + # half-unit inset used for the *offset* chord endpoints (t_x0). The interior nodes of + # the *corner* chord sit an additional half unit further in, so their base is + # self.end_width + unit_width/2. + t_x0 = self.end_width # inset for offset-chord endpoints + b_base = self.end_width + self.unit_width / 2 # base x for corner-chord interior nodes + # Bottom chord nodes if self.end_type == "triangle_down": + # Corners at x=0 and x=width; n_units interior nodes self.nodes.append(Vertex(0.0, 0.0)) - else: - self.nodes.append(Vertex(self.end_width - self.unit_width / 2, 0.0)) - for i in range(int(self.n_units) + 1): - x = self.end_width + i * self.unit_width - self.nodes.append(Vertex(x, 0.0)) - if self.end_type == "triangle_down": + for i in range(int(self.n_units)): + self.nodes.append(Vertex(b_base + i * self.unit_width, 0.0)) self.nodes.append(Vertex(self.width, 0.0)) - else: - self.nodes.append( - Vertex(self.width - (self.end_width - self.unit_width / 2), 0.0) - ) + else: # triangle_up — offset endpoints; n_units-1 interior nodes + self.nodes.append(Vertex(t_x0, 0.0)) + for i in range(1, int(self.n_units)): + self.nodes.append(Vertex(t_x0 + i * self.unit_width, 0.0)) + self.nodes.append(Vertex(self.width - t_x0, 0.0)) # Top chord nodes if self.end_type == "triangle_up": - self.nodes.append(Vertex(0, self.height)) - else: - self.nodes.append(Vertex(self.end_width - self.unit_width / 2, self.height)) - for i in range(int(self.n_units) + 1): - x = self.end_width + i * self.unit_width - self.nodes.append(Vertex(x, self.height)) - if self.end_type == "triangle_up": + # Corners at x=0 and x=width; n_units interior nodes + self.nodes.append(Vertex(0.0, self.height)) + for i in range(int(self.n_units)): + self.nodes.append(Vertex(b_base + i * self.unit_width, self.height)) self.nodes.append(Vertex(self.width, self.height)) - else: - self.nodes.append( - Vertex(self.width - (self.end_width - self.unit_width / 2), self.height) - ) + else: # triangle_down — offset endpoints; n_units-1 interior nodes + self.nodes.append(Vertex(t_x0, self.height)) + for i in range(1, int(self.n_units)): + self.nodes.append(Vertex(t_x0 + i * self.unit_width, self.height)) + self.nodes.append(Vertex(self.width - t_x0, self.height)) def define_connectivity(self) -> None: - n_bottom_nodes = int(self.n_units) + ( - 1 if self.end_type == "triangle_down" else 0 - ) - n_top_nodes = int(self.n_units) + (1 if self.end_type == "triangle_up" else 0) + # triangle_down: bottom has corner endpoints → n_units+2 nodes; top is offset → n_units+1 + # triangle_up: top has corner endpoints → n_units+2 nodes; bottom is offset → n_units+1 + n_bottom_nodes = int(self.n_units) + (2 if self.end_type == "triangle_down" else 1) + n_top_nodes = int(self.n_units) + (2 if self.end_type == "triangle_up" else 1) # Bottom chord connectivity self.bottom_chord_node_ids = list(range(1, n_bottom_nodes + 1)) From cfef0bacdbaf0427cb3b6b71d758056bb2df7067 Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Sat, 6 Jun 2026 16:27:49 +1000 Subject: [PATCH 16/18] Linting --- anastruct/preprocess/beam.py | 2 -- anastruct/preprocess/beam_class.py | 14 ++++++-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/anastruct/preprocess/beam.py b/anastruct/preprocess/beam.py index cdca379..15072fa 100644 --- a/anastruct/preprocess/beam.py +++ b/anastruct/preprocess/beam.py @@ -1,7 +1,5 @@ from typing import Any, Literal, Optional -import numpy as np - from anastruct._types import SectionProps from anastruct.preprocess.beam_class import Beam from anastruct.vertex import Vertex diff --git a/anastruct/preprocess/beam_class.py b/anastruct/preprocess/beam_class.py index 2d393b3..ff5e5e9 100644 --- a/anastruct/preprocess/beam_class.py +++ b/anastruct/preprocess/beam_class.py @@ -31,7 +31,7 @@ class Beam(ABC): angle (float): Angle of the beam (degrees; 0 = horizontal, positive = CCW); defaults to 0.0 section (SectionProps): Section properties for all beam elements; defaults to DEFAULT_BEAM_SECTION supports_type (Literal["simple", "pinned", "fixed"]): Type of supports to apply; defaults to "simple" - system (SystemElements): The FEM system containing all nodes, elements, and supports; initialized after adding elements + system (SystemElements): The FEM system containing all nodes, elements, and supports """ # Common geometry @@ -94,12 +94,9 @@ def __init__( self.span_lengths = [length] if angle != 0.0 and -2 * np.pi <= angle <= 2 * np.pi: - import warnings - - warnings.warn( - f"A very small angle was provided ({angle}). " - f"Please ensure input units are degrees, not radians.", - stacklevel=2, + print( + f"WARNING: A very small angle was provided ({angle}). " + f"Please ensure input units are degrees, not radians." ) if angle < 0 or angle >= 360: angle = angle % 360 @@ -292,7 +289,8 @@ def apply_point_load_to_spans( relative_location must be provided. spans (Optional[Union[int, Sequence[int]]]): Span(s) to apply the load to. If None, applies to all spans. - tolerance (float): Tolerance for matching existing node locations (length units). Defaults to beam length * 1e-4. + tolerance (float): Tolerance for matching existing node locations (length units). + Defaults to beam length * 1e-4. """ if spans is None: spans = list(self.element_ids.keys()) From c03e0784984d4e75efd95440b417c180656d4b12 Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Sat, 6 Jun 2026 16:30:23 +1000 Subject: [PATCH 17/18] Use warnings import --- anastruct/preprocess/beam_class.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/anastruct/preprocess/beam_class.py b/anastruct/preprocess/beam_class.py index ff5e5e9..e438feb 100644 --- a/anastruct/preprocess/beam_class.py +++ b/anastruct/preprocess/beam_class.py @@ -1,3 +1,4 @@ +import warnings from abc import ABC, abstractmethod from typing import Iterable, Literal, Optional, Sequence, Union, cast @@ -94,9 +95,10 @@ def __init__( self.span_lengths = [length] if angle != 0.0 and -2 * np.pi <= angle <= 2 * np.pi: - print( + warnings.warn( f"WARNING: A very small angle was provided ({angle}). " - f"Please ensure input units are degrees, not radians." + f"Please ensure input units are degrees, not radians.", + stacklevel=2, ) if angle < 0 or angle >= 360: angle = angle % 360 From 1f96c8c8e6d404f469a24e2aab0cb5e81aa34aea Mon Sep 17 00:00:00 2001 From: Brooks Smith <42363318+smith120bh@users.noreply.github.com> Date: Sat, 6 Jun 2026 16:33:58 +1000 Subject: [PATCH 18/18] Formatting --- anastruct/preprocess/truss.py | 10 +++++++--- tests/test_beam.py | 4 +++- tests/test_truss.py | 8 ++++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/anastruct/preprocess/truss.py b/anastruct/preprocess/truss.py index 289dc31..78fdad4 100644 --- a/anastruct/preprocess/truss.py +++ b/anastruct/preprocess/truss.py @@ -258,8 +258,10 @@ def define_nodes(self) -> None: # half-unit inset used for the *offset* chord endpoints (t_x0). The interior nodes of # the *corner* chord sit an additional half unit further in, so their base is # self.end_width + unit_width/2. - t_x0 = self.end_width # inset for offset-chord endpoints - b_base = self.end_width + self.unit_width / 2 # base x for corner-chord interior nodes + t_x0 = self.end_width # inset for offset-chord endpoints + b_base = ( + self.end_width + self.unit_width / 2 + ) # base x for corner-chord interior nodes # Bottom chord nodes if self.end_type == "triangle_down": @@ -290,7 +292,9 @@ def define_nodes(self) -> None: def define_connectivity(self) -> None: # triangle_down: bottom has corner endpoints → n_units+2 nodes; top is offset → n_units+1 # triangle_up: top has corner endpoints → n_units+2 nodes; bottom is offset → n_units+1 - n_bottom_nodes = int(self.n_units) + (2 if self.end_type == "triangle_down" else 1) + n_bottom_nodes = int(self.n_units) + ( + 2 if self.end_type == "triangle_down" else 1 + ) n_top_nodes = int(self.n_units) + (2 if self.end_type == "triangle_up" else 1) # Bottom chord connectivity diff --git a/tests/test_beam.py b/tests/test_beam.py index d8f9c50..792ad88 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -480,7 +480,9 @@ def it_updates_internal_ids_after_node_insertion(): def it_validates_location_arguments(): beam = SimpleBeam(length=10) - with raises(ValueError, match="Either absolute_location or relative_location"): + with raises( + ValueError, match="Either absolute_location or relative_location" + ): beam.apply_point_load_to_spans(Fy=-100) with raises(ValueError, match="Only one of"): diff --git a/tests/test_truss.py b/tests/test_truss.py index d012495..3472648 100644 --- a/tests/test_truss.py +++ b/tests/test_truss.py @@ -691,7 +691,9 @@ def it_solves_with_top_chord_load(): # Check that reactions are non-zero at support nodes for node_id in support_node_ids: reaction = truss.system.get_node_results_system(node_id=node_id)["Fy"] - assert abs(reaction) > 0, f"Node {node_id} should have non-zero reaction" + assert ( + abs(reaction) > 0 + ), f"Node {node_id} should have non-zero reaction" # Verify total vertical reaction equals applied load total_reaction = sum( @@ -730,7 +732,9 @@ def it_solves_with_bottom_chord_load(): # Check that reactions are non-zero at support nodes for node_id in support_node_ids: reaction = truss.system.get_node_results_system(node_id=node_id)["Fy"] - assert abs(reaction) > 0, f"Node {node_id} should have non-zero reaction" + assert ( + abs(reaction) > 0 + ), f"Node {node_id} should have non-zero reaction" # Verify total vertical reaction equals applied load total_reaction = sum(