FRUEDELA
Felix Candela Thin-Shell Concrete Design & Analysis Tool: A parametric Grasshopper tool for exploring hypar shell geometry, structural performance, and Candela benchmarking
Overview
FRUEDELA is a parametric design tool for generating, analyzing, and evaluating hyperbolic paraboloid (hypar) umbrella shell structures. Inspired by Felix Candela’s Los Manantiales Restaurant (1958), FRUEDELA allows users to explore the relationship between shell geometry, structural efficiency, and material economy all while benchmarking directly against Candela’s design.
The tool is designed for architecture and engineering students who want to understand how shell geometry drives structural behavior, and how close their designs come to Candela’s legendary efficiency.
What It Does
FRUEDELA generates a parametric four-unit hypar umbrella shell and runs a full structural analysis using Karamba3D. Results are displayed in a live viewport dashboard that compares your design against Candela’s historical benchmarks.
Primary Inputs (Design Variables):
- outerRadius: overall footprint size of the shell
- numDivisions: number of umbrella units (default = 4)
- shellThickness: concrete shell thickness [m]
- vBeamDepth: V-beam edge stiffener depth [cm]
- Toggle: turn V-Beam edge stiffeners on or off
Additional curvature and profile sliders are available in the Advanced Shape Parameters cluster for users who want deeper control over the parabolic edge geometry.
Outputs:
- Live 3D shell geometry with stress color visualization
- FRUEDELA dashboard displaying
- L/Δ deflection ratio vs. Candela benchmark (~3000) and code minimum (360)
- L/t slenderness ratio vs. Candela benchmark (800)
- Mass per surface area [kg/m^2] vs. Candela benchmark (~100)
- Stress index (relative metric)
- Status rating: OVERSTRESSED, FAILS SERVICEABILITY, STRUCTURALLY CONSERVATIVE, ELEGANT — CANDELA RANGE, or ACCEPTABLE
ShellView modes:
- Cross Section - displays shell thickness as an extruded surface, useful for verifying thickness is applied correctly across the whole shell
- Utilization: color-maps structural utilization ratio across the shell. Red zones = elements approaching capacity. Blue zones = underutilized
- Displacement: color-maps deflection magnitude across the surface, highlighting where the shell deforms most under gravity load, typically the low corners and center
- Princ. stress 1: color-maps the first principal stress (compression). On a Candela hypar, compression will concentrate at the support corners and ridge lines
- Princ. stress 2: colors-maps the second principal stress (tension), revealing where the shell is being pulled apart and where cracking might initiate in concrete
- Equivalent stress: combined von Mises stress metric, giving a single overall picture of stress distribution across the shell.
BeamView modes
- Section Forces: displays axial force, shear, and moment diagrams along each V-beam element
- Utilization: color-maps V-beam utilization, showing which edge stiffeners are working hardest
- Displacement: shows deflection along each V-beam under load
Requirements
- Rhino 7 or 8 (Mac or Windows)
- Grasshopper (included with Rhino)
- Karamba3D 2.2.0 (licensed or trial)
- No other plugins required
How to Use
- Open 4units_RyanFruehwirth_Module9.gh in Grasshopper with Rhino running. The shell will generate automatically with default parameters.
- Adjust the footprint and rise
- Use outerRadius to set the overall size and centerHeight to control how tall the shell rises. These two sliders have the largest effect on structural behavior.
- Adjust shell thickness
- Use shellThickness to explore the tradeoff between material efficiency and structural performance. Thinner shells score better on slenderness but are more prone to instability.
- Toggle V-beams
- Use the Toggle switch to turn edge stiffeners on or off. Watch the dashboard metrics update in real time.
- Adjust V-beam dimensions
- Use vBeamDepth, vBeamTopWidth (advanced), and vBeamBottomWidth (advanced) to control the cross-section of the edge stiffeners.
- Switch visualization modes
- Drop down the ShellView or BeamView components to switch between Utilization, Displacement, Principal Stress, and other render modes to explore different aspects of structural behavior.
- Read the dashboard
- The FRUEDELA dashboard appears directly in the Rhino viewport. Compare your metrics against the Candela benchmarks and aim for ELEGANT - CANDELA RANGE status.
- Fine-tune the form
- The additional curvature sliders (topMidpoint, sideMidpoint, bottomCurvature1, bottomCurvature2, etc.) allow more advanced control over the parabolic edge profile for users who want to push the geometry further.
Typical Results
A well-proportioned shell with outerRadius around 16 m and centerHeight around 0.22 meters should achieve a status of ACCEPTABLE or ELEGANT - CANDELA RANGE with a deflection ratio above 300 and slenderness above 600. Enabling V-beams typically improves the deflection ratio.
Known Limitations
- Analysis Scope
- The structural analysis considers self-weight under gravity loading only. Live loads, wind, seismic, thermal effects, etc. are not modeled. Results are intended for comparative design exploration purposes only and should not be used for engineering certification or construction documentation.
- Mesh Stability
- Karamba3D mesh convergence can be sensitive to extreme parameter combinations. Very low shellThickness values (below 0.02 m) or very high centerHeight relative to outerRadius may cause solver instability or unrealistic stress results. If the dashboard shows unexpected values, reset sliders toward defaults and adjust incrementally.
- Typology Fixed
- The tool is calibrated for the four-unit hypar umbrella typology only. The structural benchmarks, support conditions, and dashboard metrics are all derived from this specific form. Applying the tool to fundamentally different shell geometries would require recalibration of the evaluators.
- Karamba Version Dependency
- The script was developed and tested on Karamba3D 2.2.0. Behavior on significantly older or newer versions is not guaranteed. If components appear orange or red on first open, check your Karamba version.
- Mac vs. Windows
- The script runs on both platforms since there is no dependency on Anemone which is Windows-only.
About the Name
FRUEDELA combines Fruehwirth (author) and Candela (inspiration). Felix Candela (1910-1997) was a Spanish-born Mexican architect and structural engineer renowned for his mastery of thin-shell concrete hyperbolic paraboloid structures, routinely achieving slenderness ratios and material efficiencies that remain extraordinary by any standard.
Contact
Developed for CEE 220C: Parametric Design and Optimization, Stanford University, Spring 2026.
Please download the image below for a clear view of the Grasshopper script:

The final tool closely follows the original pitch. The core geometry, Karamba pipeline, comparative dashboard, and verdict logic were all delivered as proposed. Two inputs were renamed from the pitch: tipHeight became centerHeight and meshDensity became numDivisions. Both function identically. Input validation panels were deprioritized in favor of the Advanced Shape Parameters cluster. Three nice-to-have features from the pitch were attempted but not completed, documented below.
- Varying V-Beam Depth (Tapered Cross-Section)
- Candela’s actual V-beams tapered from 60 cm at the center to 120 cm at the supports. This was attempted using domain-driven depth interpolation per beam segment but failed because Karamba3D’s LineToBeam component accepts a single depth value per element. Implementing a true taper requires subdividing each beam into many short segments with incrementally changing cross-sections, which caused mesh convergence instability at the shell-beam interface.
- Typology Switcher
- A Stream Filter-based switcher was built to allow users to swap between Los Manantiales, a single saddle hypar, the Cosmic Rays Pavilion, and a groined vault. The saddle and Cosmic Rays geometry were partially completed. The feature was abandoned because each typology requires different support conditions and mesh topology. Feeding different geometry mid-pipeline broke the Karamba Supports component which expects consistent corner point locations.
- Principal Stress Streamlines
- A C# script was written to trace streamlines across the shell surface following principal stress directions. The script generated curves but they were geometrically derived from projected global axes rather than actual Karamba stress vectors. Karamba’s S-Forces component outputs scalar stress magnitudes, not direction vectors. The shell mesh also fragmented across the four umbrella units in a way that Mesh Join and Weld could not fully resolve, causing tracers to jump between mesh pieces and produce funky/invalid curves.


#region Usings
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using Rhino;
using Rhino.Geometry;
using Grasshopper;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;
#endregion
public class Script_Instance : GH_ScriptInstance
{
#region Notes
#endregion
private void RunScript(
Mesh mesh,
int seedCount,
double stepSize,
int maxSteps,
ref object compression,
ref object tension)
{
mesh.FaceNormals.ComputeFaceNormals();
var dir1 = new List<Vector3d>();
var dir2 = new List<Vector3d>();
Vector3d globalX = new Vector3d(1, 1, 0);
globalX.Unitize();
for (int i = 0; i < mesh.Faces.Count; i++)
{
Vector3d normal = mesh.FaceNormals[i];
normal.Unitize();
Vector3d d1 = globalX - (Vector3d.Multiply(globalX, normal)) * normal;
if (d1.IsZero) d1 = new Vector3d(0, 1, 0);
d1.Unitize();
Vector3d d2 = Vector3d.CrossProduct(normal, d1);
d2.Unitize();
dir1.Add(d1);
dir2.Add(d2);
}
// Seed from face centers
var seeds = new List<Point3d>();
int skip = Math.Max(1, mesh.Faces.Count / seedCount);
for (int i = 0; i < mesh.Faces.Count && seeds.Count < seedCount; i += skip)
{
MeshFace f = mesh.Faces[i];
Point3d ptA = mesh.Vertices[f.A];
Point3d ptB = mesh.Vertices[f.B];
Point3d ptC = mesh.Vertices[f.C];
seeds.Add((ptA + ptB + ptC) / 3.0);
}
var compCurves = new List<Polyline>();
var tensCurves = new List<Polyline>();
foreach (var seed in seeds)
{
compCurves.Add(TraceStream(mesh, dir1, seed, stepSize, maxSteps));
tensCurves.Add(TraceStream(mesh, dir2, seed, stepSize, maxSteps));
}
compression = compCurves;
tension = tensCurves;
}
private Polyline TraceStream(Mesh mesh, List<Vector3d> vecs, Point3d start, double step, int maxSteps)
{
var pts = new List<Point3d> { start };
Point3d current = start;
for (int i = 0; i < maxSteps; i++)
{
MeshPoint mpd = mesh.ClosestMeshPoint(current, double.MaxValue);
int faceIdx = mpd.FaceIndex;
if (faceIdx < 0 || faceIdx >= vecs.Count) break;
Vector3d dir = vecs[faceIdx];
if (dir.IsZero) break;
dir.Unitize();
Point3d next = current + dir * step;
MeshPoint mpdNext = mesh.ClosestMeshPoint(next, double.MaxValue);
Point3d projected = mpdNext.Point;
if (projected.DistanceTo(next) > step * 2) break;
pts.Add(projected);
current = projected;
if (pts.Count > 5 && projected.DistanceTo(pts[0]) < step) break;
}
return pts.Count > 1 ? new Polyline(pts) : new Polyline(new[] { start, start });
}
}

Stress Utilization:

Displacement:

Principal Stress 2:
