Appearance
The Calc sheet
The Calc tab (top bar, next to Footings) is a MathCAD-style working document, freehand: click anywhere on the page and type. It is not a form. There is no "add block" button, no name field beside an expression field, no dialog. A line you finish typing is recognised and typeset live; the line your caret is on stays plain text so you are never fighting a re-render while you type.
It exists for the calculations CivilKit doesn't do for you - fire protection, vibration, temporary works, a hand check against the solver's own number - written next to live references into the model, so a value in your working updates when the model does.
Gated behind a setting
The Calc tab is pre-release. Enable it in File ▸ Settings… ▸ Experimental ▸ Calculation document.
Quick start
Open the Calc tab and type:
Bearing check, pad F1.
phi: 0.9
fy: 280
Zex: 1230
phi.Ms: phi * fy * Zex / 1000Press Enter after each line. As soon as you move off a finished line it typeset itself:
φ := 0.9 = 0.9
fy := 280 = 280
Zex := 1230 = 1230
φ.Ms := φ · fy · Zex / 1000 = 309.96 = 0.9 * 280 * 1230 / 1000That's the whole idiom. name: value defines something; a name used later reads it back; a finished line renders as maths with the substituted working shown alongside, exactly the way you'd derive it by hand.
Defining a variable
Any line shaped name: value or name: expression is a calculation:
kt: 0.45
phi.Nt.fire: phi.Nt * kt- MathCAD's own
:=also works -kt := 0.45is identical tokt: 0.45. - Dotted names are fine -
phi.Nt.fire,M.zcat,q.applied- and print with the trailing part as a subscript:φ.Nt.firebecomes φ_Nt.fire. - Greek letters spell themselves: type
phi,alpha,beta,gamma,delta,lambda,mu,rho,sigma,tau,theta,psi,omega,eta,epsilon,nuorpiand it typesets as the symbol. Everything else renders upright as a name. - A literal value is a given and boxes itself.
V.R: 45is highlighted because 45 is a number you typed in, not something derived.A: b * dis not boxed - it's computed from other values. You don't mark this yourself; the sheet can tell the difference. - Only lines above can be referenced. A calc block cannot use a name defined further down the sheet - that's what keeps a sheet acyclic: no circular references, ever.
Functions
The core language is + - * / ^ and parentheses, plus a fixed, whitelisted set of functions - not a general programming language, and not eval: every function is a known, deterministic operation, an unknown name is always an error, and there is no way to define a new one from inside a sheet.
B.req: sqrt(N / q.allow)
util: min(N / q.allow / (B * B), 1.5)
ratio.deg: asin(0.5) * 180 / pitypesets as
B.req := √(N/q.allow) = 2.28
util := min(N/q.allow/(B·B), 1.5) = 0.903
ratio.deg := sin⁻¹(0.5) · 180/π = 30A function wrapping a live @ reference typesets correctly too - sqrt({member:1.phiNt} / 1000) renders as a proper nested radical over the reference, not broken text.
| function | does | notes |
|---|---|---|
sqrt(x) | square root | |
abs(x) | absolute value | |
floor(x), ceil(x) | round down / up | |
round(x), round(x, n) | round to the nearest integer, or to n decimal places | |
min(a, b, ...), max(a, b, ...) | smallest / largest of two or more values | takes 2 or more arguments |
sin(x), cos(x), tan(x) | trig functions | radians - multiply degrees by pi / 180 first |
asin(x), acos(x), atan(x) | inverse trig | result is in radians |
ln(x) | natural log | |
log(x) | log base 10 | MathCAD's own split: ln is natural, log is base 10 |
exp(x) | e^x | |
pi | 3.14159… | a constant, not a function - used bare, no parentheses |
Units by function, following the same logic as +/-/* above:
abs,floor,ceil,roundkeep the unit - the value's physical dimension hasn't changed, only its sign or precision.min/maxkeep the unit when every argument shares one, the same rule+/-already follow; otherwise it drops.sqrt, the trig functions,ln/log/expalways drop the unit - each of these changes the physical dimension of its input (or requires a dimensionless one), and a plausible-looking wrong unit is worse than none.
Reserved names. sqrt, min, max, pi and every function above are reserved - you can define a variable with one of those names, but a bare use of the name in an expression always means the built-in, never your variable. Simplest just to avoid naming a variable sqrt or pi.
What's still not there: ^ still needs a literal exponent - x ^ 2 works, x ^ n where n is a variable does not; sqrt(x) (or x ^ 0.5) is how you write a square root either way.
Comparisons and branching
<, <=, >, >=, ==, != compare two values, and if(condition, a, b) picks between two results - the piece a real calc sheet needs for a loss-of-contact check, a code-limit check, or anything else that reads "if this, use that":
e: M / N
q.max: if(e <= B/6, N/A * (1 + 6*e/B), 2*N/(3*(B/2-e)))typesets as
e := M/N = 0.42
q.max := if(e ≤ B/6, N/A · (1 + 6·e/B), 2·N/(3·(B/2-e))) = 187.3if() evaluates both branches before picking one - there's no lazy/short-circuit evaluation, so neither branch can divide by a value that would be zero specifically in the case that branch is meant to avoid.
and(a, b, ...), or(a, b, ...) and not(x) combine conditions - and/or take two or more arguments:
ok: if(and(e <= B/6, N > 0), 1, 0)Comparisons never chain. 0 < x < 10 is a parse error, not silently read left-to-right - 0 < x < 10 reads as a range to a person, but (0 < x) < 10 to most languages that allow it, and those are two different answers from the same six characters. Write it as and(x > 0, x < 10) instead.
Units. A comparison's result is a fact (true/false), never a physical quantity, so it never carries a unit regardless of its operands' units. if() keeps the unit only when both branches agree - same rule as min/max - and the condition's own unit is irrelevant to the result. and/or/not always drop the unit, same as a comparison.
if, and, or, not are reserved names, same as every function in the table above.
Headings and structure
Markdown's own convention, because it's what people already type:
# Wind Design Actions
## 1) Derivation of Design Wind Speeds# gives you a large underlined heading, ## a sub-heading, ### a smaller one. A plain line with neither a heading mark nor a name: shape is prose - free text, exactly as typed.
The clause column
A trailing | ... on any line becomes the right-hand margin note - the code clause or a short remark, exactly where a reviewer looks for it on a printed calc sheet:
M.zcat: 0.91 | Tbl 4.1
Not in lee zone | Cl 4.4.3| can't appear inside an expression, so there's no escaping to remember - just add it at the end of the line.
Referencing the model: @
Type @ anywhere and a search opens over two things: your own variables defined above the caret, and live values from the model - footing results, member capacities, node reactions and displacements.
q.applied: @Typing narrows it, ↑/↓ moves the selection, Enter or Tab accepts. Picking a model value is two steps: first the entity (a footing mark, M12, N5), then that entity's field. The result is inserted as a live reference - not a copied number - so if the model changes and you re-solve, the value in your sheet changes with it.
Available today:
| domain | fields |
|---|---|
| footing | B, L, D, cover, q_max, q_allow, util_bearing, util_punching, A_st_x, A_st_y |
| member | phiMs, phiMb, phiMsy (minor-axis), phiNt, phiVv, Ze, fy, util (governing utilisation) |
| node | Rx, Ry, Rz (reactions), Mx, My (moment reactions), ux, uy, uz (displacements) |
Units are handled for you - a member capacity reads in kN/kN·m, not the raw SI newtons the solver works in, and the unit shown is always the unit of the number next to it. member and node fields need @env (the picker adds this automatically) - that means governing value across every solved load case, sign kept, so a reaction of -28 kN stays negative because the direction matters.
A refused check is never a silent zero
If a value hasn't been computed - punching shear that the engine declined to check, a footing that hasn't been designed yet - the reference shows a dashed marker with the reason, never 0.00. That is the one rule this whole feature exists to protect: a stamped calculation must never show a passing number for something that was never actually checked.
Diagrams and contours: !
Type ! the same way you type @ - it opens a list of diagram kinds, and picking one immediately opens the second question (which member, or which plate field):
!bmd 3draws the bending moment along member 3, taken from its solved stations on the governing load case - filled to the axis, drawn on the tension side (the usual convention), the peak value called out where it occurs.
Member diagrams (!kind memberNumber):
| kind | draws | unit |
|---|---|---|
bmd | bending moment along the member | kN·m |
sfd | shear force along the member | kN |
axial | axial force along the member | kN |
defl | deflected shape along the member | mm |
Plate contours (!contour field):
!contour mxdraws the chosen field over the whole plate mesh in plan - one polygon per element region, smoothly shaded rather than a flat block per element. The shading is nodal-averaged and bilinearly interpolated: values are averaged at nodes shared between elements (what any FEA package means by a "nodal" contour), then interpolated across each element using the element's own shape function - so the colour at any point is the value the element would actually report there, not a blur filter. The mesh outline is drawn on top, so a coarse mesh still visibly looks coarse behind the smooth field.
| field | draws | unit |
|---|---|---|
mx | bending moment about the local x-axis | kN·m/m |
my | bending moment about the local y-axis | kN·m/m |
mxy | twisting moment | kN·m/m |
vm | von Mises stress | MPa |
Both diagram kinds pick the governing load case by peak magnitude, the same case a @ reference next to them would resolve against - so a diagram and a number on the same sheet can never quietly come from different solves.
Images
Paste an image anywhere on the sheet (screenshot, a phone photo of a trial pit, a scanned manufacturer chart) and it lands as its own line, downscaled automatically so the model file doesn't balloon. It travels with the model exactly like everything else on the sheet.
Saving, printing and the report
- The sheet saves with the model - it's part of the
.sgfile, and it also survives a browser refresh through session autosave. Nothing extra to do. - PDF (top-right of the Calc tab) prints just the sheet on its own - references become plain inline text (
F1.q_max (governing)rather than a coloured chip), diagrams and contours print as vector images, and an unresolved reference keeps its warning in the printed page too. This is a one-off export; it doesn't touch your report's configuration. - The full report can include the sheet as a section - open File ▸ Report, turn on Calculation sheet under Report content, and it appears wherever you've placed it in the report order.
Worked example: a fire check the solver doesn't do
FIRE PROTECTION - GOVERNING COLUMN
AS 4100 Section 12. CivilKit has no fire module, so this is the engineer's own working,
wired to the model.
kt: 0.45
phi.Nt: {member:1.phiNt}
phi.Nt.fire: phi.Nt * kt
util.ambient: {member:1.util@env}
N.fire: util.ambient * phi.Nt * 0.7
util.fire: N.fire / phi.Nt.fire
Adequate in fire when the utilisation above is below 1.0.(The {member:1.phiNt} form is what a @-picked reference actually stores - you never type this by hand, the picker inserts it for you.)
Worked example: wind actions with the clause column
# Wind Design Actions
## 1) Derivation of Design Wind Speeds
Location: Tauranga, design working life 50 years | AS/NZS 1170.0
V.R: 45 | Tbl 3.1
M.d: 1.0 | Tbl 3.2
h: 5 | reference height
b: 20 | width in wind direction
d: 15 | length in wind direction
A: b * d | plan area
TC: 2 | Cl 4.2.1
M.zcat: 0.91 | Tbl 4.1
V.site: V.R * M.d * M.zcat | Cl 2.2V.R, M.d, h, b, d, TC and M.zcat are all boxed automatically (they're literals - the givens); A and V.site are not (they're derived from the lines above).
What's not there yet
- No units on your own variables -
V.R: 45is a bare number; a live model reference does carry its unit, a typed-in value does not yet. - No named load combinations for
member/nodereferences - only@env(governing) resolves today. - No way to save a sheet as a reusable template across models (see below).
Roadmap: saved sheets / templates
Saving a sheet as a personal template - so a fire check, a wind derivation or a standard cover note can be dropped into a new model without retyping it - is planned but not built. Today the way to reuse a sheet is to copy the text out of one model's Calc tab and paste it into another's; the @ references will need re-picking against the new model's entities (a reference is stored against a stable id, and that id doesn't exist in a different model).