Carrie Tam - Module 8 - Part 2

FunicularFINDR šŸ”

image

Overview: Fun with Funiculars šŸ™‚

This program allows the user to apply point loads, line loads, and area loads to a UV grid and finds the resulting moment distributions using Python scripts nested in the dynamo file and custom nodes. The moment distributions from each load are superimposed and are used to create the funicular shell structure.

Video Demo

Workspace Screenshots

Overall Workspace Code - General Model with 1 Point Load, 1 X-Line Load, 1 Y-Line Load, and 1 Area Load
Overall Workspace Code - General Model with 1 Point Load, 1 X-Line Load, 1 Y-Line Load, and 1 Area Load
image
image
[TOP] UV Grid Initialization, [MIDDLE] X-Line Load inputs & custom node, [BOTTOM] Y-Line Load inputs & custom node
[TOP] UV Grid Initialization, [MIDDLE] X-Line Load inputs & custom node, [BOTTOM] Y-Line Load inputs & custom node
image
[TOP] Point Load inputs & custom node, [BOTTOM] Area Load inputs & custom node
[TOP] Point Load inputs & custom node, [BOTTOM] Area Load inputs & custom node
Code group that superimposes moments and creates a shell structure based on that distribution
Code group that superimposes moments and creates a shell structure based on that distribution
Code group that creates Revit geometry from the resulting Dynamo geometry
Code group that creates Revit geometry from the resulting Dynamo geometry
Sample Custom Node: Point Loads. Typical load calculating custom node structure has inputs of force & location of application. This is fed into the Python script which then calls on external functions to calculate the moment distributions, which are the outputs of the custom node.
Sample Custom Node: Point Loads. Typical load calculating custom node structure has inputs of force & location of application. This is fed into the Python script which then calls on external functions to calculate the moment distributions, which are the outputs of the custom node.
# Load the Python Standard and DesignScript Libraries
import sys
import clr
import importlib

clr.AddReference('ProtoGeometry')
sys.path.append(r'C:\Users\carri\Documents')
sys.path.append(r'C:\Users\carri\AppData\Local\python-3.8.10-embed-amd64\Lib\site-packages')

import numpy as np
from Autodesk.DesignScript.Geometry import *

import Moment_Calculations

importlib.reload(Moment_Calculations)

# The inputs to this node will be stored as a list in the IN variables.
uv_grid = IN[0]
xline_ld = IN[1]
sf = IN[2]

# Get information about x line load
f_xl = xline_ld[0]
locstart_xl = xline_ld[1]
locend_xl = xline_ld[2]

# Calculate moments from x line load
# Find start and end points of the load
appy_xlstart = locstart_xl.Y - sf
appy_xlend = locend_xl.Y - sf
appx_xl = locend_xl.X - sf

# Run point load moment finding function
mx_xl = Moment_Calculations.LineLoad(sf, len(uv_grid) * sf, appy_xlstart + sf, appy_xlend + sf, f_xl, sf)
mx_xl = np.array(mx_xl)

# initialize numpy zeros array for point load moments
m_xl = np.zeros((6, 6))

# assign moment values in array accordingly
m_xl[int(appx_xl / sf), :] = mx_xl

# for each y-coordinate
for i in range(1, len(uv_grid[0])):
    # scale the moment distribution in the x direction by the factor from the m-dist in the y-dir
    slope_a = 1 / int(appx_xl)
    slope_b = 1 / (len(uv_grid) * sf - int(appx_xl) - sf)
    if i*sf <= appx_xl:
        m_xl[i, :] = mx_xl * i * slope_a * sf
    else:
        m_xl[i, :] = mx_xl - mx_xl * (i * sf - int(appx_xl)) * slope_b

# Assign your output to the OUT variable.
OUT = m_xl
Sample Moment Calculating embedded Python script. The above code is found in the Dynamo file. There are code blocks that calculate point load moments, line load moments, and area load moments with inputs of the magnitude and location of application.
def PointLoad(mmax, start, maxapp, end, sf):
    length = int((end - start + sf) / sf)
    m_p = [0] * length
    slope_a = mmax / (maxapp - start) * sf
    print(slope_a)
    slope_b = mmax / (maxapp - end) * sf
    print(slope_b)
    for i in range(length):
        if i*sf < maxapp - sf:
            m_p[i] = slope_a * i
        elif i*sf == maxapp - sf:
            m_p[i] = mmax
        else:
            m_p[i] = mmax + slope_b * (i - maxapp/sf + 1)

    return m_p


