Skip to content

cable_stayed_bridge

CableStayedBridge

Bases: BaseGenerator

Builds a cable-stayed bridge: a deck trail, towers with backstays, and fan cables, as CEM trail edges.

Source code in src/torch_structure/generators/cable_stayed_bridge.py
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
class CableStayedBridge(BaseGenerator):
    """Builds a cable-stayed bridge: a deck trail, towers with backstays, and fan cables, as CEM trail edges."""

    def __init__(self, **overrides):
        super().__init__(**overrides)
        self.max_attempts = 100

        self.node_attrs = {
            "coords": torch.empty((0, 3), dtype=torch.float),
            "load": torch.empty((0, 3), dtype=torch.float),
            "support_condition": torch.empty((0, 3), dtype=torch.long),
            "is_origin_node": torch.empty((0, 1), dtype=torch.bool),
            "sequence": torch.empty((0, 1), dtype=torch.long),
        }
        self.edge_attrs = {
            "force": torch.empty((0, 1), dtype=torch.float),
            "length": torch.empty((0, 1), dtype=torch.float),
            "is_trail_edge": torch.empty((0, 1), dtype=torch.bool),
            "force_sign": torch.empty((0, 1), dtype=torch.float),
        }
        self.default_attrs = {
            "force": torch.tensor([torch.nan]),
            "length": torch.tensor([torch.nan]),
            "coords": torch.full((3,), torch.nan),
            "load": torch.zeros(3, dtype=torch.float),
            "support_condition": torch.zeros(3, dtype=torch.bool),
            "is_origin_node": torch.tensor(0, dtype=torch.bool),
        }

    def sample_input(self, **kwargs):
        """
        No sampling required
        """
        return kwargs

    def validate_input(self, **kwargs):
        """
        No validation required
        """
        pass

    def generate(
        self,
        n_towers,
        n_cables,
        deck_trail_length,
        tower_trail_length,
        center_deviation_force,
        cable_deviation_force,
        tower_height,
        tower_offset,
        back_stay_offset,
        back_stay_force,
        deck_load=torch.tensor([0.0, 0.0, -1.0]),
    ):
        """Build the (not yet form-found) cable-stayed bridge graph from the given parameters.

        Returns:
            StructData: the constructed graph.
        """
        # Cmpute number of trail edges
        n_deck_trail_edges = n_towers * n_cables
        # Initialize graph to contain data
        graph = StructData(
            node_attrs=self.node_attrs,
            edge_attrs=self.edge_attrs,
            default_attrs=self.default_attrs,
        )

        # Deck
        deck_origin_coords = [
            torch.tensor([-0.5 * deck_trail_length, 0.0, 0.0]),
            torch.tensor([0.5 * deck_trail_length, 0.0, 0.0]),
        ]
        for i in range(2):
            # Add origin nodes
            graph.add_node(
                f"deck_trail_{i}_node_0",
                coords=deck_origin_coords[i],
                is_origin_node=torch.tensor(True),
                sequence=torch.tensor(0),
                load=deck_load,
            )
            for j in range(1, n_deck_trail_edges + 1):
                load = (
                    torch.zeros(3, dtype=torch.float)
                    if j == n_deck_trail_edges
                    else deck_load
                )
                support_condition = (
                    torch.tensor([True, True, True])
                    if j == n_deck_trail_edges
                    else torch.tensor([False, False, False])
                )
                # Add node
                graph.add_node(
                    f"deck_trail_{i}_node_{j}",
                    is_origin_node=torch.tensor(False),
                    sequence=torch.tensor(j),
                    load=load,
                    support_condition=support_condition,
                )
                # Add new edge with the created node and its previous node
                graph.add_edge(
                    f"deck_trail_{i}_node_{j - 1}",
                    f"deck_trail_{i}_node_{j}",
                    is_trail_edge=torch.tensor(True),
                    length=deck_trail_length,
                    force_sign=torch.tensor(-1.0),
                )

        # Add element connecting rails
        graph.add_edge(
            "deck_trail_0_node_0",
            "deck_trail_1_node_0",
            is_trail_edge=torch.tensor(False),
            force=center_deviation_force,
        )

        # Towers
        span = (n_deck_trail_edges * 2 + 1) * deck_trail_length
        tower_x = torch.linspace(-0.5 * span, 0.5 * span, 2 * n_towers + 1)[1:-1:2]
        for i in range(n_towers):
            alternate = 1 - 2 * (i % 2)
            applied_tower_offset = alternate * tower_offset
            tower_origin_coords = torch.tensor(
                [tower_x[i], applied_tower_offset, tower_height]
            )
            graph.add_node(
                f"tower_trail_{i}_node_0",
                coords=tower_origin_coords,
                is_origin_node=torch.tensor(True),
                sequence=torch.tensor(0),
            )
            for j in range(1, n_cables + 1):
                support_condition = (
                    torch.tensor([True, True, True])
                    if j == n_cables
                    else torch.tensor([False, False, False])
                )
                length = tower_height * 0.8 if j == n_cables else tower_trail_length
                graph.add_node(
                    f"tower_trail_{i}_node_{j}",
                    is_origin_node=torch.tensor(False),
                    sequence=torch.tensor(j),
                    support_condition=support_condition,
                )
                graph.add_edge(
                    f"tower_trail_{i}_node_{j - 1}",
                    f"tower_trail_{i}_node_{j}",
                    is_trail_edge=torch.tensor(True),
                    length=length,
                    force_sign=torch.tensor(-1.0),
                )
            # Backstay
            applied_back_stay_offset = alternate * (tower_offset + back_stay_offset)
            backstay_origin_coords = torch.tensor(
                [tower_x[i], applied_back_stay_offset, 0.01]
            )
            graph.add_node(
                f"backstay_trail_{i}_node_0",
                coords=backstay_origin_coords,
                is_origin_node=torch.tensor(True),
                sequence=torch.tensor(0),
            )
            graph.add_node(
                f"backstay_trail_{i}_node_1",
                is_origin_node=torch.tensor(False),
                sequence=torch.tensor(1),
                support_condition=[True, True, True],
            )
            graph.add_edge(
                f"backstay_trail_{i}_node_0",
                f"backstay_trail_{i}_node_1",
                is_trail_edge=torch.tensor(True),
                length=0.4 * tower_height,
                force_sign=torch.tensor(1.0),
            )
            graph.add_edge(
                f"tower_trail_{i}_node_0",
                f"backstay_trail_{i}_node_0",
                is_trail_edge=torch.tensor(False),
                force=back_stay_force,
            )

        # Cables
        deck_nodes = [
            f"deck_trail_0_node_{i}" for i in reversed(range(n_deck_trail_edges))
        ] + [f"deck_trail_1_node_{i}" for i in range(n_deck_trail_edges)]
        cable_nodes = [
            f"tower_trail_{i}_node_{j}"
            for i in range(n_towers)
            for reverse in [False, True]
            for j in (reversed(range(n_cables)) if reverse else range(n_cables))
        ]

        for deck_node, cable_node in zip(deck_nodes, cable_nodes):
            graph.add_edge(
                deck_node,
                cable_node,
                is_trail_edge=torch.tensor(False),
                force=cable_deviation_force,
            )

        return graph

