FCS Worked Examples

This document provides annotated complete examples of FCS scripts.


Example 1: Cooling Tower Shell (temelin3.fcs)

A complete shell structure model demonstrating geometry, meshing, materials, members, supports, and loads.

######################################
##   Automatic FemCAD script file   ##
######################################

#=============================================================================
# GEOMETRY PARAMETERS
#=============================================================================

# Tower dimensions
topH = 150           # Height at top
topR = 80/2          # Top radius (diameter/2)
midH = 120           # Height at middle section
midR = 70/2          # Middle radius
botH = 0             # Height at bottom (ground level)
botR = 130/2         # Bottom radius

# Helper constants
s2 = 0.7071          # sqrt(2)/2 for 45° positions
meshH = 5            # Mesh element size

#=============================================================================
# VERTEX DEFINITIONS
# Define key points on the shell surface
#=============================================================================

# Cardinal points (0°, 90°, 180°, 270°) at each level
vertex {Vb1} xyz botR 0 botH        # Bottom, +X direction
vertex {Vm1} xyz midR 0 midH        # Middle, +X direction  
vertex {Vt1} xyz topR 0 topH        # Top, +X direction

vertex {Vb2} xyz 0 botR botH        # Bottom, +Y direction
vertex {Vm2} xyz 0 midR midH        # Middle, +Y direction
vertex {Vt2} xyz 0 topR topH        # Top, +Y direction

vertex {Vb3} xyz -botR 0 botH       # Bottom, -X direction
vertex {Vm3} xyz -midR 0 midH       # Middle, -X direction
vertex {Vt3} xyz -topR 0 topH       # Top, -X direction

vertex {Vb4} xyz 0 -botR botH       # Bottom, -Y direction
vertex {Vm4} xyz 0 -midR midH       # Middle, -Y direction
vertex {Vt4} xyz 0 -topR topH       # Top, -Y direction

# Intermediate points (45°, 135°, 225°, 315°) for arc control
vertex {Vb12} xyz +s2*botR +s2*botR botH   # 45° at bottom
vertex {Vb23} xyz -s2*botR +s2*botR botH   # 135° at bottom
vertex {Vb34} xyz -s2*botR -s2*botR botH   # 225° at bottom
vertex {Vb41} xyz +s2*botR -s2*botR botH   # 315° at bottom

vertex {Vt12} xyz +s2*topR +s2*topR topH   # 45° at top
vertex {Vt23} xyz -s2*topR +s2*topR topH   # 135° at top
vertex {Vt34} xyz -s2*topR -s2*topR topH   # 225° at top
vertex {Vt41} xyz +s2*topR -s2*topR topH   # 315° at top

#=============================================================================
# CURVE DEFINITIONS
# Create arcs connecting the vertices
#=============================================================================

# Vertical generator curves (arc through bottom-middle-top at each position)
curve {Cv1} arc vertex {Vb1} {Vm1} {Vt1}
curve {Cv2} arc vertex {Vb2} {Vm2} {Vt2}
curve {Cv3} arc vertex {Vb3} {Vm3} {Vt3}
curve {Cv4} arc vertex {Vb4} {Vm4} {Vt4}

# Horizontal arcs at bottom (quarter circles)
curve {Cb12} arc vertex {Vb1} {Vb12} {Vb2}   # Quadrant 1
curve {Cb23} arc vertex {Vb2} {Vb23} {Vb3}   # Quadrant 2
curve {Cb34} arc vertex {Vb3} {Vb34} {Vb4}   # Quadrant 3
curve {Cb41} arc vertex {Vb4} {Vb41} {Vb1}   # Quadrant 4

# Horizontal arcs at top (quarter circles)
curve {Ct12} arc vertex {Vt1} {Vt12} {Vt2}
curve {Ct23} arc vertex {Vt2} {Vt23} {Vt3}
curve {Ct34} arc vertex {Vt3} {Vt34} {Vt4}
curve {Ct41} arc vertex {Vt4} {Vt41} {Vt1}

#=============================================================================
# SURFACE PATCHES
# Define four quadrant areas bounded by curves
#=============================================================================

area 1 boundary curve {Cv1} {Ct12} {Cv2} {Cb12}
area 2 boundary curve {Cv2} {Ct23} {Cv3} {Cb23}
area 3 boundary curve {Cv3} {Ct34} {Cv4} {Cb34}
area 4 boundary curve {Cv4} {Ct41} {Cv1} {Cb41}