def LineLoad(start, end, app_start, app_end, force, sf):
    length = int((end - start + sf) / sf)
    m_xl = [0] * length
    a = app_start - start
    b = app_end - app_start
    c = end - app_end

    R1 = (force * b) / (2 * (length-1) * sf) * (2*c + b)
    R2 = (force * b) / (2 * (length-1) * sf) * (2*a + b)

    for i in range(length):
        if i*sf < a:
            m_xl[i] = R1 * i * sf
        elif a <= i*sf < a+b:
            m_xl[i] = R1 * i * sf - force / 2 * (i * sf - a) ** 2
        else:
            m_xl[i] = R2 * (length - i - 1) * sf

    return m_xl
External python functions. Because Dynamo does not allow for functions to be created and used within Python scripts, these two functions are external to the Dynamo file and are imported in the Python scripts. These provide moment distributions for a 2D cross-section given a point load or a uniformly distributed load.

Sample Use: Structural Reactions with a Column & 2 Walls

Overview

As an example, a generative study was performed on a pavilion roof structure with a uniformly distributed self-weight supported by a column & 2 bearing walls. The self-weight provides a uniformly distributed area load downwards on the structure whereas the reaction from the column and the 2 bearing walls provide a point load & 2 line loads acting upwards, respectively.

Overall Workspace: Example Problem with Column & 2 Bearing Walls
Overall Workspace: Example Problem with Column & 2 Bearing Walls

Loading Assumptions & Application

Plan view of layout. Column in lower left corner, 2 walls at shortest length in right top corner. It is assumed the column takes ~40% of the load in this case.
Plan view of layout. Column in lower left corner, 2 walls at shortest length in right top corner. It is assumed the column takes ~40% of the load in this case.
Play view of layout. Column in lower left corner, 2 walls at longest length in right top corner. It is assumed the column takes ~25% of the load in this case.
Play view of layout. Column in lower left corner, 2 walls at longest length in right top corner. It is assumed the column takes ~25% of the load in this case.

It was assumed that there was a linear relationship in the force distribution between the column and the walls based on these two cases and on the total length of the 2 walls. Self-weight was applied as a typical area load using the coding group above. The approximate loading on the structures was calculated in the code group below.

image

Calculation of Total Panel Areas

image
Calculation of total area of panels in both Revit & Dynamo. Total area in Revit would typically be used, but for the purposes of a generative study, Revit geometry cannot be used, so the above code using Dynamo is available.
Calculation of total area of panels in both Revit & Dynamo. Total area in Revit would typically be used, but for the purposes of a generative study, Revit geometry cannot be used, so the above code using Dynamo is available.

Results of Generative Study

Overall, a generative study was performed using the end points of the wall line loads as input parameters and the area of the discretized shell structure as the evaluation variable. Ultimately, 16 options were explored with 4 different X-Value and Y-Value end points. The minimum area was found when the Y-Value end was 4 and the X-Value end was 2.

Explore Outcomes results
Explore Outcomes results
Relationship between wall end point & area.
Relationship between wall end point & area.

Next Steps

Here are the next steps in developing this tool:

  • Parameterize the discretization of the moment distributions: this code should already be available within the dynamo script, but it needs to be debugged. The code currently runs successfully when the moment distribution is discretized into 6 points, but it should theoretically work with any number of points. The error should be somewhere in the Python scripts.
  • Toggle for framing accommodation. If this structure were to be a framed structure (e.g. with wood or steel framing the panel edges) instead of a concrete shell, they would add line loads to the structure. Ideally, the code would have a button (or a Boolean True/False node) that would allow the user to select if they wanted to account for framing loads or not. This has not been implemented because Iā€™m not sure how to account for the number framing elements yet.
  • Loads on the boundary of the structure: the code currently only accounts for loads that are applied in the middle of the structure. Because of this, if a load is applied to a boundary, the moment distributions will be wrong. This was done for ease of coding for now, but can be updated.
  • Design: the code currently focuses on the loading and finding a funicular structure purely based on the moment diagram. The next step would be to take that loading and to be able to design say a post-tensioned concrete shell or size framing to withstand the loads and moments in the configurations given.