generate(n_towers, n_cables, deck_trail_length, tower_trail_length, center_deviation_force, cable_deviation_force, tower_height, tower_offset, back_stay_offset, back_stay_force, deck_load=torch.tensor([0.0, 0.0, -1.0]))

Build the (not yet form-found) cable-stayed bridge graph from the given parameters.

Returns:

Name Type Description
StructData

the constructed graph.

Source code in src/torch_structure/generators/cable_stayed_bridge.py
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
def generate(
    self,
    n_towers,
    n_cables,
    deck_trail_length,
    tower_trail_length,
    center_deviation_force,
    cable_deviation_force,
    tower_height,
    tower_offset,
    back_stay_offset,
    back_stay_force,
    deck_load=torch.tensor([0.0, 0.0, -1.0]),
):
    """Build the (not yet form-found) cable-stayed bridge graph from the given parameters.

    Returns:
        StructData: the constructed graph.
    """
    # Cmpute number of trail edges
    n_deck_trail_edges = n_towers * n_cables
    # Initialize graph to contain data
    graph = StructData(
        node_attrs=self.node_attrs,
        edge_attrs=self.edge_attrs,
        default_attrs=self.default_attrs,
    )

    # Deck
    deck_origin_coords = [
        torch.tensor([-0.5 * deck_trail_length, 0.0, 0.0]),
        torch.tensor([0.5 * deck_trail_length, 0.0, 0.0]),
    ]
    for i in range(2):
        # Add origin nodes
        graph.add_node(
            f"deck_trail_{i}_node_0",
            coords=deck_origin_coords[i],
            is_origin_node=torch.tensor(True),
            sequence=torch.tensor(0),
            load=deck_load,
        )
        for j in range(1, n_deck_trail_edges + 1):
            load = (
                torch.zeros(3, dtype=torch.float)
                if j == n_deck_trail_edges
                else deck_load
            )
            support_condition = (
                torch.tensor([True, True, True])
                if j == n_deck_trail_edges
                else torch.tensor([False, False, False])
            )
            # Add node
            graph.add_node(
                f"deck_trail_{i}_node_{j}",
                is_origin_node=torch.tensor(False),
                sequence=torch.tensor(j),
                load=load,
                support_condition=support_condition,
            )
            # Add new edge with the created node and its previous node
            graph.add_edge(
                f"deck_trail_{i}_node_{j - 1}",
                f"deck_trail_{i}_node_{j}",
                is_trail_edge=torch.tensor(True),
                length=deck_trail_length,
                force_sign=torch.tensor(-1.0),
            )

    # Add element connecting rails
    graph.add_edge(
        "deck_trail_0_node_0",
        "deck_trail_1_node_0",
        is_trail_edge=torch.tensor(False),
        force=center_deviation_force,
    )

    # Towers
    span = (n_deck_trail_edges * 2 + 1) * deck_trail_length
    tower_x = torch.linspace(-0.5 * span, 0.5 * span, 2 * n_towers + 1)[1:-1:2]
    for i in range(n_towers):
        alternate = 1 - 2 * (i % 2)
        applied_tower_offset = alternate * tower_offset
        tower_origin_coords = torch.tensor(
            [tower_x[i], applied_tower_offset, tower_height]
        )
        graph.add_node(
            f"tower_trail_{i}_node_0",
            coords=tower_origin_coords,
            is_origin_node=torch.tensor(True),
            sequence=torch.tensor(0),
        )
        for j in range(1, n_cables + 1):
            support_condition = (
                torch.tensor([True, True, True])
                if j == n_cables
                else torch.tensor([False, False, False])
            )
            length = tower_height * 0.8 if j == n_cables else tower_trail_length
            graph.add_node(
                f"tower_trail_{i}_node_{j}",
                is_origin_node=torch.tensor(False),
                sequence=torch.tensor(j),
                support_condition=support_condition,
            )
            graph.add_edge(
                f"tower_trail_{i}_node_{j - 1}",
                f"tower_trail_{i}_node_{j}",
                is_trail_edge=torch.tensor(True),
                length=length,
                force_sign=torch.tensor(-1.0),
            )
        # Backstay
        applied_back_stay_offset = alternate * (tower_offset + back_stay_offset)
        backstay_origin_coords = torch.tensor(
            [tower_x[i], applied_back_stay_offset, 0.01]
        )
        graph.add_node(
            f"backstay_trail_{i}_node_0",
            coords=backstay_origin_coords,
            is_origin_node=torch.tensor(True),
            sequence=torch.tensor(0),
        )
        graph.add_node(
            f"backstay_trail_{i}_node_1",
            is_origin_node=torch.tensor(False),
            sequence=torch.tensor(1),
            support_condition=[True, True, True],
        )
        graph.add_edge(
            f"backstay_trail_{i}_node_0",
            f"backstay_trail_{i}_node_1",
            is_trail_edge=torch.tensor(True),
            length=0.4 * tower_height,
            force_sign=torch.tensor(1.0),
        )
        graph.add_edge(
            f"tower_trail_{i}_node_0",
            f"backstay_trail_{i}_node_0",
            is_trail_edge=torch.tensor(False),
            force=back_stay_force,
        )

    # Cables
    deck_nodes = [
        f"deck_trail_0_node_{i}" for i in reversed(range(n_deck_trail_edges))
    ] + [f"deck_trail_1_node_{i}" for i in range(n_deck_trail_edges)]
    cable_nodes = [
        f"tower_trail_{i}_node_{j}"
        for i in range(n_towers)
        for reverse in [False, True]
        for j in (reversed(range(n_cables)) if reverse else range(n_cables))
    ]

    for deck_node, cable_node in zip(deck_nodes, cable_nodes):
        graph.add_edge(
            deck_node,
            cable_node,
            is_trail_edge=torch.tensor(False),
            force=cable_deviation_force,
        )

    return graph

sample_input(**kwargs)

No sampling required

Source code in src/torch_structure/generators/cable_stayed_bridge.py
37
38
39
40
41
def sample_input(self, **kwargs):
    """
    No sampling required
    """
    return kwargs

validate_input(**kwargs)

No validation required

Source code in src/torch_structure/generators/cable_stayed_bridge.py
43
44
45
46
47
def validate_input(self, **kwargs):
    """
    No validation required
    """
    pass