#=============================================================================
# ANALYSIS MODEL SETUP
#=============================================================================

# Declare this is a 3D shell model
model_shell3d

# Generate triangular mesh on each surface patch
mesharea 1 mesh_type MappedTrias h meshH
mesharea 2 mesh_type MappedTrias h meshH
mesharea 3 mesh_type MappedTrias h meshH
mesharea 4 mesh_type MappedTrias h meshH

#=============================================================================
# MATERIAL & THICKNESS
#=============================================================================

# Concrete material properties
# rho=density, alpha=temp factor, lambda=conductivity, c=heat capacity
# E=Young's modulus (MPa), ni=Poisson's ratio
material {concrete} rho 2500 alpha 40 lambda 1.2E-05 c 440 linear E 35000 ni 0.2 

# Shell thickness (1 meter) using concrete
thickness 1 material {concrete} t 1  

#=============================================================================
# STRUCTURAL MEMBERS
# Assign thickness to areas (plane stress shell elements)
#=============================================================================

planestress 1 area 1 section 1  
planestress 2 area 2 section 1  
planestress 3 area 3 section 1  
planestress 4 area 4 section 1  

#=============================================================================
# BOUNDARY CONDITIONS
# Fixed supports at the base (all DOFs constrained)
#=============================================================================

support 1 curve {Cb12} fixed "uxuyuzrxryrz"  
support 2 curve {Cb23} fixed "uxuyuzrxryrz"  
support 3 curve {Cb34} fixed "uxuyuzrxryrz"  
support 4 curve {Cb41} constant 0 0 0 0 0 0 fixed "uxuyuzrxryrz"  

#=============================================================================
# LOADS
# Distributed load on one edge of the top rim
#=============================================================================

# Load case 1: vertical distributed load on curve Ct23
# Constant intensity: fx=0, fy=0, fz=-0.1, mx=0, my=0, mz=0
load 1 case 1 curve {Ct23} constant 0 0 -0.1 0 0 0

Key Learnings:

  1. Variables are defined with name = value or name := value
  2. Vertices use xyz for 3D coordinates
  3. Curves can be arc (through 3 points) or straight
  4. Areas use boundary curve to list bounding curves
  5. Model type must be declared before mesh/members
  6. Material, thickness, and section work together
  7. Supports use DOF strings like "uxuyuzrxryrz"

Example 2: Steel Frame with Beams (Cage.fcs)

Demonstrates beam elements, cross-section classes, and distributions.

############################
##   FemCAD script file   ##
############################

#=============================================================================
# DESIGN PARAMETERS
#=============================================================================

D := 0.05           # Tube diameter [m]
a := 0.4            # Inner ladder width (clear)
b := 0.3            # Rung spacing

hC := 2             # Cage height
aC := 0.7           # Cage width
bC := 0.75          # Cage depth  
rC := 0.35          # Cage corner radius

tH := 0.005         # Hoop strip thickness
aH := 0.02          # Hoop strip width
s := 0.5            # Distance between hoops
nHoops := Ceiling(hC/s)    # Calculate number of hoops

dC := 0.010         # Vertical bar diameter
overlap := 0.3      # Bar overlap length

#=============================================================================
# HORIZONTAL HOOPS (using GClass/GBlock)
#=============================================================================

# Define hoop geometry class from external file
gclass 1 filename ("Hoop.fcs") parameters {D = D, aC = aC, bC = bC, rC = rC}

# Instantiate top and bottom hoops
gblock {hoopBottom} gclass 1 lcs GCS 
gblock {hoopTop} gclass 1 lcs (GCS.Tz(hC-aH))

# Distribute hoops vertically
distribution 1 geometries {hoopTop} {hoopBottom} repetitions count nHoops

#=============================================================================
# VERTICAL BARS
#=============================================================================

# Cross-section geometry class for circular section
gclass 2 filename ("Circle.fcs") parameters {D = dC}

# Offset from centerline (half thickness + half diameter)
odOsy := tH/2 + dC/2

# Define vertical bar endpoints
vertex 1 xyz 0 (-bC+odOsy) -overlap 
vertex 2 xyz 0 (-bC+odOsy) hC+overlap

vertex 3 xyz ((-aC)/2+odOsy) ((-bC)+rC) -overlap
vertex 4 xyz ((-aC)/2+odOsy) ((-bC)+rC) hC+overlap

vertex 5 xyz ((aC)/2-odOsy) ((-bC)+rC) -overlap
vertex 6 xyz ((aC)/2-odOsy) ((-bC)+rC) hC+overlap

