Skip to content

residual_force

ResidualForceLoss

Bases: Module

Penalizes non-zero residual force at unsupported nodes, i.e. equilibrium violation.

Source code in src/torch_structure/loss/residual_force.py
 6
 7
 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
class ResidualForceLoss(torch.nn.Module):  # only works for undirected graphs!
    """Penalizes non-zero residual force at unsupported nodes, i.e. equilibrium violation."""

    def __init__(self, reduction="mean"):
        super(ResidualForceLoss, self).__init__()
        self.residual_force = ResidualForce()
        self.mse = torch.nn.MSELoss(reduction=reduction)

    def forward(self, coords, load, is_support, force, edge_index):
        """Compute the mean squared residual force over unsupported nodes.

        Args:
            coords (torch.Tensor [N, D]): node coordinates.
            load (torch.Tensor [N, D]): externally applied nodal loads.
            is_support (torch.Tensor [N], bool): mask of supported (fixed) nodes,
                excluded from the loss since they may carry a reaction force.
            force (torch.Tensor [E]): axial force magnitude of each member.
            edge_index (torch.Tensor [2, E]): edge connectivity (undirected).

        Returns:
            torch.Tensor: the mean squared residual force.
        """
        is_support = is_support.view(-1)
        residual_force = self.residual_force(coords, force, edge_index, load)
        residual_force = torch.norm(residual_force, dim=1)

        # Apply mask for free/unsupported nodes
        residual_force = residual_force[~is_support]

        loss = self.mse(residual_force, torch.zeros_like(residual_force))
        return loss

forward(coords, load, is_support, force, edge_index)

Compute the mean squared residual force over unsupported nodes.

Parameters:

Name Type Description Default
coords Tensor[N, D]

node coordinates.

required
load Tensor[N, D]

externally applied nodal loads.

required
is_support (Tensor[N], bool)

mask of supported (fixed) nodes, excluded from the loss since they may carry a reaction force.

required
force Tensor[E]

axial force magnitude of each member.

required
edge_index Tensor[2, E]

edge connectivity (undirected).

required

Returns:

Type Description

torch.Tensor: the mean squared residual force.

Source code in src/torch_structure/loss/residual_force.py
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def forward(self, coords, load, is_support, force, edge_index):
    """Compute the mean squared residual force over unsupported nodes.

    Args:
        coords (torch.Tensor [N, D]): node coordinates.
        load (torch.Tensor [N, D]): externally applied nodal loads.
        is_support (torch.Tensor [N], bool): mask of supported (fixed) nodes,
            excluded from the loss since they may carry a reaction force.
        force (torch.Tensor [E]): axial force magnitude of each member.
        edge_index (torch.Tensor [2, E]): edge connectivity (undirected).

    Returns:
        torch.Tensor: the mean squared residual force.
    """
    is_support = is_support.view(-1)
    residual_force = self.residual_force(coords, force, edge_index, load)
    residual_force = torch.norm(residual_force, dim=1)

    # Apply mask for free/unsupported nodes
    residual_force = residual_force[~is_support]

    loss = self.mse(residual_force, torch.zeros_like(residual_force))
    return loss