Skip to main content
This page walks through a real-world use of solveSecant() to find the rail span where demand equals capacity. For syntax and general usage, see Equation Functions. Calcs Builder equations are powered by Math.js; solveSecant() is a custom solver built on top of it.

Big Picture

  1. We know that for a given rail span (the distance between rail supports), a panel will experience some demand (like wind load or snow load) that depends on that span.
  2. We also know that the rail has a certain capacity to withstand that load, which depends on the rail span (longer spans mean lower capacity) and on the angle of the force acting on it.
  3. The formula sets up: f(rail_span) = Demand(rail_span) - Capacity(rail_span)
  4. We want to solve f(rail_span) = 0, where Demand equals Capacity.
  5. To do that, we’re using a numerical solver named solveSecant(). This function tries different values for rail_span (starting between 30 cm and 300 cm) and zeroes in on the value that makes f(rail_span) = 0.

High-Level Code Flow

solveSecant(
    30 cm,              // x0:  first guess for rail span
    300 cm,             // x1:  second guess for rail span
    0.00001 cm,         // tolerance: how close we need to get to 0
    100,                // max number of iterations
    f(rail_span) = ...  // the function we want to solve = 0
)

1. Secant Method Setup

Initial Parameters:
  • 30 cm, 300 cm: These are our initial “guesses” or bracket for the solution. We know the actual required rail span is somewhere between 30 cm and 300 cm.
  • 0.00001 cm: The solver will stop iterating if it finds a solution whose error is smaller than 10^ cm.
  • 100: This is the maximum number of iterations to try before giving up (i.e., if no solution is found within 100 tries, it’ll fail).

2. The Function f(rail_span)

Inside solveSecant(), we define:
f(rail_span) = 
   (matrixSubset(ultimateLCs_Resultant_Cpemin, rowIndex() + 1, 2) 
    * (panel_ornt == "Landscape Vert. Rails" ? pnlX : pnlY )
    * rail_span) / 2
   -
   interpolate(
       [
         1.298 * exp(-0.00828 * number(rail_span, "cm")) - 0.00702,
         1.296 * exp(-0.00820 * number(rail_span, "cm")) - 0.00719,
         1.244 * exp(-0.00669 * number(rail_span, "cm")) - 0.01198,
         1.242 * exp(-0.00662 * number(rail_span, "cm")) - 0.01232
       ],
       matrixSubset(angle_resultF_Cpemin, rowIndex() + 1, 2),
       [0 deg, 30 deg, 60 deg, 90 deg]
   )
   *
   interpolate([5700 N, 5350 N, 3250 N, 2900 N],
               matrixSubset(angle_resultF_Cpemin, rowIndex() + 1, 2),
               [0 deg, 30 deg, 60 deg, 90 deg])
This breaks down into two major parts:

A) Demand Part

( matrixSubset(ultimateLCs_Resultant_Cpemin, rowIndex() + 1, 2 )
  * (panel_ornt == "Landscape Vert. Rails" ? pnlX : pnlY )
  * rail_span ) / 2
  • matrixSubset(ultimateLCs_Resultant_Cpemin, rowIndex() + 1, 2)
    • This takes the loads of Ultimate Limit State - Resultant Loads
  • (panel_ornt == "Landscape Vert. Rails" ? pnlX : pnlY )
    • If the panel orientation is “Landscape Vert. Rails,” we use pnlX; otherwise, we use pnlY. Essentially, this picks the relevant dimension of the panel based on orientation.
  • rail_span
    • The rail span (the variable we’re trying to solve for).
  • Divide by 2
    • Because the demand is distributed in two rails.
Putting it together: Demand = (load factor) * (panel dimension) * rail_span / 2

B) Capacity Part

Next, we subtract the “capacity part” from that Demand. The capacity expression is:
interpolate(
    [
      1.298 * exp(-0.00828 * number(rail_span, "cm")) - 0.00702,
      1.296 * exp(-0.00820 * number(rail_span, "cm")) - 0.00719,
      1.244 * exp(-0.00669 * number(rail_span, "cm")) - 0.01198,
      1.242 * exp(-0.00662 * number(rail_span, "cm")) - 0.01232
    ],
    matrixSubset(angle_resultF_Cpemin, rowIndex() + 1, 2),
    [0 deg, 30 deg, 60 deg, 90 deg]
)
*
interpolate(
    [5700 N, 5350 N, 3250 N, 2900 N],
    matrixSubset(angle_resultF_Cpemin, rowIndex() + 1, 2),
    [0 deg, 30 deg, 60 deg, 90 deg]
)
This calculates the capacity by combining two interpolated factors: one for the span and one for the angle of force.

Breaking Down the Capacity Part

1. Angle-Based Interpolation

Notice that the capacity calculation involves two interpolations, each using four data points for angles 0°, 30°, 60°, and 90°.

2. First Interpolation

interpolate(
    [ 
      1.298 * exp(-0.00828 * number(rail_span, "cm")) - 0.00702,
      1.296 * exp(-0.00820 * number(rail_span, "cm")) - 0.00719,
      1.244 * exp(-0.00669 * number(rail_span, "cm")) - 0.01198,
      1.242 * exp(-0.00662 * number(rail_span, "cm")) - 0.01232
    ],
    angle_value,  // from matrixSubset(angle_resultF_Cpemin)
    [0 deg, 30 deg, 60 deg, 90 deg]
)
  • Each element in the array represents an exponential formula for the rail_span:
    • A * exp(B * rail_span) - C
    • where the constants A, B, and C are slightly different for each angle (0°, 30°, 60°, 90°).
  • The angle_value comes from matrixSubset(angle_resultF_Cpemin). This value represents the force angle (in degrees) that we’re considering.
  • The interpolate() function selects a capacity factor based on the actual angle by interpolating between the data points.

3. Second Interpolation

interpolate(
    [5700 N, 5350 N, 3250 N, 2900 N],
    angle_value,
    [0 deg, 30 deg, 60 deg, 90 deg]
)
  • This provides a base capacity (in Newtons) corresponding to the angles (0°, 30°, 60°, 90°).
  • Again, the actual angle is used to interpolate the specific base capacity.

4. Multiplying the Two Interpolations

capacity = (exponential_factor_for_span_and_angle) * (base_capacity_for_angle)
The final capacity is: capacity(rail_span, angle) = (A * exp(B * rail_span) - C) * (base capacity for angle)
  • The exponential factor decreases as rail_span increases.
  • The base capacity is adjusted according to the force angle.

Final Formula: Demand - Capacity

Putting the two parts together:
f(rail_span) = Demand(rail_span) - Capacity(rail_span, angle)
Where:
  • Demand(rail_span) = (load factor) * (panel dimension) * rail_span / 2
  • Capacity(rail_span, angle) = (interpolated exponential factor) * (interpolated base capacity)
The solveSecant() function iteratively adjusts the rail_span value until the difference between demand and capacity approaches zero, finding the optimal rail spacing that balances structural requirements with material efficiency.