vertex {v10} xyz (-a/2+odOsy) (-D/2) -overlap
vertex {v11} xyz (a/2-odOsy) (-D/2) -overlap 

# Vertical bar curves
curve 1 vertex 1 2
curve 2 vertex 3 4
curve 3 vertex 5 6

#=============================================================================
# ANALYSIS MODEL
#=============================================================================

material 1                          # Use default material (material ID 1)
cross_section 1 geometry_class 2    # Reference circular cross-section
model_shell3d                       # 3D shell/frame model
OneMeshElementPerBeam = True        # Single element per beam (frame analysis)

#=============================================================================
# BEAM MEMBERS
#=============================================================================

beam 1 type Frame curve 1 xsection 1
beam {b2} type Frame curve 2 xsection 1
beam {b3} type Frame curve 3 xsection 1

# Distribute beams across width
distribution 5 geometries {b2} {v10} repetitions count 4
distribution 6 geometries {b3} {v11} repetitions count 4

Key Learnings:

  1. Use := for mutable variables
  2. Ceiling() is a built-in math function
  3. gclass loads parametric components from external files
  4. gblock instantiates with specific LCS and parameters
  5. GCS.Tz(height) translates in Z direction
  6. distribution creates repeated copies
  7. beam type Frame for 3D frame elements
  8. cross_section geometry_class links section to geometry

Example 3: Variable I-Beam Frame (prFrameMid2.fcs)

Demonstrates variable cross-sections using traction.

#=============================================================================
# FRAME PARAMETERS
#=============================================================================

L := 8              # Total span
LL := L/2           # Left half span
LR := L/2           # Right half span

hL := 4             # Left column height
hP := 5             # Peak height
hR := 6             # Right column height (asymmetric)

# Calculate roof angles  
alfaL := Atan((hP-hL)/LL)    # Left rafter angle
alfaR := Atan((hP-hR)/LR)    # Right rafter angle

OneMeshElementPerBeam = True

#=============================================================================
# VISUALIZATION
#=============================================================================

layer {Primary} color Orange

#=============================================================================
# FRAME GEOMETRY
#=============================================================================

# Corner vertices
vertex 1 xyz 0 0 0          # Left base
vertex 2 xyz 0 0 hL         # Left eave
vertex 3 xyz LL 0 hP        # Ridge
vertex 4 xyz L 0 hR         # Right eave
vertex 5 xyz L 0 0          # Right base

# Frame member curves
curve 1 vertex 1 2          # Left column
curve 2 vertex 2 3          # Left rafter
curve 3 vertex 3 4          # Right rafter
curve 4 vertex 4 5          # Right column

#=============================================================================
# PARAMETRIC CROSS-SECTION
#=============================================================================

# Load I-profile class (height h is parameter)
gclass {gCss} filename "css\I_profile_rotated.fcs"

# Cross-sections at key locations with varying heights
# Note: gbCss1.h references the block's own 'h' property for self-positioning

gblock {gbCss1} gclass {gCss} lcs {Origin={gbCss1.h/2,0,0}, Axes={GCS.Axes}} parameters {h:=0.3}

gblock {gbCss2} gclass {gCss} lcs {
    Origin = {gbCss2.h/2*Cos((-alfaL+PI/2)/2), 0, hL-gbCss2.h/2*Sin((-alfaL+PI/2)/2)},
    Axes = {GCS.Axes.Ry((-alfaL+PI/2)/2)}
} parameters {h:=0.8}

gblock {gbCss3} gclass {gCss} lcs {
    Origin = {LL, 0, hP-gbCss3.h/2},
    Axes = {GCS.Axes.Ry(PI/2)}
} parameters {h:=0.3}

gblock {gbCss4} gclass {gCss} lcs {
    Origin = {LL+LR+gbCss4.h/2*Cos(PI/2+(alfaR+PI/2)/2), 0, hR-gbCss4.h/2*Sin(PI/2+(alfaR+PI/2)/2)},
    Axes = {GCS.Axes.Ry(PI/2+(alfaR+PI/2)/2)}
} parameters {h:=0.8}

gblock {gbCss5} gclass {gCss} lcs {
    Origin = {LL+LR-gbCss5.h/2, 0, 0},
    Axes = {GCS.Axes.Ry(PI)}
} parameters {h:=0.3}

#=============================================================================
# VARIABLE SECTIONS (TRACTIONS)
# Loft between cross-sections for variable-depth beams
#=============================================================================

traction {tBeam1} sections {gbCss1, gbCss2} layer {Primary}   # Column base to haunch
traction {tBeam2} sections {gbCss2, gbCss3} layer {Primary}   # Left rafter
traction {tBeam3} sections {gbCss3, gbCss4} layer {Primary}   # Right rafter
traction {tBeam4} sections {gbCss4, gbCss5} layer {Primary}   # Column to base

Key Learnings:

  1. Atan() calculates arctangent for angles
  2. Cross-sections can have variable heights via parameters
  3. GCS.Axes.Ry(angle) rotates about Y axis
  4. Self-referencing (e.g., gbCss1.h) enables dynamic positioning
  5. traction creates variable-section beams between cross-sections
  6. Complex transforms combine Origin and Axes

Example 4: Array-Based Distribution (BeamPartDistribution.fcs)

Demonstrates iteration with ith for array-driven geometry.

#=============================================================================
# SEGMENT PARAMETERS (Arrays)
#=============================================================================

BeamLength := [2.25, 2, 2, 2]                    # Length of each segment
BeamCssHeights := [0.54, 0.28, 0.24, 0.28, 0.36] # Height at each end (n+1 values)
BeamCssAngle := [-PI/2, -PI/2, -PI/2, -PI/3, -PI/2.5]  # Angle at each end
HeadCut := 0.5                                   # Cut at first segment

#=============================================================================
# BEAM SEGMENT CLASS
#=============================================================================

gclass {gBeam} filename "BeamPart.fcs"

#=============================================================================
# DISTRIBUTION WITH ITERATION
#=============================================================================

distribution {dBeam} gclass {gBeam} 
    lcs {Origin={0,0,0}, Axes=GCS.Axes} 
    transformation translation direction {1,0,0}        # Translate along X
    repetitions count (BeamLength.Count)                # Number = array length
    spacings BeamLength                                 # Use array as spacings
    specialization ithparameters {
        # ith.i = current index (0-based)
        # Access array elements using [ith.i]
        Length := BeamLength[ith.i], 
        HeadCut := ((ith.i==0) ? (HeadCut) : 0),       # Only first segment has cut
        Headh := BeamCssHeights[ith.i],                # Height at start of segment
        Endh := BeamCssHeights[ith.i+1],               # Height at end of segment
        HeadAngleY := BeamCssAngle[ith.i], 
        EndAngleY := BeamCssAngle[ith.i+1]
    }

Key Learnings:

  1. Arrays defined with [value1, value2, ...]
  2. .Count property gets array length
  3. ithparameters provides iteration context
  4. ith.i is the current iteration index (0-based)
  5. Array indexing: array[index]
  6. Ternary operator: condition ? trueValue : falseValue
  7. spacings can be an array for variable spacing

Example 5: Loads with Object Syntax (FitLoadVertex.fcs)

Demonstrates modern object-based load definition.

model_shell3d
OneMeshElementPerBeam = True

fitId := "FitLoadVertex"

#=============================================================================
# LOAD PARAMETERS
#=============================================================================

Name := ""
Description := ""
isOn := True

# Load case definition (object with properties)
LoadCase := { 
    Name := "selfWeight", 
    ActionType := "Variable",       # "Variable" or "Permanent"
    Specification := "",
    LoadType := "Static" 
}

# Transform for load position
Lcs := GCS

# Load components (forces and moments)
Fx := 0
Fy := 0
Fz := 0
Mx := 0
My := 0
Mz := 0

#=============================================================================
# GEOMETRY
#=============================================================================

v1Coords := Lcs.Origin.Point       # Extract point from LCS origin
vertex {v1} xyz (v1Coords.X) (v1Coords.Y) (v1Coords.Z)

#=============================================================================
# VERTEX LOAD (Object Syntax)
#=============================================================================

vl1 = VertexLoad{
    Vertex    := v1,
    Intensity := { Fx, Fy, Fz, Mx, My, Mz },    # 6-DOF intensity
    LoadCase  := LoadCase
}

#=============================================================================
# VISUALIZATION
#=============================================================================

maxFM := [Fx,Fy,Fz,Mx,My,Mz].Select(it => Abs(it)).Max()

isDrawingOn := False
layer {lLoadLayer} color Lime
Length := 1

# Label formatting function (lambda)
strForceFn := val => (val/1000).ToString("# ##0.00 kN")
LabelForceString := strForceFn(Fx) + ", " + strForceFn(Fy) + ", " + strForceFn(Fz)

# Conditional arrow visualization
gclass {ArrowForce} filename "../FcsComponent/ArrowSimpleClass.fcs" parameters {
    Layer := lLoadLayer,
    isDown := True,
    ArrowType := 1 
}

gblock {gbArrowForceX} gclass {ArrowForce} lcs (Lcs.Ry(-PI/2)) if (isDrawingOn and Fx!=0) parameters { Length := Fx/maxFM*Length }
gblock {gbArrowForceY} gclass {ArrowForce} lcs (Lcs.Rx(-PI/2)) if (isDrawingOn and Fy!=0) parameters { Length := Fy/maxFM*Length }
gblock {gbArrowForceZ} gclass {ArrowForce} lcs (Lcs.Ry(PI)) if (isDrawingOn and Fz!=0) parameters { Length := Fz/maxFM*Length }

Key Learnings:

  1. Object literals: { Property1 := value1, Property2 := value2 }
  2. VertexLoad{} creates typed structural objects
  3. Lambda functions: name := param => expression
  4. .Select() and .Max() for LINQ-style operations
  5. Abs() for absolute value
  6. .ToString("format") for number formatting
  7. if (condition) for conditional geometry
  8. String concatenation with +

Common Patterns Summary

Pattern 1: Parametric Input

# Define parameters at top
span := 10
height := 5
load := 25

# Use in expressions
vertex {top} xyz span/2 0 height

Pattern 2: Component Hierarchy

# Load base class
gclass {component} filename "Component.fcs" parameters {param1 := value1}

# Instantiate multiple copies
gblock {inst1} gclass {component} lcs GCS
gblock {inst2} gclass {component} lcs (GCS.Tx(spacing))

Pattern 3: Array-Driven Geometry

heights := [1, 2, 3, 2, 1]
for i in Range(0, heights.Count) {
    vertex {v[i]} xyz i*spacing 0 heights[i]
}

Pattern 4: Conditional Features

hasOpening := True
gblock {opening} gclass {openingClass} lcs (Lcs) if (hasOpening)

Pattern 5: Typed Structural Objects

myLoad = VertexLoad{ Vertex := v1, Intensity := {Fz := -1000}, LoadCase := lc1 }
mySupport = VertexSupport{ Vertex := v2, Conditions := {ux := 0, uy := 0, uz := 0} }

Example 3: Parametric Portal-Frame Building (LabComponents/PortalFrame.fcc/)

A multi-file, fully-updater-driven example in LabComponents/PortalFrame.fcc/ that demonstrates the complete HiStruct building-model pattern at production complexity. Run with:

fli.exe LabComponents/PortalFrame.fcc/Main.fcs L "{B=24, He=6, Hr=8.5, Lb=6, N=5}"

Files

File Role
Main.fcs Top-level assembly — parameters B, He, Hr, Lb, N; frame distribution; siding placement
Frame.fcs Single portal frame (columns + rafters as FEM beams, local XZ plane)
Siding.fcs Building envelope — all wall and roof faces spanning total length L, placed once
Inputs.fcs Fcs.Parameter input page definitions for the HiStruct UI
css/SolidRect.fcs Parametric solid rectangle cross-section

Key patterns demonstrated

1. Updater-driven parameters (Main.fcs)

B   := 20    # building span (m)
He  := 5     # eaves height  (m)
Hr  := 7     # ridge height  (m)
Lb  := 5     # bay spacing   (m)
N   := 4     # number of bays
L   := N * Lb

2. Multi-file component hierarchy with parameter passing

gclass {gcFrame}  filename "Frame.fcs"  parameters {B=B, He=He, Hr=Hr}
gclass {gcSiding} filename "Siding.fcs" parameters {B=B, He=He, Hr=Hr, L=L}

3. Distribution for repeated portal frames

gblock {frame0} gclass {gcFrame} lcs {lcsF0}
gblock {frameN} gclass {gcFrame} lcs {lcsFN}
distribution 1 geometries {frame0} {frameN} repetitions count (N+1)

4. Fcs.Parameter input page (Inputs.fcs)

SpanDef := Fcs.Parameter.ItemDouble{
    HumanName  := "Building span",
    Identifier := NameSpace+"B",
    DefaultUnit := "m",
    Min := 6.0, Max := 60.0, Step := 1.0
}
DimensionsPage := Fcs.Parameter.ItemClass{
    HumanName := "Portal Frame Building — Dimensions",
    Items := [ SpanDef, EavesDef, RidgeDef, BaySpacingDef, BayCountDef, ... ]
}