Introduction
CivilKit Calcs is an engineering calculation sheet that runs in your browser. You write a calculation as readable text, with quantities, units, formulas and notes, and the page works it out and shows a formatted report. You can plot the results, export the report to Word, Excel or PDF, and keep working with no network connection.
Everything is calculated on your own computer. The engine is compiled to WebAssembly and runs inside the page, so a calculation is never sent to a server.
Try it. Open CivilKit Calcs in a new tab and start typing, or begin from a worked example in Calculators and guides: a beam, a retaining wall, a pad footing, a pipe or a pump, each of which opens as a form. The product page gives the short overview.
What you get
- Real units.
6 m,12 kN/m,300 MPa. The engine multiplies, divides and converts them, and it refuses to add a length to a time. A moment comes out in kilonewton metres because the units said so, not because you typed a label. - Two ways to write. The sheet format is Markdown prose with
name: valuelines. The Calcpad worksheet language (.cpd) is the full language of CalcpadCE, with macros, input forms and every directive. Both run on the same engine, and a sheet can show you the Calcpad it becomes. - Vectors, matrices and a large function library. Linear solves, eigenvalues, interpolation, numerical integration, root finding and more.
- Plots. A one-line
plotcommand, the Calcpad$Plotand$Mapcommands, and a Python block that draws with a matplotlib-style or Plotly-style interface, including 3D charts. - Python blocks. Small Python programs inside a sheet, run in the page, with results handed back to the sheet as ordinary quantities.
- Templates with inputs. Put a
?in front of a value (L: ? 6 m) and it becomes a box, a drop-down, radio buttons or a checkbox in a fill-in form. A template is one file. - Symbolic maths. Rearrange a formula, differentiate, integrate or solve exactly.
- A worksheet importer. Bring in worksheets from another calculation tool.
- Export. Word with real equations, Excel with native charts, and PDF through the print dialog.
- Free and open source. The source is on GitHub under the MIT licence.
Where to start
If you have never used it, open Your first sheet and follow it through once. It takes about five minutes. After that, read The sheet format, which describes everything you can write on a sheet line. The later chapters are independent: read the ones you need.
Each chapter that matches a short how-to video carries a line starting with “Video:”. The
videos are recorded from the scripts in the book/videos folder of the source.
The videos
Each video has an Enlarge button in its top right corner that opens it large over the page; Esc closes it again.
| Video | Length | Chapter |
|---|---|---|
| 1. Your first calculation in five minutes | 85 seconds | Your first sheet in five minutes |
| 2. Units and results | 85 seconds | Units |
| 3. Plots in the sheet format | 80 seconds | Plots |
| 4. Plots from Python (Plotly style and matplotlib style) | 90 seconds | Python blocks |
| 5. Templates with inputs | 85 seconds | Templates with inputs |
| 6. Import an existing worksheet | 90 seconds | Importing worksheets |
| 7. Symbolic maths for a beam deflection | 90 seconds | Symbolic maths |
| 8. Export a report to Word, Excel and PDF | 85 seconds | Exporting |
The lengths are the planned ones in the storyboards.
Credit
CivilKit Calcs is built on CalcpadCE, the continuation of Calcpad by Nedelcho Ganchovski (Proektsoft) and contributors. The worksheet language, the editor support and the sample worksheets all come from that work. See Credits and licences.
A note on the examples
Every sheet and cpd example in this guide was run through the real engine when the guide was
built (book/check-examples.sh). The results shown beside them are what the engine printed, with
the default setting of two decimals. The seven template sheets quoted in Templates with
inputs are checked to be identical to the samples the app ships. The Python examples
and the input forms need the browser: they are run in the built app (book/check-python.mjs),
which also counts the controls each form draws.
Your first sheet in five minutes
Video: Your first calculation in 5 minutes
This walk-through builds a bending check for a simply supported beam. You will type a few lines, see units work, add a pass or fail message and change a number.
1. Open a new sheet
Open https://civilkit.io/calcs/ . The first tab is a short welcome sheet. To start your own, use File > New sheet, or the New button at the top left. A sheet opens with a few lines of example text. Select all of it and delete it. The editor is on the left and the result is on the right.
A sheet is a plain text file. Its first line is
<!--sheet-->, which the editor adds for you.
2. Type the inputs
Type these lines. Each one is a quantity line: a name, a colon, a value with a unit, and after
a bar | a note.
# Beam check
A simply supported beam under a uniform load.
L: 6 m | span
w: 12 kN/m | design load
The result pane shows the heading, the sentence, and two lines like these:
L = 6 m span
w = 12 kN/m design load
The result updates as you type. If it does not, press Calculate on the Calculation tab, or Ctrl+Alt+X.
3. Calculate with units
Add a line below the inputs:
L: 6 m | span
w: 12 kN/m | design load
Mstar: w * L^2 / 8 -> kN*m | maximum bending moment
The result shows the formula, the numbers put in, and the answer:
M⋆ = w·L²/8 = 12 kN/m · (6 m)² / 8 = 54 kN·m maximum bending moment
Three things happened:
Mstarwas written as M with a subscript “star”. A name that ends instarafter a capital letter becomes a subscript. Greek names work the same way:phiis φ,sigma_cis σ with a subscript c.^is a power.L^2is L squared.-> kN*masked for the answer in kilonewton metres. Without it the engine picks a unit itself, which here is also kN·m. Write->when you want to be sure which unit you get, or a different one (-> N*mm).
4. Add a capacity and a check
Now add the section capacity and a utilisation ratio. This is the complete sheet:
# Beam check
A simply supported beam under a uniform load. The moment **comes out in kN·m** because the
engine tracks the units.
L: 6 m | span
w: 12 kN/m | design load
Mstar: w * L^2 / 8 -> kN*m | maximum bending moment
fy: 300 MPa | yield stress
Ze: 1230000 mm³ | section modulus
Ms: fy * Ze -> kN*m | moment capacity
utilisation: Mstar / (0.9 * Ms)
if utilisation <= 1: "OK" else: "Fails"
The result ends with:
Ms = fy·Ze = 300 MPa · 1230000 mm³ = 369 kN·m moment capacity
utilisation = M⋆ / (0.9·Ms) = 54 kN·m / (0.9 · 369 kN·m) = 0.163
OK
Look at the Ms line. A stress in megapascals times a volume in cubic millimetres came out as a
moment in kilonewton metres. You did not convert anything. The utilisation line divides a
moment by a moment, so the units cancel and it is a plain number.
The last line is a one-line condition. It prints the text OK when the ratio is at most 1 and
Fails otherwise.
5. Change a number
Change w: 12 kN/m to w: 80 kN/m. The moment becomes 360 kN·m, the ratio 1.08, and the last
line reads Fails. Everything after the changed line recalculates as you type.
6. See what the sheet compiles to
A sheet is turned into the Calcpad worksheet language, and the engine runs that. To see the translation, open the Resources tab and choose Show compiled. For the sheet above it is:
'<h1>Beam check</h1>
#markdown
A simply supported beam under a uniform load. The moment **comes out in kN·m** because the
engine tracks the units.
#end markdown
L = 6 m
w = 12 kN/m
M_star = w * L^2 / 8|kN*m
fy = 300 MPa
Ze = 1230000 mm^3
Ms = fy * Ze|kN*m
utilisation = M_star / (0.9 * Ms)
#if utilisation ≤ 1
'OK
#else
'Fails
#end if
(In the compiled view each note is kept as a comment at the end of its line.) You can read it as
a short lesson in the Calcpad language: |kN*m is the conversion, #if … #end if is the
condition. The language is covered in The Calcpad language. Convert to
Calcpad, next to Show compiled, replaces the sheet with that text, for when you want to leave
the sheet format for good.
7. Save it
Press Ctrl+S (Cmd+S on a Mac). In browsers that can write files, you choose a place and the sheet
is saved as a .sheet file. In other browsers the file downloads. See
Saving, opening and working offline.
Where next
- All the line kinds: The sheet format.
- Why the units came out right: Units.
- Draw the moment along the beam: Plots.
- Turn the sheet into a form you fill in: Templates with inputs.
Related calculators: Simply supported beam, Cantilever beam. More pages are in Calculators and guides.
The screen
The window has five parts.
+-------------------------------------------------------------+
| (suite bar, wide browser windows only) |
| File New Open Save Undo Redo |
| Math | Input/Output | Functions | ... | Resources | ribbon
| [groups of buttons for the selected tab] |
+----------------------------+-----------------------+--------+
| tab: Beam check | Results |Sidebar |
| | Preview Unwrapped | Insert |
| editor | Input Report | ... |
| | | |
+----------------------------+-----------------------+--------+
The ribbon
A quick-access strip at the top holds New, Open, Save, Undo and Redo. Under it
are ten tabs. In a sheet the buttons insert the sheet form of each item, and a button that has no
sheet form inserts Calcpad text as >> lines and carries a small >> mark.
| Tab | What is on it |
|---|---|
| Math | Regions (math line, text, heading, image, plot, table), operators, Greek letters and symbols, programming (conditions, loops, macros), constants, numerical methods, units, clipboard. |
| Input/Output | Input fields: entry, slider, dropdown, radio, checkbox (the ? form in a sheet, #UI in a worksheet), data grid; reading and writing files; breakpoints; the Input form view. |
| Functions | Trigonometric, hyperbolic, logarithmic, rounding, statistical, logical, complex and other functions; define a function; the Symbolic dialog. |
| Matrices/Tables | Vector and matrix literals, vector and matrix functions, determinant, inverse and transpose, tables. |
| Calculation | Calculate, auto-calculate, the four result views, settings, and the Variables and Errors lists. |
| Plots & Diagrams | Function, parametric, multiple and colour-map plots; plot settings; the Figures group: the Diagrams menu of starter diagrams (see Diagrams) and Image. |
| Math Formatting | Rounding, number format, angle units, output control (#hide, #val, #nosub and so on). |
| Text Formatting | Headings, bold, italic, colours, links, lists, rules, page break. In a sheet these write Markdown. |
| Document | Import worksheet, the tidy tools, header and footer, page break, the report, contents, metadata, and Save as, Print PDF, Word, Excel and Export. |
| Resources | Samples, library, New sheet, New Calcpad, Show compiled, Convert to Calcpad, themes, zoom, the sidebar and Settings, help. |
The tabs follow the work: write (Math to Matrices/Tables), calculate, plot, format, then the document. Hover over a button for what it inserts or does; where it teaches syntax the tooltip shows the typed form.
The editor
The editor is on the left, one tab per open file. It colours the text, completes names, Greek spellings and function names, and underlines mistakes. Hover over a name to see where it is defined; F12 jumps to the definition. Format Document (Shift+Alt+F) tidies a sheet. See Editing.
The results
The right-hand pane shows the calculated worksheet. The Calculation tab chooses between four views:
- Preview: the document as written, with every
#preand#postpart. This is the usual view while you work. - Unwrapped: the source listing with macros and includes resolved. Useful for finding errors in macros.
- Input: the fill-in form of a sheet or worksheet that has inputs (
L: ? 6 min a sheet,#UIin a worksheet). See Templates with inputs. - Report: the print layout, as it will come out in a PDF or Word file.
Results update as you type; Auto-calculate can be turned off on the Calculation tab, and then Calculate (Ctrl+Alt+X, and F5 in the desktop app) runs the sheet on demand.
Under a plot there is a row of small buttons (log axes, 1:1, copy data, save as PNG or SVG). These are in the preview only and are not part of a printout or export.
The sidebar
The sidebar holds the Insert tab, a searchable library of every symbol, function, unit and snippet (a click inserts it at the cursor), and tabs for the table of Contents and the Variables of the worksheet. Settings, Export, Errors and Prettify open as dialogs over the page. Hide the sidebar with the button at its top right, or Resources > Sidebar (Ctrl+Shift+B in the desktop app).
Settings
The gear at the right end of the top strip opens Settings (so do Calculation > Calculation settings and Resources > Settings). It has five tabs:
| Tab | What is on it |
|---|---|
| General | Language, number format, and the appearance (colour theme, preview theme). |
| Calculation | Decimals, angle units, complex numbers and the other math settings, plot defaults, US or UK units. |
| Editor | Quick typing, comment format, formatting keys, auto-run, cursor sync, the linter. |
| Export | The PDF page: paper size (A4 or Letter by the browser’s region until you choose one), orientation, margins, header and footer. |
| Advanced | Script libraries, logging and limits, the server address, saved configurations. |
The search box above the tabs looks through all of them and lists each match under its tab’s name; clear it to get the tabs back. Settings opens on the tab you last used, until the browser tab is closed. Calculation settings opens it on Calculation, and Document > Header and footer on Export. On the tab strip, the arrow keys, Home and End move between the tabs.
On a phone
At 760 pixels wide or less, one pane shows at a time, switched from a bar along the bottom: Edit, Results and Insert. The ribbon starts folded; tap an open tab to fold it. See Editing for touch editing.
Saving, opening and working offline
The File menu
The File button at the top left of the ribbon opens a menu:
| Item | What it does |
|---|---|
| New sheet | A new sheet in a new tab. |
| New Calcpad worksheet | A new .cpd worksheet, the advanced syntax. |
| Open… | Opens a .sheet, .cpd or .txt file. Data files and pictures you pick join the library. |
| Import worksheet… | Converts a worksheet from another tool. See Importing worksheets. |
| Samples… | The sample browser. See Samples tour. |
| Save, Save as… | Saves the active tab. |
| Print PDF…, Export…, Export Excel… | See Exporting. |
Below the commands are the Recent worksheets and the Library. The library holds the files
that #include and #read use: data files, pictures, shared definitions. Everything you open
or drop on the page goes into it. It is stored in your browser.
You can also drag a file onto the page. A .cpd or .sheet file opens in a tab, and any other
file joins the library.
Saving
Press Ctrl+S (Cmd+S on a Mac), or use Save in the quick-access strip. Ctrl+Shift+S is Save as.
- In a browser that can write files in place (Chrome and Edge on a computer), you choose a file once and later saves write to it.
- In other browsers the file downloads each time you save.
A sheet is saved with the extension .sheet and a Calcpad worksheet as .cpd. Both are plain
text. You can open them in any text editor and keep them in version control.
Saving is manual. Nothing you type is uploaded anywhere, and the browser keeps no copy of unsaved text, so save before you leave.
Knowing what is unsaved
A document has unsaved changes when its text differs from what Save or Save As last wrote.
- Its tab shows a dot (●) after the name, and the browser tab’s title starts with ● while that document is the active one.
- Undoing back to the saved text clears the dot again.
- Closing a tab with unsaved changes asks Save, Don’t Save or cancel (click outside the box).
- Closing or reloading the browser tab while any document has unsaved changes makes the browser ask whether to leave. The wording of that box is the browser’s own.
Print PDF, Word and Excel exports are copies of the report. They do not save the document, so the dot stays until you save it.
Working offline
CivilKit Calcs is a progressive web app. After one visit the whole app (about 22 MB) is cached by the browser, and it opens and calculates with no connection. To make it behave like an installed program, use your browser’s Install or Add to home screen command.
The page’s own files include the calculation engine, the Word and Excel writers, the importer, the Python runtime and the Symbolic dialog, so all of them work offline after the first visit. The one exception is the Plotly chart script: interactive Plotly charts from Python blocks load the Plotly script from its CDN the first time a chart is shown, and cache it after that. Without it the chart’s place shows a note instead of a blank. See Python blocks. The first visit itself needs a connection, and so does installing the app.
When a new build is available the app tells you with a small box (Reload and Later). It never reloads by itself, so unsaved work is safe.
Themes
The Resources tab has Light and Dark. Adding ?theme=dark or ?theme=light to the address forces
the theme for that visit.
The sheet format
A sheet is a calculation written the way you would explain it to a colleague: Markdown
prose, plain name: value lines, and LaTeX where you want a typeset formula. The sheet compiler
turns it into the Calcpad worksheet language and the engine runs that. There is no second engine:
units, vectors, matrices, plots, and the Word and Excel exports all work because the engine sees
an ordinary Calcpad worksheet.
A file is a sheet when its first non-blank line is <!--sheet-->, or when its name ends in
.sheet. The editor adds the marker line for you.
A whole sheet
# Beam bending check
A simply supported beam. The moment **comes out in kN·m**.
L: 6 m | span
w: 12 kN/m | design load
Mstar: w * L^2 / 8 -> kN*m | maximum bending moment
Ms: 300 MPa * 1230000 mm³ -> kN*m
utilisation: Mstar / (0.9 * Ms)
if utilisation <= 1: "OK" else: "Fails"
The result:
Beam bending check
A simply supported beam. The moment comes out in kN·m.
L = 6 m span
w = 12 kN/m design load
M_star = w·L²/8 = 12 kN/m · (6 m)² / 8 = 54 kN·m maximum bending moment
Ms = 300 MPa · 1230000 mm³ = 369 kN·m
utilisation = M_star / (0.9·Ms) = 54 kN·m / (0.9 · 369 kN·m) = 0.163
OK
The line kinds
Every line of a sheet is one of these.
| Line | Looks like | Chapter |
|---|---|---|
| Prose | A simply supported beam. or ## Heading | Prose, LaTeX and tables |
| Quantity | L: 6 m | span | Quantities and notes |
| Input | L: ? 6 m | span | Templates with inputs |
| Section marker | ## Workings {collapse}, M: ... {key}, {key results} | Folding sections and key results |
| Function | f(x): x^2 + 1 | Functions |
| Condition | if u <= 1: "OK" else: "Fails" | Conditions and loops |
| Block | for i in 1..5: with an indented body | Conditions and loops |
| Plot | plot M(x) for x in 0..L | Plots |
| Python | a fenced python block | Python blocks |
| Diagram | a fenced mermaid block | Diagrams |
| Calcpad | a line starting with >>, or a calcpad fence | Mixing in Calcpad |
A line that looks like a quantity but is really prose (Note: see the drawing) is prose, because
its right-hand side is not an expression. To force prose, start the line with a backslash.
A page to keep open
The quick reference puts the sheet language on one page that prints: every line kind and input, the functions, constants, operators and units of the engine. It has a Print button, and it is also what to hand to a colleague who has not used a sheet before.
What a sheet cannot do
- There is no symbolic algebra in the sheet itself. The engine is numeric. Use the Symbolic dialog to derive a formula and paste it in.
- A vector or matrix literal cannot carry a unit after the bracket (
[1, 2] kN). Put the unit on the elements. - A formula is typeset in the page, but in Word and Excel it appears as its TeX source in italics.
- Convert to Calcpad works one way. Calcpad text is not turned back into a sheet.
Everything else in the Calcpad language is reachable by passing lines through. See Mixing in Calcpad.
Quantities, units and notes
A quantity line defines a name:
name: expression [-> unit] [| note]
name = expression
a: 1; b: 2 | note for b
The colon and the equals sign both work. The result shows what an equation line shows in Calcpad: the name, the formula, the numbers put in, and the answer with its unit.
Names
A name is made of letters, digits, _ and primes. Greek spellings become Greek letters:
phi: 0.9
sigma_c: 25 MPa
Delta_T: 40 K
phiMs: phi * 369 kN*m
Mstar: 54 kN*m
φ = 0.9
σ_c = 25 MPa
Δ_T = 40 K
φMs = φ · 369 kN·m = 0.9 · 369 kN·m = 332.1 kN·m
M_star = 54 kN·m
phiis φ,sigma_cis σ with a subscript c,Delta_Tis Δ with a subscript T.- A Greek spelling followed by a capital or a digit (
phiMs,sigma2) is the letter and the rest. - Capital Greek letters are written only where they differ from a Latin capital:
Gamma,Delta,Theta,Lambda,Xi,Pi,Sigma,Upsilon,Phi,Psi,Omega. - A name that ends in
starafter a capital or a digit (Mstar) is that name with the subscriptstar. - The first
_in a name starts the subscript:my_long_name_2is shown asmywith the subscriptlong_name_2, as Calcpad writes it. Names with digits and several underscores calculate normally; only the way they are typeset changes.
The same rule renames every use of a name, so you spell it one way throughout the sheet. Inside
>> lines and calcpad fences the sheet’s spelling is used too: phi in a raw line is φ.
Units
Write a unit after a number. The engine checks and combines them:
a: 2 m; b: 350 mm
A: a * b -> m^2
v: 90 km/h -> m/s
t: 2 h + 30 min -> min
F: 10 N * 3 m -> J
a = 2 m
b = 350 mm
A = a·b = 2 m · 350 mm = 0.7 m²
v = 90 km/h = 25 m/s
t = 2 h + 30 min = 150 min
F = 10 N · 3 m = 30 J
²and³after a name or unit are^2and^3.mm³andmm^3are the same.- A unit written after a number is never renamed, so
3 psiis a pressure andpsialone would be the Greek letter ψ. - Adding a length to a time is an error. Multiplying and dividing them is fine.
- Several units in a sum convert to the first:
5 m + 30 cmis5.3 m.
The whole subject, with the unit list and custom units, is in Units.
Converting the answer: ->
-> unit converts the result. It must come last, before the note:
Mstar: 12 kN/m * (6 m)^2 / 8 -> kN*m | maximum bending moment
Mnmm: Mstar -> N*mm
M_star = 12 kN/m · (6 m)² / 8 = 54 kN·m maximum bending moment
Mnmm = M_star = 54 kN·m = 54000000 N·mm
Without -> the engine chooses the unit itself, from the units in the formula. Use -> when you
want a particular unit in the result, and always when the result goes into a report.
Notes
The first | outside brackets starts a note, a short comment shown beside the result in a muted
style. || is the logical or, not a note. A note can contain LaTeX (| load at stage $i$).
Several per line
Separate quantities with ;. A note belongs to the last one:
a: 3; b: 4 | note for b
c: sqrt(a^2 + b^2)
a = 3
b = 4 note for b
c = √(a² + b²) = √(3² + 4²) = 5
Numbers and operators
- You can write
1.23e6or2.5e-3. The engine has no exponent notation, so the compiler writes the plain number (1230000,0.0025) and that is what the result shows. - Operators are
+ - * / ^ %and the comparisons< > <= >= == !=, withandandor. The Unicode forms≤ ≥ ≠ ≡ ∧ ∨ × · ÷ −work too. In a condition a single=also means equal. - Calls take commas:
max(a, b). The compiler writes the semicolon the engine wants. - Use
abs(x)for an absolute value, not bars. π(orpi) andeare built in. The other constants in the Insert tab (gravity, the speed of light, unit weights and so on) are snippets that insert a definition line such asg = 9.80665m/s^2; until you insert one,gis the unit gram. See the reference.
Vectors and matrices
v: [1, 2, 3]
A: [2, -1; -1, 2]
[1, 2, 3] is a vector; [1, 2; 3, 4] is a matrix with columns separated by commas and rows by
semicolons. See Vectors and matrices.
Inputs: a quantity the reader can change
Put a ? in front of the value and the quantity becomes an input, with that value as its default:
L: ? 6 m | span
w: ? 12 kN/m | design load
M: w * L^2 / 8 -> kN*m | maximum moment
In Input mode L and w are boxes. Everywhere else the lines read as the quantities they are. A
list of options ([Steel = 200 GPa, Timber = 11 GPa], or round brackets for radio buttons) and
on or off (a checkbox) are inputs too. See Templates with inputs.
Prose, LaTeX and tables
Anything that is not one of the line kinds is Markdown prose. Use it to say what is being checked, to state assumptions and to explain results.
Markdown
Supported Markdown: headings (# to ######), paragraphs, **bold**, *italic*, bulleted
(-) and numbered lists, pipe tables, links,  images from the library, `code`
and fenced code blocks. Blank lines between sections are kept.
A plain paragraph, even over several lines, becomes one text line. Only prose that really contains Markdown (lists, tables, quotes, emphasis, links, code) is passed to the engine’s Markdown renderer.
LaTeX
$...$ is an inline formula and $$...$$ a display formula, in prose, in notes and in the text
of an if line. A $$ alone on a line opens and closes a multi-line formula. \$ is a dollar
sign, and a $ before a digit (“$5”) is one too.
A pipe of diameter $d$ carries a flow $Q$. The mean velocity is
$$v = \frac{4 Q}{\pi d^2}$$
d: 0.2 m
Q: 0.05 m^3/s
v: 4 * Q / (π * d^2) -> m/s
A pipe of diameter d carries a flow Q. The mean velocity is
4Q
v = ----
πd²
d = 0.2 m
Q = 0.05 m³/s
v = 4·Q / (π·d²) = 4 · 0.05 m³/s / (3.14 · (0.2 m)²) = 1.59 m/s
The page typesets formulas with KaTeX, which is bundled with the app and loaded the first time a sheet has a formula, so formulas work offline. A formula that cannot be typeset is shown as its TeX source. In the LaTeX of a sheet, variable names take the same blue as in an equation. In Word and Excel a formula appears as its TeX source in italics, not as Office Math.
Tables
A pipe table is prose, with the engine’s table styling:
| Action | Symbol | Value |
|------------|--------|-------|
| Permanent | G | 4.5 kPa |
| Imposed | Q | 3 kPa |
G: 4.5 kPa
Q: 3 kPa
w_uls: 1.2 * G + 1.5 * Q -> kPa | strength combination
Action Symbol Value
Permanent G 4.5 kPa
Imposed Q 3 kPa
G = 4.5 kPa
Q = 3 kPa
w_uls = 1.2·G + 1.5·Q = 1.2 · 4.5 kPa + 1.5 · 3 kPa = 9.9 kPa strength combination
The table is text. It does not feed the calculation, so type the numbers again in quantity lines, or define the quantities first and mention them in the table text.
In the preview, click a column heading to sort the rows by it (again for descending, a third time for the source order). It is a view only: the sheet, the printout and the exports keep the order you wrote. See Sorting a table.
Diagrams
A fenced block tagged mermaid is drawn as a diagram in the results: boxes and arrows, a flow
chart, a sequence or a timeline, written as text in Mermaid’s syntax.
# Load path
```mermaid
graph TD
Slab --> Beam
Beam --> Column
Column --> Footing
```
G: 4.5 kPa
The drawing comes from the text, so editing the fence redraws it. Diagrams starts from three small examples (a flow chart, a sequence and a state diagram) and gives tips, what prints and what exports.
Forcing prose
A line starts with a backslash when it must not be read as a quantity:
\L: 5 is shown as text
Note: see the drawing
Note: see the drawing is already prose, because “see the drawing” is not an expression.
Diagrams
A diagram is written as text in a fenced block tagged mermaid, and the results draw it. Type the
steps, the app draws the boxes and arrows. Edit the text and the drawing follows. The language of
the fence is Mermaid’s, and the app bundles Mermaid 12.1.0, which draws more than thirty kinds of
diagram and chart: flow charts, sequence and state diagrams, Gantt charts, pie and XY charts,
Sankey diagrams, mind maps and more.
This chapter is a gallery: one small example of each kind, grouped by what it is for. Copy one
into a sheet to see it drawn, then change it. A kind whose first word ends in -beta is new in
the diagram library, and its syntax may still change in a later version. The kinds that are not
available are listed at the end, and the samples
show diagrams next to the calculations they describe.
Starting from the ribbon
The Diagrams menu in the Figures group of the Plots & Diagrams tab of the ribbon inserts a short starter
diagram, so there is no syntax to learn before the first one. Put the caret where the diagram
should go and pick a kind: flowchart, sequence, state, block, architecture, entity relationship,
requirement, tree view, mind map, fishbone, Gantt, timeline, pie, XY chart, quadrant, radar,
Sankey or treemap. In a sheet the starter goes in as a block of its own after the paragraph or
block the caret is in; in a Calcpad worksheet it goes in a #markdown block after the caret’s
line. Its text is left selected, ready to edit, and Undo takes it out in one step. The menu offers
the kinds engineers use most; the other kinds can be typed by hand, and the gallery below shows
them all.
A diagram does not read the sheet’s numbers. Work a value out with a quantity line and type it into the diagram, as the samples do.
Processes and behaviour
Flow chart
flowchart TD draws from top to bottom (LR draws from left to right). A box is a name and its
label in square brackets, a decision is in braces, and --> is an arrow. Text between -- and
--> labels the arrow.
# Design check
```mermaid
flowchart TD
A[Design moment M*] --> B{M* <= phi Ms?}
B -- yes --> C[Section passes]
B -- no --> D[Choose a deeper section]
D --> A
```
Mstar: 54 kN*m | design moment
phiMs: 332 kN*m | design capacity
if Mstar <= phiMs: "OK: the section passes." else: "Fails: choose a deeper section."
Sequence diagram
sequenceDiagram draws people or parts side by side and the messages between them, in order from
the top. ->> is a solid arrow and -->> a dashed one.
# Review of the calculation
```mermaid
sequenceDiagram
participant D as Designer
participant C as Checker
D->>C: Calculation for review
C-->>D: Comments
D->>C: Revised calculation
C-->>D: Approved
```
State diagram
stateDiagram-v2 draws the states something passes through. [*] is the start or the end, and the
text after a colon labels the change.
# Status of the calculation
```mermaid
stateDiagram-v2
[*] --> Draft
Draft --> Checked: checker signs
Checked --> Draft: comments
Checked --> Issued: approved
Issued --> [*]
```
User journey
journey scores each step of a task from 1 (bad) to 5 (good) for the people who take part.
# Inspection of a slab pour
```mermaid
journey
title Site inspection of a slab pour
section Before the pour
Check reinforcement: 4: Engineer
Check cover and chairs: 3: Engineer, Builder
section The pour
Slump test: 5: Tester
Take cylinders: 4: Tester
```
Use case diagram
usecase-beta draws actors and the things they do. actor names the actors, and
name(label) is a use case.
# Who does what
```mermaid
usecase-beta
actor Designer, Checker
Designer --> design(Design a member)
Designer --> report(Print the report)
Checker --> review(Review the calculation)
```
Event model
eventmodeling draws a process as frames in time order: tf is a time frame with a number, a
kind (ui, cmd, evt, rmo) and a name, and ->> points to the frame it follows.
# A check from input to report
```mermaid
eventmodeling
tf 01 ui InputForm
tf 02 cmd RunCheck ->> 01
tf 03 evt CheckPassed ->> 02
tf 04 rmo DesignReport ->> 03
```
Structure and data
Class diagram
classDiagram draws classes with their fields and methods. <|-- is inheritance.
# Section shapes
```mermaid
classDiagram
class Section {
+area() A
+inertia() I
}
class Rectangle {
+b
+h
}
class Circle {
+d
}
Section <|-- Rectangle
Section <|-- Circle
```
Entity relationship diagram
erDiagram draws a data model. }o--|| reads “many to exactly one”, and the braces list the
attributes of an entity.
# Member data model
```mermaid
erDiagram
MEMBER }o--|| SECTION : uses
SECTION }o--|| MATERIAL : "made of"
MEMBER {
string mark
float length_m
}
SECTION {
string name
float area_mm2
}
MATERIAL {
string grade
float fy_MPa
}
```
Requirement diagram
requirementDiagram ties requirements to the elements that satisfy or verify them.
# Traceability
```mermaid
requirementDiagram
requirement deflection {
id: R1
text: Deflection under span over 250
risk: medium
verifymethod: analysis
}
element beam_check {
type: sheet
}
beam_check - satisfies -> deflection
```
Block diagram
block-beta lays blocks out on a grid. columns 3 sets the grid, :3 makes a block span three
columns and space leaves a gap.
# A portal frame in blocks
```mermaid
block-beta
columns 3
Roof:3
Beam1["Beam"] space Beam2["Beam"]
Col1["Column"] space Col2["Column"]
Footing:3
```
Architecture diagram
architecture-beta draws services with icons (cloud, database, disk, internet, server)
in groups. sensors:R -- L:logger joins the right side of one to the left side of the other.
# Monitoring a bridge
```mermaid
architecture-beta
group site(cloud)[Bridge site]
service sensors(disk)[Strain gauges] in site
service logger(server)[Data logger] in site
service store(database)[Database]
sensors:R -- L:logger
logger:R -- L:store
```
C4 diagram
C4Context draws a system in its setting, in the C4 model’s notation: people, systems and the
relations between them.
# Context of a calculation system
```mermaid
C4Context
title Calculation system
Person(eng, "Engineer", "Writes the calculation")
System(app, "Calculation app", "Runs the sheet")
System_Ext(lib, "Section library", "Section properties")
Rel(eng, app, "Uses")
Rel(app, lib, "Reads")
```
Packet diagram
packet-beta draws the fields of a data record by bit position.
# A logger record
```mermaid
packet-beta
0-15: "Sensor id"
16-31: "Strain, microstrain"
32-47: "Temperature"
48-63: "Checksum"
```
Plans and time
Gantt chart
gantt draws tasks against dates. dateFormat sets how dates are written, after a1 starts a
task when another ends, and a duration such as 10d is in days.
# Design programme
```mermaid
gantt
title Design programme
dateFormat YYYY-MM-DD
section Design
Concept :a1, 2026-11-02, 10d
Detailed :a2, after a1, 15d
section Review
Check :b1, after a2, 5d
Issue :milestone, after b1, 0d
```
Timeline
timeline lists events by period, one line each: period : event.
# Strength gain
```mermaid
timeline
title Concrete strength gain
Day 3 : 15 MPa
Day 7 : 22 MPa
Day 28 : 32 MPa
```
Kanban board
kanban draws columns of cards. A line indented under a column is a card in it.
# Design tasks
```mermaid
kanban
todo[To do]
t1[Wind loads]
t2[Connection design]
doing[In progress]
t3[Column check]
done[Done]
t4[Gravity loads]
```
Git graph
gitGraph draws commits on branches, here the revisions of a calculation and a checker’s branch.
# Revisions
```mermaid
gitGraph
commit id: "Rev A"
branch checker
commit id: "Comments"
checkout main
commit id: "Rev B"
merge checker
commit id: "Rev C issued"
```
Charts of numbers
Pie chart
pie draws each value as a slice; showData adds the values to the legend.
# Dead load share
```mermaid
pie showData
title Dead load, kPa
"Slab" : 4.8
"Screed" : 1.1
"Services" : 0.5
"Partitions" : 1.0
```
XY chart
xychart-beta draws bars and lines over an x axis of categories or numbers.
# Moment along a beam
```mermaid
xychart-beta
title "Bending moment, kN.m"
x-axis "x, m" [0, 1, 2, 3, 4, 5, 6]
y-axis "M" 0 --> 60
bar [0, 30, 48, 54, 48, 30, 0]
line [0, 30, 48, 54, 48, 30, 0]
```
Quadrant chart
quadrantChart places points with coordinates from 0 to 1 in four labelled quadrants.
# Risk matrix
```mermaid
quadrantChart
title Site risks
x-axis Unlikely --> Likely
y-axis Minor --> Severe
quadrant-1 Control first
quadrant-2 Plan for it
quadrant-3 Accept
quadrant-4 Monitor
Trench collapse: [0.3, 0.9]
Wet weather: [0.9, 0.5]
```
Radar chart
radar-beta compares options over several axes. max sets the outer ring.
# Floor systems
```mermaid
radar-beta
title Floor systems
axis cost["Cost"], speed["Speed"], depth["Shallow depth"], span["Span"]
curve flat["Flat plate"]{4, 3, 5, 2}
curve steel["Steel and deck"]{3, 5, 3, 4}
max 5
```
Sankey diagram
sankey-beta draws flows as bands whose width is the value. Each line is from,to,value.
# Energy through a pump
```mermaid
sankey-beta
Input,Motor,43.3
Motor,Motor losses,3.0
Motor,Pump,40.3
Pump,Pump losses,8.9
Pump,Water,31.4
```
Treemap
treemap draws nested rectangles with an area in proportion to the value. Indentation nests an
item in its group.
# Cost plan
```mermaid
treemap
"Cost plan"
"Structure"
"Frame": 310
"Floors": 260
"Envelope"
"Facade": 280
"Roof": 90
```
Ideas and analysis
Mind map
mindmap draws a tree from its root; indentation gives the branches. ((text)) draws a circle.
# Footbridge brief
```mermaid
mindmap
root((Footbridge))
Geometry
Span 24 m
Width 2.5 m
Loads
Crowd 5 kPa
Limits
Deflection L/360
```
Ishikawa (fishbone) diagram
ishikawa-beta draws an effect at the head and its causes on the bones. Indentation gives the
categories and the causes in each.
# Causes of cracking
```mermaid
ishikawa-beta
Cracked slab
Materials
High water content
Method
Late curing
Design
Joints too far apart
```
Venn diagram
venn-beta draws sets as circles. set adds a set, and union labels where sets overlap.
# Kinds of check
```mermaid
venn-beta
title Checks
set S["Strength"]
set V["Serviceability"]
union S, V["Both"]
```
Cynefin framework
cynefin-beta places items in the five domains (complex, complicated, clear, chaotic,
confusion). An item is a quoted text, and --> shows a move from one domain to another.
# Kinds of design problem
```mermaid
cynefin-beta
complex
"Novel bracing system"
complicated
"Long-span roof"
clear
"Standard lintel"
chaotic
"Collapse on site"
chaotic --> complex : "Make safe, then probe"
```
Wardley map
wardley-beta maps components by visibility (up) and evolution (across). The coordinates are
[visibility, evolution], from 0 to 1, and -> joins a component to one it depends on.
# Design office
```mermaid
wardley-beta
title Design office
anchor Client [0.95, 0.6]
component Calculation [0.7, 0.5]
component Section tables [0.4, 0.85]
Client -> Calculation
Calculation -> Section tables
```
Tree view
treeView-beta draws an indented list as a tree, such as the folders of a project.
# Project folders
```mermaid
treeView-beta
project
calcs
beams.sheet
columns.sheet
drawings
general.pdf
```
Grammars: railroad diagrams
A railroad diagram draws the grammar of a language: follow the track from left to right. Each
rule ends with ;. The same drawing comes from four notations.
EBNF
railroad-ebnf-beta: , joins in sequence and [ ] is optional. This is the grammar of a
quantity line.
# A quantity line
```mermaid
railroad-ebnf-beta
quantity = name , ":" , expression , [ "->" , unit ] , [ "|" , note ] ;
```
ABNF
railroad-abnf-beta: 1*DIGIT is one or more digits and [ ] is optional.
# A number
```mermaid
railroad-abnf-beta
number = 1*DIGIT [ "." 1*DIGIT ] ;
```
PEG
railroad-peg-beta: <- defines a rule, + is one or more and ? is optional.
# A number
```mermaid
railroad-peg-beta
Number <- Digit+ ("." Digit+)? ;
```
Railroad functions
railroad-beta builds a diagram from functions: sequence, choice, optional, oneOrMore,
zeroOrMore, terminal and nonterminal.
# A quantity line
```mermaid
railroad-beta
quantity = sequence(nonterminal("name"), terminal(":"), nonterminal("expression"), optional(sequence(terminal("|"), nonterminal("note")))) ;
```
Kinds that are not available
Every kind above was drawn in the app with the bundled Mermaid 12.1.0. These are not available:
| Kind | Why |
|---|---|
ZenUML (zenuml) | A separate plugin of the diagram library, not part of the app. The fence shows “No diagram type detected”. Use a sequence diagram instead. |
The elk layout (layout: elk) | Not shipped; diagrams use the standard layout. |
Samples
The Plots and diagrams group of the Samples dialog (Resources > Samples) has sheets with a diagram next to the calculation it describes:
- Design check as a flow diagram and Load path and tributary loads (flow charts)
- Design states of a steel beam (state diagram) and Review and sign-off (sequence diagram)
- Construction programme (Gantt chart), with durations worked out from quantities and rates
- Dead load share (pie chart) and Cost plan (treemap), with the shares worked out
- Site risk matrix (quadrant chart) and Bending moment along a beam (XY chart)
- Energy flow through a pump (Sankey), from the hydraulic power back to the electrical input
- Footbridge design brief (mind map) and Requirements traceability (requirement diagram)
- Concrete strength gain (timeline) and Section shapes (class diagram)
For plots drawn from a function, see Plots.
Learning more
Every diagram type and option is described in the Mermaid project’s own documentation; what it shows there can be pasted into a fence here, as long as the kind is in the gallery above.
Tips
- Keep the text in a box short. A long label wraps onto several lines and makes the box tall.
- A diagram is part of the page, not of the calculation. Names in it are only text: changing
win a box does not change the load, and a quantity line is still needed for every number. - In the dark theme a diagram is drawn on a white panel, so it reads the same as on paper.
- A fence that cannot be read shows its text with the reason under it. The usual cause is a character the diagram language treats as syntax, such as a bracket or a quote inside a label.
Printing and exports
Diagrams print and save with the HTML and PDF report as drawings; in Word they appear as their
text. The same fence works inside a #markdown block of a Calcpad worksheet. The diagram library
is part of the app and is only loaded when a page has a diagram, so it works offline and costs
nothing on a page without one.
Folding sections and key results
A long calculation has a few numbers the reader came for and a lot of working that leads to them. Two markers let the sheet say which is which, without changing a single result.
A section that folds
End a heading with {collapse} and the section under it is folded away until the reader opens it:
# Beam moment
L: 6 m | span
w: 12 kN/m | design load
## Workings {collapse}
The moment at mid-span of a simply supported beam under a uniform load is $w L^2 / 8$.
M: w * L^2 / 8 -> kN*m | maximum bending moment
Ms: 180 kN*m | moment capacity
## Result
utilisation: M / Ms | bending utilisation
In the preview and the report the heading shows with a small arrow in front of it. Click the heading to open
the section and click it again to fold it. The lines under a folded heading are still calculated, so M is
there for the line after it. The section runs to the next heading of the same level or a higher one, so a
### under a ## is part of it, and it ends at the end of the sheet if no such heading follows.
{collapse open} starts the section open. Use it for a section the reader should see at first and may fold away.
Only a heading at the top level of the sheet can fold. A {collapse} heading inside an if, for, while or
repeat block is ignored, with a warning.
The preview also has a fold arrow beside every other heading (see Editing). That fold is only a view
and is not saved in the sheet; a {collapse} heading folds by its marker and has no arrow of its own, and “Collapse
all” leaves it as the sheet wrote it.
When you print, or save as PDF, every folded section is opened, so the printed report is complete. The Word and Excel exports include them too. There is no option to leave a folded section out of an export.
Key lines
End a quantity or an input line with {key} to mark it as one of the numbers that matter:
L: ? 6 m | span {key}
w: 12 kN/m | design load
M: w * L^2 / 8 -> kN*m | maximum bending moment {key}
Ms: 180 kN*m
utilisation: M / Ms | bending utilisation {key}
A key line carries a star after it and is highlighted in the preview, the report and the printed page. In Word and Excel the star is in the line, though the highlight is not. The marker goes last, after the note.
A list of the key lines
A line that is just {key results} becomes a list of the key lines above it, with the values the engine
worked out and their notes:
L: ? 6 m | span {key}
w: 12 kN/m | design load
M: w * L^2 / 8 -> kN*m | maximum bending moment {key}
Ms: 180 kN*m
utilisation: M / Ms | bending utilisation {key}
## Key results
{key results}
Put it after the lines it lists: a sheet is calculated from the top, so a key line written below the list has no
value yet and is not in it. A line inside an if or for block, and a function definition, can be marked but
are not listed.
In the editor, Text formatting > Fold inserts a folding heading, Key results inserts the heading and the list, and the + between blocks of the preview offers both. Format Document writes the markers as one space and the marker.
Conditions and loops
One-line conditions
utilisation: 0.82
if utilisation <= 1: "OK" else: "Fails"
The branches are a quoted text or quantities. The text may contain LaTeX. A one-line condition
can also define a quantity: if a == 2: b: 1.
Blocks
A line ending in : that starts with if, else if, else, for, while or repeat opens a
block. The body is the lines indented more than the header. A tab counts as four spaces. Blank
lines inside are fine. A line indented no deeper than the header closes the block. A body can hold
anything: quantities, prose, formulas, >> lines, and nested blocks.
n: 5
if n > 3:
Large.
else if n > 1:
Medium.
else:
Small.
n = 5
Large.
Loops
for i in 1..3:
P: 10 kN * i | load at stage $i$
P = 10 kN · i = 10 kN · 1 = 10 kN load at stage 1
P = 10 kN · i = 10 kN · 2 = 20 kN load at stage 2
P = 10 kN · i = 10 kN · 3 = 30 kN load at stage 3
| Sheet | Meaning |
|---|---|
for i in a..b: | i takes a, a+1, … b. |
for i in a..b step s: | A stepped range. The step may be negative. |
for x in v: | Each element of the vector v (a name or a literal). |
while c: | Repeat while the condition holds. |
repeat n: | Repeat n times. |
break, continue | Leave the loop, or skip to the next pass. if c: break works on one line. |
for i in 0..10 step 5:
s: i
for x in [2, 4, 6]:
y: x^2
n: 3
while n > 0:
n: n - 1
total: 0
for i in 1..5:
total: total + i
if total > 5: break
The last example stops once the total passes 5; it prints the passes with total 1, 3 and 6.
A quantity line in a loop prints on every pass, exactly like a Calcpad loop. Use the loop to build a vector or to accumulate; if you only need the final value, put the quantity line after the loop.
Limits
repeatneeds a count; for anything else use>>lines.- A loop over a vector cannot have a step.
- A header whose condition is not an expression (
If the load is large:) is prose. The compiler warns if it starts with a keyword. - An
elsewith no matchingifat the same indentation is read as text, with a warning.
Functions
Your own functions
A line with an argument list defines a function:
f(x, y): sqrt(x^2 + y^2)
g(t): 2 * t
r: f(3, 4) + g(1)
f(x; y) = √(x² + y²)
g(t) = 2·t
r = f(3; 4) + g(1) = 7
Calls take commas in a sheet; the compiler writes the engine’s ;. Calcpad’s own ; works too,
in a definition and in a call (f(x; y): x + y, max(3; 7)): inside brackets it means the same as
a comma. Functions can use any quantity defined above them, and may be used in plots
(plot g(t) for t in 0..5).
Keeping functions for reuse
A function defined in a sheet belongs to that sheet. To use it in other sheets, put its definition
in a .cpd file and add the file to the library (File > Library > Add files to the library,
or drop it on the page). Any sheet then pulls it in with an include line:
>> #include beam_functions.cpd
The file holds Calcpad text, so its arguments are separated by ;:
delta(w; L; E; I) = 5*w*L^4/(384*E*I)
Two things to watch in definitions that integrate over time or space:
- The limits of
$Area,$Sumand the other numerical commands must have the same unit.$Area{F(t) @ t = 0ms : 2s}is fine; a bare0against2sis an error. - An angular frequency is a number per second. Write
20 / 1 s, not20 rad/s.
Copying the definition lines into each sheet also works, and keeps the sheet self-contained when you send it to someone who does not have your library.
Built-in functions
The engine has more than 200 functions: trigonometric, hyperbolic, logarithmic, rounding, statistical, interpolation, complex numbers, and a large set for vectors and matrices. The function reference lists them all, with the argument forms, and the Insert tab in the sidebar finds them as you type.
A few that are used constantly:
a: sqrt(2)
b: round(3.14159)
c: max(3, 7, 5)
d: sum([1, 2, 3])
e: interp(2.5, [1, 2, 3], [10, 20, 30])
There is no hypot in a sheet. For the hypotenuse, or the resultant of any number of components,
use srss (square root of the sum of squares), which keeps the unit:
a: 3 m
b: 4 m
c: srss(a, b)
The result is 5 m, and srss(3 m, 4 m, 12 m) is 13 m. (In a Python block math.hypot exists.)
A function whose name is also a variable name needs the Calcpad spelling (a name like gamma
or beta used as a variable only keeps working if you write it the Calcpad way). Function calls
are not renamed unless the sheet defines the function.
Solving, integrating and slopes
Three numerical operations have a sheet form of their own, written like a plot line:
f(x): x^2
x0: solve f(x) = 2 for x in 0..2 | the positive root
A: integral of f(x) for x in 0..3
k: slope of f(x) at x = 3
solve f(x) = c for x in a..bfinds thexbetweenaandbwhere both sides are equal (Calcpad’s$Root{f(x) = c @ x = a : b}). Without= cit solvesf(x) = 0. Both sides may use the variable (solve f(x) = g(x) for x in 0..5finds where two curves cross). The difference of the sides must change sign once across the range.integral of f(x) for x in a..bis the numerical integral ($Integral).slope of f(x) at x = ais the derivative at a point ($Slope).
root(27, 3) is something else: the cube root of 27. The bounds may carry units, and a bare 0
takes the unit of the other bound, so solve x^2 = 4 m^2 for x in 0..5 m -> mm gives 2000 mm. A
line that starts like one of these but is malformed (for 2 in 0..5, two = signs) is an error on
its line.
Numerical commands
The $Root, $Area, $Sum, $Find and similar commands are Calcpad commands. Apart from the three
above, in a sheet they go through >>:
>> f(x) = x^2 - 2
>> x_0 = $Root{f(x) @ x = 0 : 2}
>> I = $Area{x^2 @ x = 0 : 3}
The result of the first is 1.41, of the second 9. See The Calcpad language.
Mixing in Calcpad, Show compiled and errors
Every feature of the Calcpad language stays reachable from a sheet.
>> lines and calcpad fences
A line that starts with >> is handed to the engine as written. So is everything between a
calcpad fence:
n: 3 | number of bays
bay: 2.5 m | bay width
>> total = 0 m
```calcpad
#for i = 1 : n
total = total + bay
#loop
```
len: total * 1 -> m
n = 3 number of bays
bay = 2.5 m bay width
total = 0 m
total = total + bay = 0 m + 2.5 m = 2.5 m
total = total + bay = 2.5 m + 2.5 m = 5 m
total = total + bay = 5 m + 2.5 m = 7.5 m
len = total · 1 = 7.5 m · 1 = 7.5 m
Sheet lines and raw lines share one worksheet, so they alternate freely: a raw block reads the
variables defined by sheet lines above it and defines variables that sheet lines below it use.
Prose, quantities, formulas and raw Calcpad can come in any order. To make that work without
remembering renames, an identifier in a raw line that the sheet defines is spelled the way the
sheet spells it (phi in a raw line is φ). That includes the name that a >> #UI line assigns. Text after a ' or " in a raw line is left alone.
A raw block inside a sheet block keeps the block’s indentation rules like any other line.
The ribbon uses >> for anything with no sheet form: the data grid and the other #UI input forms (an entry, drop-down, radio or checkbox has a sheet form, L: ? 6 m), $Map colour maps,
directives and macros. Those buttons carry a small >> mark and a tooltip saying so. See
The Calcpad language.
Python
A fenced block with the language python is a Python block. It is explained in
Python blocks.
Show compiled and Convert to Calcpad
On the Resources tab:
- Show compiled opens a panel beside the editor with the Calcpad text the sheet becomes. Its line numbers are the sheet’s lines.
- Convert to Calcpad replaces the sheet with that text. It is one way: there is no conversion back to a sheet.
A worked example is in Your first sheet. Both views give Calcpad as a person would write it, so the sheet is also a way to learn the Calcpad language.
Errors
The engine’s errors, the report’s “on line [n]” links, the error banner, the scroll anchors and the editor’s lint markers all report the sheet line, whatever kind of line it was. An undefined name, for example:
bad: foo + 1
Error in "bad = foo + 1" on line [1]: Undefined variable or units: "foo".
The text of an engine message still quotes the compiled Calcpad line (bad = foo + 1), which is
what Show compiled displays. The compiler’s own problems, such as mixed tab and space indentation,
an else with no if, an empty block, an unclosed $$ or a bad plot line, are markers on their
lines too. “Unused variable” hints are not shown for sheets, since every quantity is shown.
Format Document
Format Document (Shift+Alt+F) prettifies a sheet: one space around :, | and -> and
after ;, a blank line before each heading, runs of blank lines collapsed, and the colons of a run
of quantity lines aligned. Expressions, prose, >> lines, fences and formulas are not touched,
and formatting twice changes nothing.
Other editor help works on the names a sheet defines: Go to definition (F12), find references, hover (shows the defining line and the Calcpad spelling), and colouring by role.
The Calcpad language
The sheet format is a front end. Underneath, every sheet becomes a Calcpad worksheet, the
language of CalcpadCE, and the engine runs that. You can also write Calcpad directly: choose
File > New Calcpad worksheet (the second item of the File menu, also on the Resources tab), or
open a .cpd file.
Use the Calcpad language when you need something a sheet does not offer on its own: macros that repeat a block with different arguments, input forms with drop-downs and grids, output control (hide a block, show only results), the numerical commands, reading and writing data files, or when you are working with worksheets from the CalcpadCE community.
How a Calcpad worksheet reads
A worksheet is a list of lines. Each line is one of these.
| First character | Kind | Example |
|---|---|---|
" | Heading, a comment shown as a heading | "Beam check |
' | Text, a comment shown as written (HTML allowed) | 'Span -'L = 6m |
# | A directive | #if, #for, #def, #hide |
$ | A command | $Plot{x^2 @ x = 0 : 5} |
| anything else | A calculation | M = w*L^2/8|kN*m |
A single quote also switches between text and calculation inside a line, which is how labels
sit in front of an equation: 'Span -'L = 6m shows the text “Span -” and then the equation.
"Beam check
'Span -'L = 6m
'Load -'w = 12kN/m
'Moment -'M = w*L^2/8|kN*m
#if M < 100kN*m
'OK
#else
'Too large
#end if
Beam check
Span - L = 6 m
Load - w = 12 kN/m
Moment - M = w·L²/8 = 12 kN/m · (6 m)² / 8 = 54 kN·m
OK
Sheet and Calcpad side by side
| Sheet | Calcpad |
|---|---|
L: 6 m | span | L = 6m 'span |
M: w*L^2/8 -> kN*m | M = w*L^2/8|kN*m |
# Heading | '<h1>Heading</h1> |
Plain paragraph | 'Plain paragraph |
if u <= 1: "OK" else: "Fails" | #if u ≤ 1 … #else … #end if |
for i in 1..5: + indented body | #for i = 1 : 5 … #loop |
f(x, y): x + y | f(x; y) = x + y |
[1, 2; 3, 4] | [1; 2 | 3; 4] |
plot f(x) for x in 0..5 | $Plot{f(x) @ x = 0 : 5} |
phi, Mstar | φ, M_star |
Function arguments are separated with ; in Calcpad, matrix rows with |, and a unit
conversion is a vertical bar. A sheet writes commas, -> and brackets, and the compiler does the
translation. To see it for any sheet, use Show compiled.
Operators
^ power, * multiplication, / division, \ integer division, ⦼ modulo (type %%), !
factorial, + - , comparisons ≡ ≠ < > ≤ ≥ (type == != <= >=), logical ∧ ∨ ⊕ (type && || ),
= assignment, ← assignment to an outer scope. The editor converts the typed forms when you
open a file. The complete table is in the reference.
Angles
Angles are in degrees unless you say otherwise. #rad switches the rest of the worksheet to
radians, #gra to gradians and #deg back. This matters whenever you pass π or a plain number to
a trigonometric function. See Troubleshooting.
Output control
Directives shape what the report shows without changing the calculation.
#hide
k = 3
#show
a = k*2
#val
b = k*3
#equ
#nosub
c = k*4
#varsub
a = k·2 = 3 · 2 = 6
9
c = k·4 = 12
#hide … #show calculates but does not print, #val prints only the value, #nosub prints
the formula without the numbers put in, #noc the formula without the result and #novar only
the substituted numbers. #pre and #post split a document into the part that is filled in on
screen and the part that appears in the report. The complete list is in
Directives.
What the next pages cover
- Directives and commands: conditions, loops, macros, modules, constants, settings, files, numerical commands.
- Input forms with
#UI: the#UIdirective, grids and entry options. - Templates with inputs: fill-in forms, and the
?input lines of a sheet.
Related pages: Calcpad worksheets in the browser. More pages are in Calculators and guides.
Directives and commands
A directive starts with # and controls the flow of the worksheet. A command starts with $ and
takes arguments in braces. In a sheet, both are written on >> lines (or inside a calcpad
fence), except the ones the sheet has its own form for (if, for, while, repeat, plot).
Conditions
M = 150kN*m
#if M < 100kN*m
'OK
#else if M < 200kN*m
'Check again
#else
'Too large
#end if
The condition can be any expression that gives a number: zero is false. A condition that cannot
be evaluated (an undefined name, say) is an error, and the block is left unresolved: no branch
runs. CalcpadCE would silently take the #else branch; see
Deviations from CalcpadCE.
Loops
#repeat 3
y = 2
#loop
#for i = 1 : 4
#if i ≡ 3
#continue
#end if
s = i
#loop
s = i = 1
s = i = 2
s = i = 4
Pass 3 is skipped by #continue.
n = 0
#while n < 3
n = n + 1
#loop
#break leaves the loop and #continue skips to the next pass. Every line in the loop prints on
every pass, so use #hide around the body when you only want the final value. The commands
$Sum, $Product, $Repeat and $While do the same without printing each pass.
Macros and string variables
Macros are text substituted before the worksheet is calculated. A name ends with $.
#def twice$(a$) = 2*a$
r = twice$(7)
r = 2·7 = 14
A multi-line macro repeats a whole block with different values:
#def beam$(span$; load$)
M = load$*span$^2/8
V = load$*span$/2
#end def
beam$(6m; 12kN/m)
M = 12 kN/m · (6 m)² / 8 = 9 kN·m
V = 12 kN/m · 6 m / 2 = 36 kN
The macro text does not have to be valid Calcpad by itself. It is substituted first and parsed after. Unwrapped in the results views shows the text after substitution, which is the place to look when a macro misbehaves. A macro cannot contain another definition; it can use an earlier one.
Modules
#include name.cpd pulls in a file from the library (see Saving).
Put shared definitions in a file with a #global section and keep the worksheet-specific part in
#local: only the global part is included when the file is imported.
Constants
#const g_n = 9.81m/s^2
F = 70kg*g_n|N
A #const cannot be changed later.
Number format
#round n rounds output to n digits, #round default goes back; #format spec sets a custom
format string (for example #format 0.00). The Decimals setting sets the default.
#settings {"decimals": 4} overrides engine settings for the lines that follow.
Text modes
#md on and #md off turn Markdown on and off in comment lines. #markdown … #end markdown
and #html … #end html switch to a block of Markdown or raw HTML, and #cpd goes back to
calculation inside one.
#markdown
## Section
* one
* two
#end markdown
Reading and writing data
#read M from file.csv, #write M to file.csv and #append M to file.csv move a matrix
between the worksheet and a text, CSV or Excel file in the library. Options choose the cell range
(@R1C1:R2C2 for text, @Sheet1!A1:B2 for Excel), the matrix type and the separator. The full
forms are in the reference.
A worksheet that writes files saves them into the library and downloads them when their content changes.
Numerical commands
#rad
f(x) = x^3 - 2*x - 5
r = $Root{f(x) @ x = 2 : 3}
A = $Area{sin(x) @ x = 0 : π}
m = $Slope{x^3 @ x = 2}
hi = $Sup{sin(x) @ x = 0 : 3}
S = $Sum{1/k^2 @ k = 1 : 100}
P = $Product{k @ k = 1 : 5}
r = $Root{f(x) = 0; x ∈ [2; 3]} = 2.09
A = ∫ sin(x) dx from 0 to π = 2
m = d/dx x³ at x = 2 = 12
hi = $Sup{sin(x); x ∈ [0; 3]} = 1
S = Σ 1/k² for k = 1 to 100 = 1.63
P = Π k for k = 1 to 5 = 120
| Command | Meaning |
|---|---|
$Root{f(x) @ x = a : b} | A root of f in the interval. $Root{f(x) = c @ ...} solves f(x) = c. |
$Find{f(x) @ x = a : b} | An approximate solution, when the exact value is not needed. |
$Sup, $Inf | Local maximum or minimum. |
$Area | Numerical integral (adaptive Gauss-Lobatto). |
$Integral | Numerical integral (tanh-sinh). |
$Slope{f(x) @ x = a} | Derivative at a point. |
$Sum, $Product | Iterative sum and product. |
$Repeat, $While, $Block, $Inline | Iterative expression blocks. |
$Plot, $Map | Plots; see Plots. |
The relative precision of the numerical methods is the Precision setting (default 1e-12).
Python
#python … #end python is a Python block. In a sheet it is a fenced python block. See
Python blocks.
Input forms
#UI turns an assignment into an input control. See Input forms with #UI. In a sheet, most inputs are written as L: ? 6 m lines instead; see Templates with inputs.
Not available in the browser
#pause and #input (step-by-step execution) are not supported in the web version, and neither
are raster (PNG) plots or compiled .cpdz worksheets. See
Deviations from CalcpadCE.
Input forms with #UI
#UI is the Calcpad language’s own input directive. It turns the assignment that follows it into an
input control in Input mode: a text box, a drop-down, radio buttons, a checkbox or an editable grid.
In a sheet, most inputs do not need it. A line such as L: ? 6 m | span is an input, and the
sheet compiler writes the #UI line for you. See Templates with inputs, which
also covers the Input mode, saving values and sharing a template. Write #UI yourself when:
- you work in a Calcpad worksheet (
.cpd); - you need a data grid, a vector or matrix input, or one of the entry options below, which the
?form has no way to say.
In a sheet, a #UI line is a Calcpad line, so it starts with >>.
The input line
>> #UI 'Span, 'L = 6m
>>hands the line to the engine as written (leave it out in a.cpdworksheet).#UIsays “show the next assignment as an input control in Input mode”.'Span, 'L = 6m: an optional label ('Span,is text) and then the assignment.L = 6mis the name and the default value, with its unit.
In Preview and in a report this line shows as a plain line (Span, L = 6 m). In Input mode the
6 becomes a text box with m beside it.
What may be on the right of the =
| Right-hand side | Allowed | Example |
|---|---|---|
| A number, with or without a unit | Yes | #UI L = 10m, #UI n = 4, #UI q = 3kN/m |
| A vector or matrix literal | Yes | #UI v = [1; 2; 3], #UI M = [1; 2 | 3; 4] |
vector(n) or matrix(r; c) | Yes | #UI Z = vector(5) |
| An expression | Only with allowExpression | #UI {"allowExpression": true} h = L/2 |
| Text | No |
A sheet with #UI lines
The beam check as a sheet whose inputs are #UI lines. Names such as phi or Delta_T work in a #UI line as in any other line (the first is shown as
φ). A dotted name does not: a dot is the index operator.
# Beam bending check
Fill in the inputs, then read the check below.
## Inputs
>> #UI 'Span, 'L = 6m
>> #UI 'Design load, 'w = 12kN/m
>> #UI 'Yield stress, 'f_y = 300MPa
>> #UI 'Section modulus, 'Z_e = 1230000mm^3
>> #UI 'Capacity factor, 'cf = 0.9
## Check
Mstar: w * L^2 / 8 -> kN*m | maximum moment
Mcap: cf * f_y * Z_e -> kN*m | design capacity
ratio: Mstar / Mcap | utilisation
if ratio <= 1: "OK: the section passes." else: "Fails: increase the section."
Change the span to 10 and the load to 20 in the form: the moment is 250 kN·m, the ratio 0.753 and the message still reads OK.
Controls
The type property picks the control. When it is left out, the engine picks one from the right-hand
side.
>> #UI {"type": "dropdown", "keys": ["Soft clay", "Stiff clay", "Dense sand"], "values": ["75kPa", "150kPa", "300kPa"]} 'Soil allowable bearing, 'q_a = 150kPa
>> #UI {"type": "radio", "keys": ["Concrete", "Steel"], "values": ["25", "78.5"]} 'Column unit weight in kN/m3, 'unit_weight = 25
>> #UI {"type": "checkbox"} 'Include footing weight (1 = yes), 'add_weight = 1
- A drop-down or radio group shows the
keysand works by the matchingvaluesentry. A value can carry its own unit, so a menu can switch units as well as magnitudes ("values": ["1m", "3.281ft"]). - A checkbox is
1when ticked and0when not. - Use the
?form of a sheet for these when you can:E: ? [Steel = 200 GPa, *Timber = 11 GPa]writes this JSON for you.
A grid and a radio group together
# Column load take-down
A column carries the tributary area of each level. Choose the column material, set the sizes and fill in the floor loads, one row per level.
## Inputs
>> #UI 'Tributary area per level, 'A_t = 36m^2
>> #UI 'Column section area, 'A_c = 0.09m^2
>> #UI 'Storey height, 'H = 3.5m
>> #UI {"type": "radio", "keys": ["Concrete", "Steel"], "values": ["25", "78.5"]} 'Column unit weight in kN/m3, 'unit_weight = 25
>> #UI {"type": "datagrid", "columnHeaders": ["Dead", "Live"], "rowHeaders": ["Roof", "Level 2", "Level 1"]} loads = [20; 5 | 35; 15 | 35; 15]
## Loads at the base of the column
levels: n_rows(loads)
G_floors: sum(col(loads, 1)) * 1 kPa * A_t -> kN | dead load from the floors
Q_floors: sum(col(loads, 2)) * 1 kPa * A_t -> kN | live load from the floors
G_column: unit_weight * 1 kN/m^3 * A_c * H * levels -> kN | weight of the column
Nstar: 1.2 * (G_floors + G_column) + 1.5 * Q_floors -> kN | factored axial load
The grid is a small spreadsheet of three rows and two columns with its own headers. Its default
([20; 5 | 35; 15 | 35; 15], with | between rows) fills the cells. Click a cell, type a number
and press Enter, and every line that uses loads follows. At the defaults:
levels = n_rows(loads) = 3
G_floors = sum(col(loads; 1)) · 1 kPa · A_t = ... = 3240 kN dead load from the floors
Q_floors = sum(col(loads; 2)) · 1 kPa · A_t = ... = 1260 kN live load from the floors
G_column = unit_weight · 1 kN/m³ · A_c · H · levels = 25 · 1 kN/m³ · 0.09 m² · 3.5 m · 3 = 23.62 kN
N_star = 1.2·(G_floors + G_column) + 1.5·Q_floors = 1.2 · (3240 kN + 23.62 kN) + 1.5 · 1260 kN = 5806.35 kN
Choose Steel: unit_weight becomes 78.5, G_column 74.18 kN and N_star 5867.02 kN.
- A grid holds numbers only. To give them units, multiply in the sheet (
* 1 kPaabove) or write the units in the headers ("Dead (kPa)"). - The grid size comes from the default value (or the
rowsandcolumnsproperties). Rows and columns cannot be added in the form. - One
#UIline per name is the stable arrangement. Rename an input and a value saved under the old name is not used any more.
Entry options
A JSON object between #UI and the label sets properties:
>> #UI {"forceUnits": false} 'Line load, 'q = 3kN/m
>> #UI {"allowExpression": true} 'Half span, 'h = L/2
forceUnits: falseputs the unit inside the box (3kN/m), so the user can type another unit.allowExpression: trueaccepts a formula as typed, and keeps it a formula across edits. Nothing is validated as you type: an entry the engine cannot read leaves the control in place and shows the error on the line.
Both were run in the form: the first box held 3kN/m and 5kN/m gave a moment of 22.5 kN·m; the
second held L/2.
All the properties
| Property | Applies to | Meaning |
|---|---|---|
type | all | entry, datagrid, dropdown, radio, checkbox. Found from the right-hand side when omitted. |
forceUnits | entry, grid | Default true: the unit stays in the document and only the number is editable. |
allowExpression | entry, grid | Default false. Accepts any expression. Implies forceUnits: false. |
keys, values | dropdown, radio | The labels shown and the values used. Both are required and must be the same length. |
rows, columns | grid | The grid size. A literal is cut or padded with zeros to fit. |
rowHeaders, columnHeaders | grid | Header labels. |
width, rowHeaderWidth, columnWidths | grid | Sizes in pixels, or a percentage for width. |
style, reportStyle | all | A CSS class for the control, or for its line in the report. |
The ribbon’s Input/Output tab inserts a starting line for each control. In a sheet, Entry,
Dropdown, Radio and Checkbox insert the ? form. Data grid and More input forms (the labelled,
vector, matrix and formula forms) insert >> #UI lines.
The views, #pre and #post
#pre and #post let one file serve two audiences: an instruction (“fill in the values below”)
that only the person at the form sees, and a note (“values used in this report”) that only the
report carries. See the table of views in Templates with inputs.
In a sheet they go in a calcpad fence:
```calcpad
#pre
'<p>Fill in the values below, then press Report.</p>
#end pre
```
In a Calcpad worksheet
A worksheet takes the lines as they are and has no renaming issue. The beam check as a .cpd:
"Beam bending check
#UI 'Span, 'L = 6m
#UI 'Design load, 'w = 12kN/m
#UI 'Yield stress, 'f_y = 300MPa
#UI 'Section modulus, 'Z_e = 1230000mm^3
#UI 'Capacity factor, 'φ = 0.9
M_star = w*L^2/8|kN*m
M_cap = φ*f_y*Z_e|kN*m
ratio = M_star/M_cap
#if ratio ≤ 1
'OK
#else
'Fails
#end if
In a worksheet, Save values writes the entered values into a comment on the first line, and the browser opens the form only when you press Input. The Excel export has an Inputs sheet listing the variables set by input fields.
Known limits
Workarounds for behaviour that is to be fixed. This is the only list of them on this page.
- Superscript units and exponent notation in a
#UIline. The engine’s own#UIline takes only the^and*spellings.1230000mm³is an error there (Error parsing "mm³" as units), and so is1.23e6. Write1230000mm^3. A?line has no such limit: it takesmm³,kN·m,N/mm²,°and%, and writes the engine’s spelling for you. - A default should be one of the options. In a raw line the default of a drop-down or radio
group should be one of its
values. A default that matches none still shows the first label while the calculation keeps using the default, so the control and the numbers disagree. (The?form cannot do this: its default is always one of the options.) A match is by value, so a default such as25kN/mfinds the option written25 kN/m. - Two options cannot have the same value in a
?line. It is an error on that line.
Units
Video: Units and results
Units are part of the value. The engine carries them through every operation, converts between them, and stops with an error when a formula does not add up dimensionally.
Attaching units
Write the unit after a number, with or without a space: 15 kg, 12kN/m, 1230000 mm³.
a: 1.23 m + 35 cm + 12 mm -> cm
v: 10 m/s -> km/h
P: 2.5 kN / (50 mm * 200 mm) -> MPa
g0: 9.81 m/s²
m: 70 kg
W: m * g0 -> N
a = 1.23 m + 35 cm + 12 mm = 159.2 cm
v = 10 m/s = 36 km/h
P = 2.5 kN / (50 mm · 200 mm) = 0.25 MPa
g0 = 9.81 m/s²
m = 70 kg
W = m·g0 = 70 kg · 9.81 m/s² = 686.7 N
Without ->, a sum comes out in the first unit it meets. With -> unit the result is converted
to the unit you choose. In the Calcpad language the same conversion is a vertical bar:
a = 1.23m + 35cm + 12mm | cm.
SI base units
-> base shows a result in the SI base units of its dimensions, so you do not have to spell them out:
F: 5 kN
L: 2 m
M: F * L -> base
P: 3 MPa -> base
The moment comes out as 10000 kg·m²/s² and the pressure as 3000000 kg·m⁻¹·s⁻². The units used are
kg, m, s, A, mol and cd. A value with no unit is left as it is, and so is one with a temperature or an
angle in it. In the Calcpad language the same thing is M = F*L | base.
Prefixes work on every unit that takes them: kN is 10³ N, MPa is 10⁶ Pa, mm is 10⁻³ m. See
“Prefixes” below for the full list.
Prefixes
Any SI prefix goes in front of any SI unit that takes one, so 3 mN, 2 GPa, 5 µm, 40 nF and 1.2 kΩ
all work.
| Prefix | Symbol | Factor | Prefix | Symbol | Factor | |
|---|---|---|---|---|---|---|
| yotta | Y | 10²⁴ | deci | d | 10⁻¹ | |
| zetta | Z | 10²¹ | centi | c | 10⁻² | |
| exa | E | 10¹⁸ | milli | m | 10⁻³ | |
| peta | P | 10¹⁵ | micro | μ, µ or u | 10⁻⁶ | |
| tera | T | 10¹² | nano | n | 10⁻⁹ | |
| giga | G | 10⁹ | pico | p | 10⁻¹² | |
| mega | M | 10⁶ | femto | f | 10⁻¹⁵ | |
| kilo | k | 10³ | atto | a | 10⁻¹⁸ | |
| hecto | h | 10² | zepto | z | 10⁻²¹ | |
| deca | da | 10¹ | yocto | y | 10⁻²⁴ |
Micro can be typed as the Greek mu μ, the micro sign µ (what a keyboard gives) or a plain u; the result
shows μ. The units that take a prefix are g, m, s, A, mol, cd, rad, L, N, Nm, Pa, bar,
J, W, Wh, VA, VAR, Hz, V, C, F, Ω, S, Wb, T, H, Bq, Gy, Sv, lm, lx, kat,
eV, Ah and Da. Everything else stays as it was: min, h, d, ft, in, lb, psi, °C and the
other non-SI units take no prefix (kft and mmin are errors), the kilogram is kg (Mg is a megagram, not
kkg), and kelvin K takes none either.
A name the unit list already had keeps its meaning, and the list is read first. So min is the minute (not a
milli-inch), mm is the millimetre, Pa the pascal, cd the candela, ft the foot, h the hour, d the day,
T the tesla and u the atomic mass unit; da alone is not a unit, and dam is the decametre. The prefix
spellings that read as another unit are told apart by their case: fT is a femtotesla and ft a foot, mS is
a millisiemens and ms a millisecond. One name is shadowed: ks has always been the metric horsepower, so a
kilosecond is written 1000 s. A variable you define always wins over a unit of the same
name, so a sheet that has a variable called mN still works.
F: 3 mN
F_n: F -> N
E: 2 GPa
E_m: E -> MPa
t: 5 µm
t_n: t -> nm
F_n = F = 3 mN = 0.003 N
E_m = E = 2 GPa = 2000 MPa
t_n = t = 5 μm = 5000 nm
Errors you want
x: 6 m
t: 2 s
speed: x / t
speed = x/t = 6 m / 2 s = 3 m/s
Dividing a length by a time is fine. Adding them is not:
x: 6 m
t: 2 s
speed: x / t
len: x + t
Error in "len = x + t" on line [4]: Inconsistent units: "m + s".
That is the engine doing its job. A unit slip is the most common mistake in hand calculations, and here it stops the sheet and names the line.
Which units exist
The built-in list is long. The groups are:
| Group | Examples |
|---|---|
| Dimensionless | %, ‰, ppm, angles °, rad, grad, rev |
| Mass | g, kg, t, mg, lb, oz, slug |
| Length | m, km, mm, μm, in, ft, yd, mi, nmi |
| Time and frequency | s, ms, min, h, d, Hz, rpm |
| Force | N, kN, MN, kgf, lbf, kip |
| Pressure | Pa, kPa, MPa, bar, atm, psi, ksi |
| Energy and power | J, kJ, Wh, kWh, cal, BTU, W, kW, hp |
| Area and volume | a, ha, ac, L, mL, gal, bbl |
| Temperature | K, °C, °F, °R |
| Electrical | A, V, Ω, F, H, C, S, T, Wb |
| Other | mol, cd, lm, lx, Bq, Gy, Sv, kat |
The Insert tab in the sidebar lists all 400 or so, grouped, and a click inserts one. The Math tab has a Units palette organised by dimension.
Angles
Angle units are accepted by trigonometric functions and override every other setting.
sin(30 deg) is 0.5 whatever the angle setting is. A bare number follows the setting: degrees by
default, changed on the Math Formatting tab (#deg, #rad, #gra in Calcpad). Inverse
trigonometric functions return a plain number unless you define ReturnAngleUnits = 1
(Calcpad line) first:
a = asin(0.5)
ReturnAngleUnits = 1
b = asin(0.5)
a = asin(0.5) = 30
ReturnAngleUnits = 1
b = asin(0.5) = 30°
Temperatures
20 °C is a temperature; 300 K is another, and the difference of two temperatures is a
difference:
T1: 20 °C
T2: 300 K
d: T2 - T1
d = T2 − T1 = 300 K − 20 °C = 280 K
US and UK names
A few bare names mean different things in the US and UK systems (gal, ton, pt, qt, bbl,
cwt, therm). The setting Non-metric units picks one. Write the explicit suffix
(gal_US, gal_UK) when a sheet must not depend on the setting.
Percentages
A ratio has no unit, so it comes out as a plain number. Convert it with -> % to show it as a
percentage, and write % after a number to enter one. ‰ (per mille) works the same way.
Ed: 245.25 kN
Rd: 355.1 kN
ratio: Ed / Rd
util: ratio -> %
r: 4%
f: Ed * r
slope: 1 / 40 -> ‰
ratio = Ed / Rd = 245.25 kN / 355.1 kN = 0.691
util = ratio = 0.691 = 69.07 %
r = 4 %
f = Ed · r = 245.25 kN · 4 % = 9.81 kN
slope = 1 / 40 = 25 ‰
The value itself does not change, only the way it is shown: util is the same number as
ratio, and r is 0.04 in every formula. A result in percent is rounded to the decimals set on the
Math Formatting tab like any other result, and the rounded figure typed back in (69.07%) is the
same ratio to that many digits. An input works the same way: rate: ? 12.5 % shows a box holding
12.5 with % after it, and the name is 0.125 in the formulas.
A percentage times a plain number is a plain number (4 % · 2 is 0.08); add -> % to the line
to keep it as a percentage.
Your own units
A sheet defines a unit of its own with a #unit line: the name, =, and its value in units
the engine knows or in units defined above it. Later lines use it after a number and after ->,
like any other unit.
#unit bag = 25 kg | cement bag
#unit pallet = 40 bag
load: 3 pallet -> t
n: 1000 kg -> bag
rate: 6 bag / 1 m³ -> kg/m³
bag = 25 kg cement bag
pallet = 40 bag
load = 3 pallet = 3 t
n = 1000 kg = 40 bag
rate = 6 bag / 1 m³ = 150 kg/m³
A unit name is letters and _ only (bag, ton_short), with no digits; a name with a digit is an
error on its line. The value can use the usual spellings (m², kN·m) and can have a note after
|. A built-in unit cannot be redefined: #unit slug = 14.6 kg is an error, because slug is
already a unit. In the Calcpad language, and in a >> line of a sheet, the same unit is a line
with a dot in front of the name: .bag = 25kg.
Currency and information units are defined as dimensionless units, the first as 1 and the others as multiples:
#unit USD = 1
#unit AUD = 0.65 USD
price: 200 AUD -> USD
USD = 1
AUD = 0.65 USD
price = 200 AUD = 130 USD
Two families of dimensionless custom units in one sheet share a dimension, so do not mix them.
Units and names
A word that follows a number immediately is a unit (2 m). A standalone word is a variable if you
defined one with that name, and a unit otherwise. Put a dot in front to force a unit even when a
variable has the same name. In a sheet this rarely matters, but it explains one surprise: if you
name a variable m and later write 5 m, the m after the number is still the unit.
Removing and reading units
The functions getunits(x), clrunits(x) and setunits(x, u) read, strip and attach units. They
are in the function reference.
q: setunits(5, kN)
F: 5 kN
n: F / 1 kN
q = setunits(5; kN) = 5 kN
F = 5 kN
n = F / 1 kN = 5 kN / 1 kN = 5
Use clrunits sparingly. A value without a unit is a value the engine can no longer check.
Units in vectors and matrices
A vector or matrix whose elements all carry the same unit shows the unit once after the bracket. See Vectors and matrices.
Related pages: Calculations with units, Simply supported beam, Pipe flow, Darcy-Weisbach. More pages are in Calculators and guides.
Vectors and matrices
Writing them
In a sheet, a bracket makes a vector or a matrix. Elements are separated by commas or semicolons and rows by semicolons:
| You write | You get |
|---|---|
[1, 2, 3] or [1; 2; 3] | a vector with three elements |
[1, 2; 3, 4] | a 2 by 2 matrix: columns separated by commas, rows by semicolons |
Rows must have equal length and elements can be expressions. (In the Calcpad language the same
matrix is [1; 2 | 3; 4], with | between rows.)
v: [1, 2, 3]
A: [2, -1; -1, 2]
b: [1; 0]
x: lsolve(A, b)
d: det(A)
e: v.2
f: A.(1, 2)
v = [1; 2; 3] = [1 2 3]
A = [2; -1 | -1; 2] = | 2 -1 |
| -1 2 |
b = [1; 0] = [1 0]
x = lsolve(A; b) = [0.667 0.333]
d = det(A) = 3
e = v.2 = 2
f = A.(1; 2) = -1
An element is reached with a dot: v.2 is the second element of the vector v, and A.(1, 2) is
row 1, column 2 of A. Indexes start at 1.
Vector and matrix names show an arrow over a vector in the report.
Arithmetic
A: [1, 2; 3, 4]
B: A * A
C: A + 2
D: A - [1, 1; 1, 1]
At: transp(A)
v: [1; 2]
Av: A * v
r: rank(A)
tr: trace(A)
B = A·A = | 7 10 |
| 15 22 |
C = A + 2 = | 3 4 |
| 5 6 |
Av = A·v = [5 11]
rank(A) = 2 trace(A) = 5
A matrix times a matrix is the matrix product. A matrix plus or minus a number applies to every
element. A power applies to every element of a vector (x^2 above squares each element), and
hprod(A, B) is the element-by-element product of two matrices.
Solving and decomposing
K: [4, -2; -2, 3]
F: [10; 0]
u: lsolve(K, F)
u = lsolve(K; F) = [3.75 2.5]
lsolve(A, b) solves A x = b with an LDLᵀ factorisation for a symmetric matrix and an LU
factorisation otherwise. clsolve uses Cholesky and slsolve an iterative method for large
sparse systems. msolve solves for several right-hand sides at once. inverse, det, rank,
cond, lu, qr, svd, cholesky, eigenvals, eigenvecs and eigen are there too.
Eigenvalues and eigenvectors
K: [4, -2; -2, 3]
lam: eigenvals(K)
V: eigenvecs(K)
E: eigen(K)
lam = eigenvals(K) = [1.44 5.56]
V = eigenvecs(K) = | -0.615 -0.788 |
| -0.788 0.615 |
E = eigen(K) = | 1.44 -0.615 -0.788 |
| 5.56 -0.788 0.615 |
eigenvals(M) returns the eigenvalues of a square matrix in ascending order.
eigenvecs(M) returns one unit eigenvector per row, in the same order, and eigen(M) gives
both at once with the eigenvalue in the first column. A second argument keeps only some of them:
eigenvals(M, 2) is the two smallest and eigenvals(M, -1) the largest. Units carry over, so a
stress tensor in MPa has principal stresses in MPa.
The matrix does not have to be symmetric:
A: [4, 1; 2, 3]
lam: eigenvals(A)
V: eigenvecs(A)
lmax: eigenvals(A, -1)
lam = eigenvals(A) = [2 5]
V = eigenvecs(A) = | -0.447 0.894 |
| 0.707 0.707 |
lmax = eigenvals(A; -1) = [5]
A symmetric matrix uses the symmetric solver. Any other square matrix is reduced to Hessenberg form and solved with the shifted QR iteration; each eigenvector is scaled to unit length with its largest component positive.
Complex eigenvalues
A real matrix that is not symmetric can have complex eigenvalues, which a vector cannot hold.
eigenvals then stops with The matrix has complex eigenvalues. Use ceigenvals and
ceigenvecs, which write each complex number as a real part and an imaginary part, the same
layout fft uses:
R: [1, -2; 2, 1]
C: ceigenvals(R)
W: ceigenvecs(R)
C = ceigenvals(R) = | 1 1 |
| -2 2 |
W = ceigenvecs(R) = | 0.707 0 |
| 0 0.707 |
| 0.707 0 |
| 0 -0.707 |
Column k of ceigenvals is eigenvalue k: row 1 is the real part and row 2 the imaginary part,
so the eigenvalues above are 1 - 2i and 1 + 2i. In ceigenvecs eigenvector k is row 2k - 1
(real parts) plus row 2k (imaginary parts): the first one is [0.707, 0.707i]. They are sorted by
real part, then imaginary part.
For the polar form, magnitude and angle, use the two rows:
R: [1, -2; 2, 1]
C: ceigenvals(R)
mag: sqrt(row(C, 1)^2 + row(C, 2)^2)
ang: atan2(row(C, 1), row(C, 2))
mag = [2.24 2.24]
ang = atan2(row(C; 1); row(C; 2)) = [-63.43 63.43]
In a Calcpad document with complex numbers switched on in Settings, #phasor shows every
complex result as magnitude∠angle, and #complex switches back to a + bi.
Natural frequencies: K x = λ M x
Give eigenvals, eigenvecs or eigen a second matrix and they solve the generalized problem
K x = λ M x. With a stiffness matrix K and a mass matrix M, each λ is ω², the square of a natural
circular frequency:
k: 20000 kN/m
m: 10 t
K: [2*k, -k; -k, k]
M: [2*m, 0 t; 0 t, m]
λ: eigenvals(K, M)
f_1: sqrt(λ.1)/(2*π) -> Hz
Phi: eigenvecs(K, M)
m_1: dot(row(Phi, 1), M*row(Phi, 1))
λ = eigenvals(K; M) = [585.79 3414.21] s⁻²
f_1 = 3.85 Hz
Φ = eigenvecs(K; M) = | 0.158 0.224 | t^-0.5
| -0.158 0.224 |
m_1 = 1
K must be symmetric and M symmetric positive definite, both square and the same size; anything
else stops with a message that says which matrix is wrong. The eigenvalues come in ascending order
with the units of K/M (kN/m over t is s⁻²). Each mode shape is a row of eigenvecs(K, M), scaled so
that xᵀ M x = 1 and turned so that its largest component is positive; its units are those of
M^-0.5, so the modal mass m_1 above is exactly 1. Divide a row by one of its components to scale
it to 1 at that point instead. Internally M is factored by Cholesky (M = L Lᵀ), the problem is
turned into the symmetric one of L⁻¹ K L⁻ᵀ, solved with the symmetric solver, and transformed back.
To keep only the lowest modes, take them from the result: first(eigenvals(K, M), 3).
The samples Principal stresses (a plane and a 3D stress tensor, checked with Mohr’s circle) and
Shear frame natural frequencies (the frequencies and mode shapes of a two storey frame from
eigenvals(K, M)) use these functions.
Building vectors and matrices
x: range(0, 10, 2.5)
y: x^2
s: sum(y)
mx: max(y)
w: linspace(0, 1, 5)
x = range(0; 10; 2.5) = [0 2.5 5 7.5 10]
y = x ^ 2 = [0 6.25 25 56.25 100]
s = sum(y) = 187.5
mx = max(y) = 100
w = linspace(0; 1; 5) = [0 0.25 0.5 0.75 1]
Constructors: vector(n), matrix(m, n), identity(n), diagonal(n, d), column(m, c),
utriang(n), ltriang(n), symmetric(n), join_cols, join_rows, augment, stack.
Pieces: row, col, submatrix, slice, first, last, extract, diag2vec. Sorting and
searching: sort, rsort, order, find, lookup, hlookup, vlookup. Statistics and
interpolation: average, median, stdev, var, take, line, spline, interp, linterp,
polyfit.
A2: [1, 2, 3; 4, 5, 6]
r1: row(A2, 1)
c2: col(A2, 2)
sm: submatrix(A2, 1, 2, 2, 3)
r1 = row(A2; 1) = [1 2 3]
c2 = col(A2; 2) = [2 5]
sm = submatrix(A2; 1; 2; 2; 3) = | 2 3 |
| 5 6 |
The whole list is in the function reference. The large high-performance
variants (matrix_hp and so on) are for big numerical models: they store the numbers more
compactly and are faster, and they behave like the ordinary ones in a calculation.
Units in vectors and matrices
A vector or matrix whose elements all have the same unit shows the unit once, after the closing bracket:
P: [16 ft; 12 ft]
Q: [3 m; 40 cm]
P = [16; 12] ft = [16 12] ft
Q = [3 m; 40 cm] = [3 0.4] m
Elements in another unit of the same dimension are converted to the first element’s unit in the
result. An element that is an expression, has no unit, or has another dimension keeps its own
unit. To write the unit on every element, put a >> line in the sheet:
>> #settings {"unitPerElement": true}
P: [16 ft; 12 ft]
You cannot write a unit after a bracket ([1, 2] kN). Put it on the elements.
Reading and writing files
#read brings a matrix in from a text, CSV or Excel file in the library, and #write and
#append save one. They are Calcpad directives, so in a sheet they are >> lines:
>> #read M from loads.csv
>> #write M to results.csv
Add the files to the library first (File > Open, or drag them onto the page). The options for cell ranges and separators are in the directive list.
Related calculators: Principal stresses, Principal axes of a section, Shear frame frequencies. More pages are in Calculators and guides.
Function and command reference
This page is generated from the editor’s own snippet library (book/gen-reference.py), so it
lists what the Insert tab and the ribbon offer. In the Calcpad language, arguments are separated
with ;, as shown here. In a sheet, write commas: max(a, b).
Names are case sensitive. Greek letters, subscripts (x_1) and primes can be part of a name.
Constants
π (also pi) and e are built in. The others are snippets that insert a definition line; until the line is in the worksheet the name means whatever it meant before (g is the unit gram).
| Form | Meaning |
|---|---|
π | Pi - ratio of circumference to diameter |
pi | Pi - ratio of circumference to diameter (spelled out) |
e | Euler’s number - base of natural logarithm |
φ = 1.618033988749894 | Golden ratio |
γ = 0.5772156649015328 | Euler-Mascheroni constant |
g = 9.80665m/s^2 | Standard gravitational acceleration |
G = 6.67430*10^-11*(m^3/(kg*s^2)) | Gravitational constant |
M_E = 5.9722*10^24*kg | Earth mass |
M_S = 1.98847*10^30*kg | Solar mass |
c = 299792458m/s | Speed of light in vacuum |
h = 6.62607015*10^-34*J/Hz | Planck constant |
μ_0 = 1.25663706212*10^-6*N/A^2 | Vacuum permeability |
ε_0 = 8.8541878128*10^-12*F/m | Vacuum permittivity |
k_e = 8.9875517923*10^9*N*m^2/C^2 | Coulomb constant |
e = 1.602176634*10^-19*C | Elementary charge |
m_e = 9.1093837015*10^-31*kg | Electron mass |
m_p = 1.67262192369*10^-27*kg | Proton mass |
m_n = 1.67492749804*10^-27*kg | Neutron mass |
N_A = 6.02214076*10^23*mol^-1 | Avogadro constant |
σ = 5.670374419*10^-8*W*m^-2*K^-4 | Stefan-Boltzmann constant |
k_B = 1.380649*10^-23*J/K | Boltzmann constant |
R = 8.31446261815324*(J/(mol*K)) | Molar gas constant |
F = 96485.33212331C/mol | Faraday constant |
γ_c = 25kN/m^3 | Unit weight of concrete |
γ_s = 78.5kN/m^3 | Unit weight of steel |
γ_a = 27kN/m^3 | Unit weight of aluminium |
γ_g = 25kN/m^3 | Unit weight of glass |
γ_w = 10kN/m^3 | Unit weight of water |
Operators
Where a typed alternative exists it is given; the editor converts it when a file is opened.
| Form | Meaning |
|---|---|
! | Factorial |
^ | Exponent (power) |
/ | Division |
÷ | Division bar (inline) / slash (pro mode) |
\ | Integer division |
⦼ | Modulo (remainder) (type %%) |
* | Multiplication |
- | Subtraction / Negation |
+ | Addition |
≡ | Equal to (type ==) |
≠ | Not equal to (type !=) |
< | Less than |
> | Greater than |
≤ | Less than or equal (type <=) |
≥ | Greater than or equal (type >=) |
∧ | Logical AND (type &&) |
∨ | Logical OR (type ||) |
⊕ | Logical XOR |
∠ | Phasor angle operator A∠φ (type <<) |
= | Assignment |
← | Outer scope assignment (type <*) |
Functions
Trigonometric
| Form | Meaning |
|---|---|
sin(x) | Sine |
cos(x) | Cosine |
tan(x) | Tangent |
csc(x) | Cosecant |
sec(x) | Secant |
cot(x) | Cotangent |
Inverse Trigonometric
| Form | Meaning |
|---|---|
asin(x) | Inverse sine (arc sine) |
acos(x) | Inverse cosine (arc cosine) |
atan(x) | Inverse tangent (arc tangent) |
atan2(a; b) | Two-argument arc tangent |
acsc(x) | Inverse cosecant |
asec(x) | Inverse secant |
acot(x) | Inverse cotangent |
Hyperbolic
| Form | Meaning |
|---|---|
sinh(x) | Hyperbolic sine |
cosh(x) | Hyperbolic cosine |
tanh(x) | Hyperbolic tangent |
csch(x) | Hyperbolic cosecant |
sech(x) | Hyperbolic secant |
coth(x) | Hyperbolic cotangent |
Inverse Hyperbolic
| Form | Meaning |
|---|---|
asinh(x) | Inverse hyperbolic sine |
acosh(x) | Inverse hyperbolic cosine |
atanh(x) | Inverse hyperbolic tangent |
acsch(x) | Inverse hyperbolic cosecant |
asech(x) | Inverse hyperbolic secant |
acoth(x) | Inverse hyperbolic cotangent |
Logarithmic, Exponential and Roots
| Form | Meaning |
|---|---|
log(x) | Decimal (base-10) logarithm |
ln(x) | Natural logarithm |
log_2(x) | Binary (base-2) logarithm |
exp(x) | Exponential function (e^x) |
sqr(x) | Square root |
sqrt(x) | Square root |
cbrt(x) | Cubic root |
root(a; b) | N-th root |
Rounding
| Form | Meaning |
|---|---|
round(x) | Round to the nearest integer |
floor(x) | Round down (towards -∞) |
ceiling(x) | Round up (towards +∞) |
trunc(x) | Truncate towards zero |
Integer
| Form | Meaning |
|---|---|
mod(a; b) | Remainder of integer division |
gcd(a; b) | Greatest common divisor |
lcm(a; b) | Least common multiple |
fact(x) | Factorial |
Complex
| Form | Meaning |
|---|---|
re(x) | Real part of a complex number |
im(x) | Imaginary part of a complex number |
abs(x) | Absolute value / magnitude |
phase(x) | Phase angle of a complex number |
conj(x) | Complex conjugate |
Aggregate and Interpolation
| Form | Meaning |
|---|---|
min(v₁; v₂; ...) | Minimum of multiple values (scalars, vectors, or matrices) |
min(x) | Minimum element of a vector |
min(x) | Minimum element of a matrix |
max(v₁; v₂; ...) | Maximum of multiple values (scalars, vectors, or matrices) |
max(x) | Maximum element of a vector |
max(x) | Maximum element of a matrix |
sum(v₁; v₂; ...) | Sum of multiple values (scalars, vectors, or matrices) |
sum(x) | Sum of all elements in a vector |
sum(x) | Sum of all elements in a matrix |
sumsq(v₁; v₂; ...) | Sum of squares of multiple values (scalars, vectors, or matrices) |
sumsq(x) | Sum of squares of all elements in a vector |
sumsq(x) | Sum of squares of all elements in a matrix |
srss(v₁; v₂; ...) | Square root of sum of squares of multiple values (scalars, vectors, or matrices) |
srss(x) | Square root of sum of squares of all elements in a vector |
srss(x) | Square root of sum of squares of all elements in a matrix |
average(v₁; v₂; ...) | Arithmetic mean of multiple values (scalars, vectors, or matrices) |
average(x) | Arithmetic mean of all elements in a vector |
average(x) | Arithmetic mean of all elements in a matrix |
product(v₁; v₂; ...) | Product of multiple values (scalars, vectors, or matrices) |
product(x) | Product of all elements in a vector |
product(x) | Product of all elements in a matrix |
mean(v₁; v₂; ...) | Geometric mean of multiple values (scalars, vectors, or matrices) |
mean(x) | Geometric mean of all elements in a vector |
mean(x) | Geometric mean of all elements in a matrix |
median(v₁; v₂; ...) | Median of multiple values (scalars, vectors, or matrices) |
stdev(v₁; v₂; ...) | Sample standard deviation (n - 1) of multiple values |
stdevp(v₁; v₂; ...) | Population standard deviation (n) of multiple values |
var(v₁; v₂; ...) | Sample variance (n - 1) of multiple values |
varp(v₁; v₂; ...) | Population variance (n) of multiple values |
take(a; b) | Returns the n-th element from a list of scalars |
take(a; b) | Returns the n-th element from a vector |
take(a; b) | Returns the n-th element from a matrix |
line(a; b) | Linear interpolation with scalar data pairs |
line(a; b; c) | Linear interpolation with x and y vectors |
line(a; b) | Linear interpolation over a linearized matrix |
spline(a; b) | Hermite spline interpolation with scalar data pairs |
spline(a; b; c) | Hermite spline interpolation with x and y vectors |
spline(a; b) | Hermite spline interpolation over a linearized matrix |
Conditional and Logical
| Form | Meaning |
|---|---|
if(a; b; c) | Conditional evaluation |
switch(c₁; v₁; c₂; v₂; …; def) | Selective evaluation (multiple conditions) |
not(x) | Logical NOT |
and(a; b) | Logical AND of multiple boolean values |
or(a; b) | Logical OR of multiple boolean values |
xor(a; b) | Logical XOR of multiple boolean values |
Other
| Form | Meaning |
|---|---|
sign(x) | Sign of a number (-1, 0, or 1) |
random(x) | Random number between 0 and x |
getunits(x) | Gets the units of x (returns 1 if unitless) |
setunits(a; b) | Sets the units to a scalar, vector, or matrix |
clrunits(x) | Clears the units from a scalar, vector, or matrix |
hp(x) | Converts to high-performance type |
ishp(x) | Checks if the type is high-performance |
timer(x) | Elapsed time in seconds |
mandelbrot(a; b) | Mandelbrot set escape value |
Vector functions
Creational
| Form | Meaning |
|---|---|
vector(x) | Creates an empty vector with length n |
vector_hp(x) | Creates an empty high-performance vector with length n |
range(a; b; c) | Creates a vector with values from x1 to xn with step s |
range_hp(a; b; c) | Creates a high-performance vector from a range |
linspace(a; b; c) | Vector of n equally spaced values from a to b |
Structural
| Form | Meaning |
|---|---|
len(x) | Returns the length of the vector |
size(x) | Returns the actual size (index of last non-zero element) |
resize(a; b) | Sets a new length for the vector |
fill(a; b) | Fills the vector with a value |
join(x) | Creates a vector by joining matrices, vectors, and scalars |
slice(a; b; c) | Returns part of vector bounded by indexes i1 and i2 |
first(a; b) | Returns the first n elements of the vector |
last(a; b) | Returns the last n elements of the vector |
extract(a; b) | Extracts elements from v whose indexes are in i |
Data
| Form | Meaning |
|---|---|
sort(x) | Sorts the vector in ascending order |
rsort(x) | Sorts the vector in descending order |
order(x) | Returns indexes in ascending order by element values |
revorder(x) | Returns indexes in descending order by element values |
reverse(x) | Returns vector with elements in reverse order |
count(a; b; c) | Counts elements equal to x starting from index i |
search(a; b; c) | Returns index of first element equal to x starting from i |
find(a; b; c) | Returns indexes of elements equal to x after index i |
find_eq(a; b; c) | Returns indexes of elements = x after index i |
find_ne(a; b; c) | Returns indexes of elements != x after index i |
find_lt(a; b; c) | Returns indexes of elements < x after index i |
find_le(a; b; c) | Returns indexes of elements <= x after index i |
find_gt(a; b; c) | Returns indexes of elements > x after index i |
find_ge(a; b; c) | Returns indexes of elements >= x after index i |
lookup(a; b; c) | Elements of a where corresponding elements of b equal x |
lookup_eq(a; b; c) | Elements of a where b elements = x |
lookup_ne(a; b; c) | Elements of a where b elements != x |
lookup_lt(a; b; c) | Elements of a where b elements < x |
lookup_le(a; b; c) | Elements of a where b elements <= x |
lookup_gt(a; b; c) | Elements of a where b elements > x |
lookup_ge(a; b; c) | Elements of a where b elements >= x |
polyfit(a; b; c) | Least-squares polynomial fit |
interp(a; b; c) | Linear interpolation in a table |
linterp(a; b; c) | Linear interpolation in a table, continued outside it |
Math
| Form | Meaning |
|---|---|
norm(x) | L2 (Euclidean) norm of vector |
norm_1(x) | L1 (Manhattan) norm of vector |
norm_2(x) | L2 (Euclidean) norm of vector |
norm_e(x) | L2 (Euclidean) norm of vector |
norm_p(a; b) | Lp norm of vector |
norm_i(x) | L-infinity norm of vector |
unit(x) | Normalized vector (with L2 norm = 1) |
cumsum(x) | Running sum of a vector |
convolve(a; b) | Discrete convolution of two vectors |
dot(a; b) | Scalar (dot) product of two vectors |
cross(a; b) | Cross product of two vectors (length 2 or 3) |
Matrix functions
Functions marked _hp use the high-performance storage; they behave like the ordinary ones.
Creational
| Form | Meaning |
|---|---|
matrix(a; b) | Creates an empty matrix with dimensions m x n |
identity(x) | Creates an identity matrix with dimensions n x n |
diagonal(a; b) | Creates a diagonal matrix n x n filled with value d |
column(a; b) | Creates a column matrix m x 1 filled with value c |
utriang(x) | Creates an upper triangular matrix n x n |
ltriang(x) | Creates a lower triangular matrix n x n |
symmetric(x) | Creates a symmetric matrix n x n |
matrix_hp(a; b) | Creates a high-performance matrix m x n |
identity_hp(x) | Creates a high-performance identity matrix n x n |
diagonal_hp(a; b) | Creates a high-performance diagonal matrix n x n |
column_hp(a; b) | Creates a high-performance column matrix m x 1 |
utriang_hp(x) | Creates a high-performance upper triangular matrix |
ltriang_hp(x) | Creates a high-performance lower triangular matrix |
symmetric_hp(x) | Creates a high-performance symmetric matrix |
vec2diag(x) | Creates a diagonal matrix from vector elements |
vec2row(x) | Creates a row matrix from vector elements |
vec2col(x) | Creates a column matrix from vector elements |
join_cols(a; b) | Creates a matrix by joining column vectors |
join_rows(a; b) | Creates a matrix by joining row vectors |
augment(a; b) | Creates a matrix by appending matrices side by side |
stack(a; b) | Creates a matrix by stacking matrices vertically |
Structural
| Form | Meaning |
|---|---|
n_rows(x) | Number of rows in matrix M |
n_cols(x) | Number of columns in matrix M |
mresize(a; b; c) | Sets new dimensions m and n for matrix M |
mfill(a; b) | Fills the matrix M with value x |
fill_row(a; b; c) | Fills the i-th row of matrix M with value x |
fill_col(a; b; c) | Fills the j-th column of matrix M with value x |
copy(a; b; c; d) | Copies all elements from A to B starting at indexes i, j |
add(a; b; c; d) | Adds elements from A to B starting at indexes i, j |
row(a; b) | Extracts the i-th row of matrix M as a vector |
col(a; b) | Extracts the j-th column of matrix M as a vector |
extract_rows(a; b) | Extracts rows from M whose indexes are in vector i |
extract_cols(a; b) | Extracts columns from M whose indexes are in vector j |
diag2vec(x) | Extracts diagonal elements of matrix M to a vector |
submatrix(a; b; c; d; e) | Extracts submatrix bounded by rows i1-i2 and columns j1-j2 |
Data
| Form | Meaning |
|---|---|
sort_cols(a; b) | Sorts columns based on values in row i (ascending) |
rsort_cols(a; b) | Sorts columns based on values in row i (descending) |
sort_rows(a; b) | Sorts rows based on values in column j (ascending) |
rsort_rows(a; b) | Sorts rows based on values in column j (descending) |
order_cols(a; b) | Column indexes in ascending order by row i values |
revorder_cols(a; b) | Column indexes in descending order by row i values |
order_rows(a; b) | Row indexes in ascending order by column j values |
revorder_rows(a; b) | Row indexes in descending order by column j values |
mcount(a; b) | Number of occurrences of value x in matrix M |
msearch(a; b; c; d) | Vector with indexes of first occurrence of x starting from i, j |
mfind(a; b) | Indexes of all elements in M equal to x |
mfind_eq(a; b) | Indexes of elements = x |
mfind_ne(a; b) | Indexes of elements != x |
mfind_lt(a; b) | Indexes of elements < x |
mfind_le(a; b) | Indexes of elements <= x |
mfind_gt(a; b) | Indexes of elements > x |
mfind_ge(a; b) | Indexes of elements >= x |
hlookup(a; b; c; d) | Values from row i2 where row i1 elements = x |
hlookup_eq(a; b; c; d) | Values from row i2 where row i1 = x |
hlookup_ne(a; b; c; d) | Values from row i2 where row i1 != x |
hlookup_lt(a; b; c; d) | Values from row i2 where row i1 < x |
hlookup_le(a; b; c; d) | Values from row i2 where row i1 <= x |
hlookup_gt(a; b; c; d) | Values from row i2 where row i1 > x |
hlookup_ge(a; b; c; d) | Values from row i2 where row i1 >= x |
vlookup(a; b; c; d) | Values from column j2 where column j1 = x |
vlookup_eq(a; b; c; d) | Values from column j2 where column j1 = x |
vlookup_ne(a; b; c; d) | Values from column j2 where column j1 != x |
vlookup_lt(a; b; c; d) | Values from column j2 where column j1 < x |
vlookup_le(a; b; c; d) | Values from column j2 where column j1 <= x |
vlookup_gt(a; b; c; d) | Values from column j2 where column j1 > x |
vlookup_ge(a; b; c; d) | Values from column j2 where column j1 >= x |
Math
| Form | Meaning |
|---|---|
hprod(a; b) | Hadamard (element-wise) product of matrices A and B |
fprod(a; b) | Frobenius product of matrices A and B |
kprod(a; b) | Kronecker product of matrices A and B |
mnorm(x) | L2 norm of matrix M |
mnorm_1(x) | L1 norm of matrix M |
mnorm_2(x) | L2 norm of matrix M |
mnorm_e(x) | Frobenius norm of matrix M |
mnorm_i(x) | L-infinity norm of matrix M |
cond(x) | Condition number based on L2 norm |
cond_1(x) | Condition number based on L1 norm |
cond_2(x) | Condition number based on L2 norm |
cond_e(x) | Condition number based on Frobenius norm |
cond_i(x) | Condition number based on L-infinity norm |
det(x) | Determinant of matrix M |
rank(x) | Rank of matrix M |
trace(x) | Trace of matrix M (sum of diagonal elements) |
transp(x) | Transpose of matrix M |
adj(x) | Adjugate of matrix M |
cofactor(x) | Cofactor matrix of M |
polyroots(x) | Real roots of a polynomial |
eigenvals(a; b) | First ne eigenvalues of matrix M (or all if omitted), or of K x = λ M x |
eigenvecs(a; b) | First ne eigenvectors of matrix M (or all if omitted), or of K x = λ M x |
eigen(a; b) | First ne eigenvalues and eigenvectors (or all if omitted) |
ceigenvals(x) | Complex eigenvalues of matrix M |
ceigenvecs(x) | Complex eigenvectors of matrix M |
cholesky(x) | Cholesky decomposition of symmetric positive-definite matrix |
lu(x) | LU decomposition of matrix M |
qr(x) | QR decomposition of matrix M |
svd(x) | Singular value decomposition of M |
inverse(x) | Inverse of matrix M |
lsolve(a; b) | Solves Ax = b using LDLT (symmetric) or LU decomposition |
clsolve(a; b) | Solves Ax = b using Cholesky decomposition |
slsolve(a; b) | Solves Ax = b using preconditioned conjugate gradient |
msolve(a; b) | Solves AX = B using LDLT or LU decomposition |
cmsolve(a; b) | Solves AX = B using Cholesky decomposition |
smsolve(a; b) | Solves AX = B using preconditioned conjugate gradient |
fft(x) | Fast Fourier transform (1 row for real, 2 for complex) |
ift(x) | Inverse Fourier transform (1 row for real, 2 for complex) |
take(a; b; c) | Returns element of matrix M at indexes x and y |
line(a; b; c) | Double linear interpolation from matrix M |
spline(a; b; c) | Double Hermite spline interpolation from matrix M |
Commands
Commands start with $ and take their arguments in braces. @ separates the expression from the variable and its interval a : b. In a sheet, write them on a >> line, except plots, which have the plot line.
| Form | Meaning |
|---|---|
$Root{a @ b = c : d} | Root finding for f(x) = 0 |
$Root{a = b @ c = d : e} | Root finding for f(x) = const |
$Find{a @ b = c : d} | Find approximate solution (x not required to be precise) |
$Sup{a @ b = c : d} | Find local maximum of a function |
$Inf{a @ b = c : d} | Find local minimum of a function |
$Area{a @ b = c : d} | Numerical integration (adaptive Gauss-Lobatto) |
$Integral{a @ b = c : d} | Numerical integration (Tanh-Sinh) |
$Slope{a @ b = c} | Numerical differentiation (slope at point) |
$Sum{a @ b = c : d} | Iterative sum |
$Product{a @ b = c : d} | Iterative product |
$Repeat{a @ b = c : d} | Iterative expression block with counter |
$While{a; b} | Iterative expression block with condition |
$Block{x} | Multiline expression block |
$Inline{x} | Inline expression block |
$Plot{a @ b = c : d} | Simple function plot |
$Plot{a | b @ c = d : e} | Parametric plot |
$Plot{a & b @ c = d : e} | Multiple function plot |
$Map{a @ b = c : d & e = f : g} | 2D color map of a 3D surface |
Directives
Directives start with #. The block forms (#if … #end if) are listed once, by their opening word.
Program Flow Control
| Form | Meaning |
|---|---|
#if | If condition |
#else if condition | Else If clause |
#else | Else clause |
Iteration Blocks
| Form | Meaning |
|---|---|
#repeat | Repeat loop start |
#for | For loop start |
#while | While loop start |
#loop | End of loop block |
#break | Break out of current loop |
#continue | Continue to next iteration |
Modules and Macros
| Form | Meaning |
|---|---|
#include filename | Include external file (module). Path is relative to the current file or the library path. |
#ProjectPath path | Declares the folder {project} stands for in #include, #read, #write and image paths below this line. |
#LibraryPath path | Declares the folder {library} stands for in #include, #read, #write and image paths below this line. |
#local | Start local section (not included when file is imported) |
#global | Start global section (included when file is imported) |
#def | Define macro or string variable |
#def name$ = expression | Inline string variable definition |
#def name$(param$) = expression | Inline macro with parameters |
External Data
| Form | Meaning |
|---|---|
#read M from filename | Read matrix from text/CSV or Excel file |
#read M from filename.csv@R1C1:R2C2 TYPE=R SEP=',' | Read matrix from a CSV/text file with all options. @R1C1:R2C2 = cell range (row, column). TYPE: R=Raw (default), D=Diagonal, C=Column, L=Lower triangular, U=Upper triangular, S=Symmetric, V=Vector. SEP: column separator character (default ‘,’). |
#read M from filename.xlsx@Sheet1!A1:B2 TYPE=R | Read matrix from an Excel file (.xlsx/.xlsm) with all options. @Sheet!A1:B2 = sheet name and cell range. TYPE: R=Raw (default), D=Diagonal, C=Column, L=Lower triangular, U=Upper triangular, S=Symmetric, V=Vector. |
#write M to filename | Write matrix to text/CSV or Excel file |
#write M to filename.csv@R1C1:R2C2 TYPE=N SEP=',' | Write matrix to a CSV/text file with all options. @R1C1:R2C2 = cell range (row, column). TYPE: Y=Compact (transpose special matrix types), N=Normal (default). SEP: column separator character (default ‘,’). |
#write M to filename.xlsx@Sheet1!A1:B2 TYPE=N | Write matrix to an Excel file (.xlsx/.xlsm) with all options. @Sheet!A1:B2 = sheet name and cell range. TYPE: Y=Compact (transpose special matrix types), N=Normal (default). |
#append M to filename | Append matrix to text/CSV or Excel file |
#append M to filename.csv@R1C1:R2C2 TYPE=N SEP=',' | Append matrix to a CSV/text file with all options. @R1C1:R2C2 = cell range (row, column). TYPE: Y=Compact (transpose special matrix types), N=Normal (default). SEP: column separator character (default ‘,’). |
#append M to filename.xlsx@Sheet1!A1:B2 TYPE=N | Append matrix to an Excel file (.xlsx/.xlsm) with all options. @Sheet!A1:B2 = sheet name and cell range. TYPE: Y=Compact (transpose special matrix types), N=Normal (default). |
Read Only
| Form | Meaning |
|---|---|
#const | Define a constant (readonly) variable or function |
#const name = value | Define a constant variable |
#const f(x) = expression | Define a constant function |
Output Control
| Form | Meaning |
|---|---|
#show | Show the output contents (default). Optionally takes a condition, e.g. ‘#show x == 5’. Applies to the rest of the document, or up to a matching #end show. |
#hide | Hide the output contents. Optionally takes a condition, e.g. ‘#hide x == 5’. Applies to the rest of the document, or up to a matching #end hide. |
#pre | Show contents on screen only - hidden when printing/exporting to PDF. Optionally takes a condition. Applies to the rest of the document, or up to a matching #end pre. |
#post | Show contents in the preview and when printing/exporting to PDF - hidden in UI mode. Optionally takes a condition. Applies to the rest of the document, or up to a matching #end post. |
#val | Show only the result, without the equation. Optionally takes a condition. Applies to the rest of the document, or up to a matching #end val. |
#equ | Show complete equations and results (default). Optionally takes a condition. Applies to the rest of the document, or up to a matching #end equ. |
#noc | Show equations without results (no calculations). Optionally takes a condition. Applies to the rest of the document, or up to a matching #end noc. |
#varsub | Show equations with both variable names and their substituted values (default). Optionally takes a condition. Applies to the rest of the document, or up to a matching #end varsub. |
#nosub | Show equations with variable names only, without substituted values. Optionally takes a condition. Applies to the rest of the document, or up to a matching #end nosub. |
#novar | Show equations with substituted values only, without variable names. Optionally takes a condition. Applies to the rest of the document, or up to a matching #end novar. |
#split | Split long equations after the “=” symbol onto a new indented line. Applies to the rest of the document; takes no condition and has no #end form - switch back with #wrap. |
#wrap | Wrap long equations at the end of the line (default). Applies to the rest of the document; takes no condition and has no #end form - switch back with #split. |
#format spec | Specify custom format string |
#format default | Restore default formatting |
#phasor | Set complex number output to polar phasor (A angle phi) |
#complex | Set complex number output to cartesian algebraic (a + ib) |
#md on | Enable markdown in comments |
#md off | Disable markdown in comments |
#html | Output the following lines as raw HTML. Only #cpd, #markdown and the #end forms are allowed inside; macros still expand. Optionally takes a condition, e.g. ‘#html x > 3’, that skips the block when false. Applies up to a matching #end html, or until the next mode directive. |
#markdown | Render the following lines as Markdown, including tables, lists and code blocks. Only #cpd, #html and the #end forms are allowed inside; macros still expand. Optionally takes a condition, e.g. ‘#markdown x > 3’, that skips the block when false. Applies up to a matching #end markdown, or until the next mode directive. |
#cpd | Parse the following lines as Calcpad (the default mode), e.g. to calculate inside an #html block. Optionally takes a condition, e.g. ‘#cpd x > 3’, that skips the block when false. Applies up to a matching #end cpd, or until the next mode directive. |
UI Inputs
| Form | Meaning |
|---|---|
#UI L = 10m | Expose the following assignment as an input control in UI mode. Ignored when rendering a report. |
#UI {"type": "datagrid", "rows": 2, "columns": 3, "columnHeaders": ["a", "b", "c"]} M = [1; 2; 3 | 4; 5; 6] | Editable grid for a vector or matrix. Rows and columns are auto-detected from the right hand side when omitted. |
#UI v = [1; 2; 3] | Editable grid whose size is auto-detected from the vector or matrix assigned to it. |
#UI {"type": "datagrid", "width": "100%", "rowHeaderWidth": 120, "columnWidths": [2, 1, 1]} M = matrix(2; 3) | Sized grid. ‘width’ is the total in pixels or “100%” to fill the line; ‘columnWidths’ are shared out in proportion. |
#UI {"forceUnits": false} q = 3kN/m | Put the unit in the input box, so the whole value - number and unit - is editable. |
#UI {"allowExpression": true} k = 2*L | Accept any expression, written to the document as typed. The line’s own errors report what it cannot read. |
#UI {"type": "dropdown", "keys": ["Low", "High"], "values": ["1", "2"]} x = 1 | Drop-down list. ‘keys’ are the labels shown, ‘values’ are substituted into the calculation. |
#UI {"type": "radio", "keys": ["Steel", "Concrete"], "values": ["200GPa", "25GPa"]} E = 200GPa | Radio button group. ‘keys’ are the labels shown, ‘values’ are substituted into the calculation. |
#UI {"type": "checkbox"} b = 1 | Checkbox toggling the value between 1 and 0. |
Settings/Rounding
| Form | Meaning |
|---|---|
#round digits | Round output to n digits after decimal point |
#round default | Restore rounding to default settings |
Settings/Overrides
| Form | Meaning |
|---|---|
#settings {"decimals": 4, "substitute": false} | Override engine settings for subsequent lines via JSON. Use the Properties panel to see the available settings and edit them. |
Breakpoints
| Form | Meaning |
|---|---|
#pause | Pause calculation and wait for user to resume. Not supported in Calcpad.Web. |
#input | Render input form and wait for user input. Not supported in Calcpad.Web. |
Settings/Angle Units
| Form | Meaning |
|---|---|
#deg | Set angle units to degrees |
#rad | Set angle units to radians |
#gra | Set angle units to gradians |
Worksheet settings
Written as an assignment on a line of their own. In a sheet, use a >> line.
| Form | Meaning |
|---|---|
PlotHeight = 400 | Height of plot area in pixels |
PlotWidth = 800 | Width of plot area in pixels |
PlotSVG = 1 | Draw plots in SVG (1) or PNG (0) format |
PlotAdaptive = 1 | Use adaptive mesh (1) or uniform (0) |
PlotStep = 0 | Mesh size for map plotting |
PlotPalette = 0 | Color palette number (0-9) for surface plots |
PlotShadows = 1 | Draw surface plots with shadows |
PlotSmooth = 1 | Smooth gradient (1) or isobands (0) for surface plots |
PlotLightDir = 0 | Direction to light source (0-7) clockwise |
Precision = 1e-12 | Relative precision for numerical methods (10^-2 to 10^-16) |
Tol = 1e-8 | Target tolerance for iterative PCG solver |
Number format strings
Used after #format, or at the end of an equation to format one result.
| Form | Meaning |
|---|---|
:e | Exponential notation, default precision |
:e3 | Exponential notation with 3 mantissa digits |
:f | Fixed-point notation, default precision |
:f3 | Fixed-point notation with 3 decimal digits |
:g | General notation, default precision |
:g3 | General notation with 3 significant digits |
:n | Number with digit grouping, default precision |
:n3 | Number with digit grouping and 3 decimal digits |
:c | Currency notation, default precision |
:c3 | Currency notation with 3 decimal digits |
:0.000 | Custom format - fixed decimal places, zero-padded |
:#,#.00 | Custom format - digit grouping with optional leading digits |
:0.00e+00 | Custom format - explicit exponential notation |
Units
The predefined units by group. Prefixes (k, M, G, m, μ and so on) are listed where they apply. The names, not the descriptions, are what you type.
- Dimensionless:
%,‰,‱,pcm,ppm,ppb,ppt,ppq - Angles:
°,′,″,deg,rad,grad,rev - Metric/Mass:
g,dag,hg,kg,t,kt,Mt,Gt,dg,cg,mg,μg,ng,pg,Da,u - Metric/Length:
m,km,dm,cm,mm,μm,nm,pm,AU,ly - Metric/Area:
a,daa,ha - Metric/Volume:
L,daL,hL,dL,cL,mL,μL,nL,pL - Time:
s,ms,μs,ns,ps,min,h,d,w,y - Frequency:
Hz,kHz,MHz,GHz,THz,mHz,μHz,nHz,pHz,rpm - Speed:
kmh - Temperature:
°C,Δ°C,K - Metric/Force:
N,daN,hN,kN,MN,GN,TN,gf,kgf,tf,dyn - Metric/Moment:
Nm,kNm - Metric/Pressure:
Pa,daPa,hPa,kPa,MPa,GPa,TPa,dPa,cPa,mPa,μPa,nPa,pPa,bar,mbar,μbar,atm,at,Torr,mmHg - Metric/Viscosity:
P,cP,St,cSt - Metric/Energy:
J,kJ,MJ,GJ,TJ,mJ,μJ,nJ,pJ,Wh,kWh,MWh,GWh,TWh,mWh,μWh,nWh,pWh,VAh,kVAh,MVAh,GVAh,VARh,kVARh,MVARh,GVARh,eV,keV,MeV,GeV,TeV,PeV,EeV,cal,kcal,erg - Metric/Power:
W,kW,MW,GW,TW,mW,μW,nW,pW,VA,kVA,MVA,GVA,TVA,mVA,μVA,nVA,pVA,VAR,kVAR,MVAR,GVAR,TVAR,mVAR,μVAR,nVAR,pVAR - Electrical/Current:
A,kA,MA,GA,TA,mA,μA,nA,pA - Electrical/Charge:
C,kC,MC,GC,TC,mC,μC,nC,pC,Ah,mAh - Electrical/Potential:
V,kV,MV,GV,TV,mV,μV,nV,pV - Electrical/Capacitance:
F,kF,MF,GF,TF,mF,μF,nF,pF - Electrical/Resistance:
Ω,kΩ,MΩ,GΩ,TΩ,mΩ,μΩ,nΩ,pΩ - Electrical/Conductance:
S,kS,MS,GS,TS,mS,μS,nS,pS,℧,k℧,M℧,G℧,T℧,m℧,μ℧,n℧,p℧ - Electrical/Magnetic Flux:
Wb,kWb,MWb,GWb,TWb,mWb,μWb,nWb,pWb - Electrical/Magnetic Flux Density:
T,kT,MT,GT,TT,mT,μT,nT,pT - Electrical/Inductance:
H,kH,MH,GH,TH,mH,μH,nH,pH - Luminous:
cd,lm,lx - Radioactivity:
Bq,kBq,MBq,GBq,TBq,mBq,μBq,nBq,pBq,Ci,Rd - Dose/Absorbed:
Gy,kGy,MGy,GGy,TGy,mGy,μGy,nGy,pGy - Dose/Equivalent:
Sv,kSv,MSv,GSv,TSv,mSv,μSv,nSv,pSv - Catalytic Activity:
kat - Amount of Substance:
mol - Imperial/Mass:
gr,dr,oz,lb,lbm,lb_m,kipm,kip_m,klb,st,qr,cwt,cwt_US,cwt_UK,ton,ton_US,ton_UK,slug - Imperial/Length:
th,in,ft,yd,ch,fur,mi,ftm,ftm_UK,ftm_US,cable,cable_UK,cable_US,nmi,li,rod,pole,perch,lea - Imperial/Speed:
mph,knot - Imperial/Temperature:
°F,Δ°F,°R - Imperial/Area:
rood,ac - Imperial/Volume:
fl_dr_UK,fl_dr_US,fl_oz,fl_oz_UK,fl_oz_US,gi,gi_UK,gi_US,pt,pt_UK,pt_US,pt_dry,qt,qt_UK,qt_US,qt_dry,gal,gal_UK,gal_US,gal_dry,bbl,bbl_UK,bbl_US,bbl_dry,pk_UK,pk_US,bu_UK,bu_US - Imperial/Force:
ozf,oz_f,lbf,lb_f,kip,kipf,kip_f,tonf,tonf_US,tonf_UK,pdl - Imperial/Pressure:
osi,osf,psi,psf,ksi,ksf,tsi,tsf,inHg - Imperial/Energy:
BTU,therm,therm_US,therm_UK,quad - Imperial/Power:
hp,hp_E,hp_S,hp_M,ks
Plots
Video: Plots in the sheet format
There are three ways to draw: the plot line of the sheet format, the Calcpad $Plot and $Map
commands, and Python blocks, which are covered in Python blocks. All three can sit in
the same sheet.
Charts that are not drawn from a function, such as a pie chart, a Gantt chart, a Sankey diagram or a bar chart of values you type, are diagrams written as text. See Diagrams for a gallery of every kind, and the Plots and diagrams group of the samples.
The plot line
L: 6
w: 12
M(x): w * x * (L - x) / 2
plot M(x) for x in 0..L
The line is plot expression for variable in from..to. It becomes $Plot{ M(x) @ x = 0 : L }. The
expression can be a function you defined, or any expression of the variable:
>> #rad
plot sin(x), cos(x) for x in 0..2*π
Several expressions, separated by commas, are drawn together, each in its own colour. An optional
y = before the expressions is dropped (plot y = f(x) for x in 0..10). A malformed plot line
is reported on its line in the report and in the editor.
A legend
Give a curve a name with as "name" after its expression, and the plot gets a legend in its top
right corner: a colour swatch and the name of each curve.
>> #rad
plot sin(x) as "sine", cos(x) as "cosine" for x in 0..2*π
A curve without a name is listed by its expression, and a plot where no curve has a name has no
legend, as before. A name cannot contain quotes, &, |, @ or braces. The legend is part of the
SVG, so it is in the printout and the PDF and in the Word picture; in Excel the names are the
series names of the chart. In Calcpad text the name follows the expression in double quotes,
$Plot{sin(x) "sine" & cos(x) "cosine" @ x = 0 : 2*π} (this is not in CalcpadCE).
The plot is an SVG drawing. It is sharp at any zoom, it prints well, and its data is exported to Excel as a native chart.
Radians, not degrees
Angles are in degrees by default. sin(x) over 0..2*π is then the sine of the first six
degrees, which is a nearly flat line. Put >> #rad in the sheet before the plot, as above, or
plot over degrees (0..360).
Plotting a function with units
The plotted variable must be a plain number. If L is 6 m, then for x in 0..L stops with
Inconsistent units. Give the variable the unit inside the expression instead:
L: 6 m
w: 12 kN/m
M(x): w * x * (L - x) / 2
plot M(x * 1 m) for x in 0..6
The axes are labelled with the variable names, and the end points of the curve are marked with their values.
Other kinds of plot: $Plot and $Map
A sheet reaches the rest of the plotting commands through >> lines.
>> #rad
>> $Plot{cos(t) | sin(t) @ t = 0 : 2*π}
>> $Plot{cos(t) | sin(t) & 2*cos(t) | 2*sin(t) @ t = 0 : 2*π}
>> $Map{x*y @ x = -1 : 1 & y = -1 : 1}
| Form | Draws |
|---|---|
$Plot{y(x) @ x = a : b} | A function of one variable. |
$Plot{y1(x) & y2(x) @ x = a : b} | Several functions on one plot. |
$Plot{y1(x) "name 1" & y2(x) "name 2" @ x = a : b} | The same, with a legend. |
$Plot{x(t) | y(t) @ t = a : b} | A parametric curve. |
$Plot{x1(t) | y1(t) & x2(t) | y2(t) @ t = a : b} | Several parametric curves. |
$Map{f(x; y) @ x = a : b & y = c : d} | A colour map of a surface. |
$Plot must be the first thing on its line. Anything after the closing brace is ignored. Plotting
supports real numbers only.
Size and style
Set these by assigning them on a line of their own (in a sheet, a >> line), before the plot:
L: 6
w: 12
M(x): w * x * (L - x) / 2
>> PlotWidth = 600
>> PlotHeight = 300
plot M(x) for x in 0..L
| Setting | Meaning |
|---|---|
PlotWidth, PlotHeight | Size of the plot area in pixels. |
PlotSVG | 1 for vector (SVG), 0 for raster. The web version draws SVG only. |
PlotAdaptive | 1 to concentrate sample points where the curve bends (the default). Turn it off for rapidly oscillating functions, which can lose peaks. |
PlotStep | Mesh size for colour maps. |
PlotPalette | Colour palette 0 to 9 for colour maps. |
PlotSmooth | 1 for a smooth gradient, 0 for isobands. |
PlotShadows | 1 to shade colour maps. |
PlotLightDir | Direction of the light, 0 to 7 clockwise from north. |
The same settings are on the Calculation tab of the Settings dialog, which sets the defaults for every worksheet. The Plots & Diagrams tab of the ribbon has buttons for each form and for these lines.
The buttons under a plot
In the preview, a plot has a row of small buttons. They are not part of a printout or an export.
| Plot made by | Buttons |
|---|---|
A plot line or $Plot | Copy data, PNG, SVG |
| Python (matplotlib style) | Log x, Log y, 1:1, Copy data, PNG, SVG |
| Python (3D scene) | Copy data, PNG |
Copy data puts the plotted points on the clipboard. For a plot line the data is read back
from the drawing, through the axis labels, so it is correct to about four figures. PNG and
SVG save the picture.
Plots in exports
- Word: plots are pictures. The SVG is rasterised for Word and kept beside the picture.
- Excel: a
$Plotorplotbecomes a native, editable XY chart with its data on a “Plot data” sheet. A colour map becomes a picture. - PDF: the printed page has the plot as drawn.
See Exporting.
Python plots
For interactive charts, subplots, 3D surfaces and plots of computed arrays, use a Python block. See Python blocks. For a chart that redraws while you drag a slider, see Interactive panels.
Related calculators: Moment and shear diagrams, Pump operating point, Concrete strength gain. More pages are in Calculators and guides.
Python blocks
Video: Plots from Python, Plotly and matplotlib style
A sheet can hold small Python programs. They run in the page, in a sandbox, on a compact Python interpreter (MicroPython) with small stand-ins for numpy, matplotlib and Plotly. What a block prints, draws and exports becomes part of the sheet, and the numbers it exports can be used by the quantity lines that follow.
Nothing is downloaded for a sheet without Python. The first time a sheet with a Python block is calculated, the page asks “This worksheet runs Python code” (Run Python or Not now). The answer is remembered for that tab. About 0.6 MB is fetched the first time and cached afterwards.
The block
A Python block is a fenced code block with the language python:
# Moment diagram with matplotlib
L: 6 m | span
w: 12 kN/m | design load
```python
import numpy as np
import matplotlib.pyplot as plt
L_m, w_k = 6.0, 12.0
x = np.linspace(0, L_m, 61)
M = w_k * x * (L_m - x) / 2
print("Maximum moment", round(float(M.max()), 2), "kN.m at", round(float(x[np.argmax(M)]), 2), "m")
plt.figure(figsize=(7, 3))
plt.plot(x, M, "b-", label="M(x)")
plt.fill_between(x, M, alpha=0.2)
plt.xlabel("x (m)")
plt.ylabel("M (kN.m)")
plt.title("Simply supported beam")
plt.grid(True)
plt.legend()
plt.show()
export(M_peak=float(M.max()))
```
Mmax: M_peak * 1 kN*m
Mcheck: w * L^2 / 8 -> kN*m
The result shows the printed line, the figure where plt.show() was called, and then the two
quantity lines:
Maximum moment 54.0 kN.m at 3.0 m
[figure: the parabolic moment diagram]
M_peak = 54
Mmax = M_peak · 1 kN·m = 54 · 1 kN·m = 54 kN·m
Mcheck = w·L²/8 = 12 kN/m · (6 m)² / 8 = 54 kN·m
The two numbers agree, which is the point of mixing: Python draws and explores, the sheet carries the units and the check.
| In the block | In the sheet |
|---|---|
print(...) | A monospace paragraph. |
plt.show() or plt.savefig(...) | An inline SVG figure at that point. |
fig.show() on a Plotly figure | An interactive chart at that point. |
export(name=value, ...) | A definition name = value, a vector for a list or 1-D array, a matrix for a list of lists. |
export_data(name=value, ...) | Like export but nothing is printed; for large arrays. |
| An exception | One red error line naming the Python line and the exception type. The rest of the sheet still calculates. |
Rules worth knowing:
- All blocks of a sheet run in order in one interpreter, before the engine. A later block sees the earlier blocks’ variables.
- Variables are exported explicitly, so a loop variable never collides with a unit name such
as
mors. Exported numbers are unitless; attach the unit in the sheet, asMmaxdoes above. - Names in
exportare written the way the sheet spells them:export(sigma_c=2)is σ_c below the block. - Python cannot read the sheet’s quantities. Pass numbers in by writing them in the block.
- Several names in one
exportcall arrive in no promised order. Use separate calls where order matters.
Which numpy and matplotlib
The stand-ins are small subsets that mimic those packages. What works:
- numpy:
array,linspace,arange,zeros,ones,full, arithmetic and**,@,dot,sum,mean,max,argmax,cumsum,abs,clip,maximum,where,sqrt,exp,sin,cos,diff,trapz,eye, boolean masks, and for plottinghypot,arctan2,meshgrid(indexing="xy"or"ij"),outer,interp,polyfit,polyval. - math: everything in MicroPython’s
math, plushypot,dist,prod,fsum,isqrt,comb,perm,gcdandlcm, which the page adds. - numpy.linalg and scipy.linalg:
solve,inv,det,cholesky,eigh,svd,matrix_rank,cond,pinv,norm. The numbers come from the same engine as the sheet’slsolve,inverseanddet. - matplotlib:
plot,scatter,bar,fill_between,axhline,axvline,text,xlabel,ylabel,title,legend,grid,xlim,ylim,figure(figsize),subplots,tight_layout,suptitle,axis("equal"), log axes,show,savefig.
Missing functions raise a named error rather than a wrong answer. Not available: vstack, hstack,
reshape, sort, random, poly1d, roots in numpy; hist, pie, errorbar,
step, annotate, imshow, contour, twinx in matplotlib; non-symmetric eig and lstsq in
linalg.
NotImplementedError: numpy.linalg.lstsq is not available in the light Python stand-in
A singular matrix raises LinAlgError: Matrix is singular. on the Python line that made the call.
A list written out in the source can hold up to 16,000 numbers; a longer one is refused with
an error that says what to do instead. For thousands of values, build the list in a loop or
parse a text string ([float(v) for v in "1.5 2.5 3.5".split()]), which is also much faster.
# Linear algebra in a block
```python
import numpy as np
K = np.array([[4.0, -2.0], [-2.0, 3.0]])
u = np.linalg.solve(K, np.array([10.0, 0.0]))
print("u =", [round(float(v), 4) for v in u])
export(u1=float(u[0]), u2=float(u[1]))
```
total: u1 + u2
u = [3.75, 2.5]
u1 = 3.75
u2 = 2.5
total = u1 + u2 = 3.75 + 2.5 = 6.25
Plotly-style charts
import plotly.graph_objects as go gives a small copy of the Plotly interface. A figure shown with
fig.show() becomes an interactive chart in the page: hover to read values, drag to zoom, use the
toolbar to save a picture.
# Shear and moment with Plotly
```python
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
L_m, w_k = 6.0, 12.0
x = np.linspace(0, L_m, 61)
V = w_k * (L_m / 2 - x)
M = w_k * x * (L_m - x) / 2
fig = make_subplots(rows=2, cols=1, shared_xaxes=True, subplot_titles=["Shear V (kN)", "Moment M (kN.m)"])
fig.add_trace(go.Scatter(x=x, y=V, name="V", line_color="#1f77b4"), row=1, col=1)
fig.add_trace(go.Scatter(x=x, y=M, name="M", fill="tozeroy"), row=2, col=1)
fig.add_vline(x=L_m / 2, line_dash="dot")
fig.update_layout(title="Simply supported beam", height=480, xaxis2_title="x (m)")
fig.show()
```
This is a pass-through, not a second copy of Plotly. Every keyword argument is written into the figure as given, and Plotly.js in the page checks it. Supported pieces:
| Supported | Notes |
|---|---|
go.Figure(data=, layout=, frames=) | data takes traces or dicts. |
Traces Scatter, Scattergl, Bar, Histogram, Box, Violin, Pie, Heatmap, Contour, Surface, Scatter3d, Mesh3d, Scatterpolar, Waterfall, Indicator, Table, Candlestick | The class only sets the type. All other keywords are the trace’s own. |
fig.add_trace, add_traces, add_scatter, add_bar | row and col on a figure from make_subplots. |
fig.update_layout, update_xaxes, update_yaxes, update_traces | Recursive merge. |
add_shape, add_annotation, add_vline, add_hline, add_vrect, add_hrect | With row and col, the lines use that subplot’s axes. |
make_subplots(rows, cols, shared_xaxes, shared_yaxes, subplot_titles, row_heights, column_widths, vertical_spacing, horizontal_spacing) | |
updatemenus and sliders with precomputed steps | Dropdowns, buttons, sliders; frames for animation. |
“Magic underscores” work when they are keyword arguments of a call: line_color="red" is
line=dict(color="red") and xaxis_title="x" is xaxis=dict(title="x"). Inside a dict they are
not expanded, and the shim refuses them by name rather than letting Plotly drop them silently.
Things that fail with a named error: trace types not in the table, write_html, write_image,
fig.data, fig.show(renderer=...), make_subplots(specs=...), plotly.express, plotly.io,
named templates (template="plotly_white"; the page applies a light or dark theme itself).
NotImplementedError: go.Figure.write_html is not available in the light plotly shim
Controls are Plotly’s own, and they are independent. A dropdown or slider step is a fixed update that Plotly applies; it cannot read another control or run Python. For controls that combine, precompute one step per combination or give each control its own traces. The “Beam explorer” sample shows both.
Sliders that run the Python again
For a control that runs Python again on every move, use an interactive panel:
a function decorated with @ui.panel(ui.slider("L", 6, 2, 12, unit="m")) that returns a Plotly
figure is called again each time the slider moves, and only its chart is redrawn.
Plotly offline, printing and exports
Plotly.js is not bundled. It is fetched once from its CDN when the first chart is shown, and cached. Without a connection the chart’s place shows a note: “Interactive charts need a connection to load Plotly…”. The Python solve and the rest of the sheet still run. The charts follow the page’s light or dark theme.
Print, PDF, Word and Excel cannot run Plotly.js, so they carry a still picture of the chart instead: the page makes it when the chart is drawn (light colours, without menus and sliders, at the view you left it in). A chart that was never drawn in this session (no connection) has no picture, and a paragraph stands in its place (“Interactive chart: TITLE. It is drawn in the browser and is not carried by print or export.”). Let the chart draw before you print or export.
3D plots
A Plotly Surface, Scatter3d, Mesh3d or a 3D line figure is a 3D scene you can rotate and
zoom. The contour lines can be projected onto the floor.
# A 3D surface
```python
import plotly.graph_objects as go
xs = [i * 0.25 for i in range(25)]
ys = [j * 0.25 for j in range(17)]
z = [[((x - 3) ** 2 + (y - 2) ** 2) ** 0.5 for x in xs] for y in ys]
fig = go.Figure(go.Surface(x=xs, y=ys, z=z, colorscale="Viridis"))
fig.update_layout(height=420, scene=dict(zaxis=dict(title=dict(text="distance"))))
fig.show()
```
The samples under 3D plots show a plate deflection surface, a column interaction surface, a space frame drawn in 3D lines, a mode-shape explorer with a dropdown, and a 3D bar chart of footing reactions. The walls of the 3D axes follow the light or dark theme. The buttons under a 3D scene are Copy data and PNG.
Plot gallery
The Plot gallery sample (group “Plots and diagrams”) is a gallery of four plots on a grid in the style of a plotting demo: implicit curves (f(x, y) = 0 drawn as a contour at level zero), functions, parametric curves, noise, and polylines with markers, a legend and a second y axis. It is drawn in a Python block with the Plotly API, so it can be zoomed and read by hovering.
Limits
| Limit | Value |
|---|---|
| Time per block | 10 seconds. The worker is stopped and restarted. |
| Time per calculation | 30 seconds. |
| Print output | 100,000 characters |
| Figures | 20 per sheet, 3 MB of SVG |
| Chart size | 4 MB of figure data, 20 figures and drawings together |
| Exported names | 500 |
| Interpreter memory | 32 MB |
The longer time limit. When a block runs out of its ten seconds, the page asks whether to run the sheet again with a longer limit: 60 seconds per block and 180 seconds per calculation. This is for a slow device such as a phone, which can need several times what a laptop needs. The answer is kept for the tab.
The sandbox
A block runs in a Web Worker: no page access, no cookies, no stored data. The worker’s network functions are removed after loading, so a script cannot send data anywhere, and the interpreter’s host-access modules are refused. A runaway loop or allocation is stopped by the time and memory limits.
This is a practical guard and not a security boundary against a determined attacker. Calculating a sheet executes its blocks, which is why the page asks before the first run. The Samples browser never runs a sample’s Python; its preview shows the source, and opening the sample asks.
Errors
A Python exception shows as one red line naming the sheet line and the exception type, and appears in the error list on that line. The rest of the sheet still calculates, so a failed block leaves the names it never exported undefined, and the lines that use them report their own errors.
Python error on line 5: ZeroDivisionError ...
Typical causes: a name that is not in the stand-in (a NotImplementedError naming it), a Plotly
keyword written in a dict with an underscore, an exported value that is nan or inf, or a block
that ran past its time limit.
Calcpad #python blocks
In the Calcpad language the block is #python … #end python on lines of their own, and a
sheet accepts that pair too.
Interactive panels
An interactive panel is a set of controls drawn above a chart, a table or a line of text, all made by one Python block. Move a slider and one Python function runs again with the new value, and its chart or table is redrawn in place. The rest of the sheet is not recalculated, so a panel stays quick even when the sheet is long.
The samples in the Panels group show three of them: a beam deflection explorer, a pump operating point with a play button, and a column buckling player.
Prompt-friendly summary
A complete sheet with a slider that redraws a chart:
# Moment explorer
```python
import ui
import plotly.graph_objects as go
L = ui.slider("L", 6, 2, 12, step=0.5, unit="m", label="Span")
@ui.panel(L)
def moment(L):
x = [L * i / 40 for i in range(41)]
return go.Figure(go.Scatter(x=x, y=[12 * v * (L - v) / 2 for v in x]))
```
The five rules:
- Write it in a
```pythonfence of a sheet,import ui, make the widgets withui.slider,ui.select,ui.checkboxorui.player, and decorate one function with@ui.panel(widget, ...). The function takes one argument per widget, in the same order, and receives plain values. - Return a Plotly figure (do not call
fig.show()), a string,ui.table(rows, header=[...]), or a list of these. Return the chart from the very first call too: Plotly is loaded only when the first result holds a chart. - The panel cannot read the sheet’s quantities, and the sheet cannot read the panel’s values. Put every number the panel needs in the block itself.
- The Python is a small stand-in for numpy:
reshape,vstack,hstackandsortare not there (meshgridandmath.hypotare). Build large lists with a loop or a comprehension: a list literal of more than 16,000 numbers in the code is refused. - Do the heavy work once in the block body and keep the panel function light: it runs on every move of a control.
A panel, a sheet slider or an input form
There are three ways to put a slider in front of a reader. Choose by what has to change.
| You want | Use | What a move does |
|---|---|---|
| A chart, table or text redrawn live while dragging | An interactive panel | Runs one Python function again. Nothing else is recalculated. |
A sheet input with a slider, L: ? 6 m [2 .. 12 step 0.5] | Templates with inputs | Recalculates the whole sheet with the new value, a moment after you stop. |
| A fill-in form of several inputs | Input mode, see Templates with inputs | Recalculates the whole sheet; every quantity line follows. |
A sheet slider changes a quantity that the lines below use, with its unit, and the report shows the working. A panel is for exploring: the chart follows your finger, but its numbers stay inside the panel.
The first run
A panel is part of a Python block, so the first calculation of the sheet in a tab asks “This worksheet runs Python code” with Run Python and Not now. The block runs in a sandbox in the page, see Python blocks. The first run takes several seconds while Python starts and, for a chart, while Plotly loads from its CDN; after that a move of a control usually redraws in a fraction of a second.
A chart: the beam moment
# Beam moment explorer
```python
import ui
import plotly.graph_objects as go
L = ui.slider("L", 6, 2, 12, step=0.5, unit="m", label="Span")
w = ui.slider("w", 12, 1, 40, unit="kN/m", label="Load")
@ui.panel(L, w)
def moment(L, w):
x = [L * i / 60 for i in range(61)]
M = [w * v * (L - v) / 2 for v in x]
fig = go.Figure(go.Scatter(x=x, y=M, mode="lines", fill="tozeroy", name="M"))
fig.update_layout(height=320, xaxis_title="x (m)", yaxis_title="M (kN.m)")
return [fig, "Maximum moment %.1f kN.m at midspan" % (w * L * L / 8)]
```
The page shows two sliders, Span and Load, each with its value and unit beside it, then the chart
and the line of text. At the start it reads Maximum moment 54.0 kN.m at midspan. Drag Span to
10 m and the curve and the text follow: Maximum moment 150.0 kN.m at midspan.
What happens, in order:
- The block runs once, top to bottom, like any Python block.
- At
@ui.panel(L, w)the functionmomentis called with the starting values, 6 and 12, and its result is drawn under the controls. - Each move of a control calls
momentagain with the new values, in the same Python session, and only the panel is redrawn. The function’s name,moment, is the panel’s name.
A 3D surface
A 3D trace works the same way. Here one slider sets the amplitude of a surface:
# Surface explorer
```python
import ui
import math
import plotly.graph_objects as go
a = ui.slider("a", 1.0, 0.2, 3.0, step=0.1, label="Amplitude")
xs = [-3 + 0.2 * i for i in range(31)]
@ui.panel(a)
def surface(a):
Z = [[a * math.sin(x) * math.cos(y) for x in xs] for y in xs]
fig = go.Figure(go.Surface(x=xs, y=xs, z=Z))
fig.update_layout(height=420, scene=dict(zaxis=dict(range=[-3, 3])))
return fig
```
The grid xs is made once, in the block body. The fixed zaxis range keeps the box the same size
while the surface grows and shrinks; without it, Plotly rescales the axis on every move. A rotated
view is kept when the surface is redrawn.
A table, a drop-down and a checkbox
A panel does not need a chart. This one returns only a table:
# Timber joist spans
```python
import ui
d = ui.select("d", [("200 mm", 0.2), ("300 mm", 0.3), ("400 mm", 0.4)], default="300 mm", label="Depth")
b = ui.slider("b", 90, 45, 200, step=5, unit="mm", label="Width")
sw = ui.checkbox("sw", True, label="Include own weight")
@ui.panel(d, b, sw)
def spans(d, b, sw):
Z = b / 1000 * d * d / 6
g = 5.0 * b / 1000 * d if sw else 0.0
rows = []
for L in [3, 4, 5, 6]:
M = (2.0 + g) * L * L / 8
rows.append([L, "%.2f" % M, "%.1f" % (M / Z / 1000)])
return ui.table(rows, header=["Span (m)", "M (kN.m)", "Stress (MPa)"])
```
The drop-down shows the labels (200 mm, …) and the function receives the value paired with the
chosen label (0.3). The checkbox gives True or False. A table without a chart never loads
Plotly, so it also works offline once the page has been visited.
A player
ui.player is a frame number with a Play and Pause button. Each frame is one call of the
function, and the next frame is asked for only after the last one is drawn, so a slow function plays
slower rather than piling up.
# Travelling wave
```python
import ui
import math
import plotly.graph_objects as go
t = ui.player("t", 0, 39, fps=8, label="Frame")
xs = [i * 0.1 for i in range(101)]
@ui.panel(t)
def wave(t):
y = [math.sin(x - t * 0.3) for x in xs]
fig = go.Figure(go.Scatter(x=xs, y=y, mode="lines"))
fig.update_layout(height=260, yaxis_range=[-1.2, 1.2])
return fig
```
A player never starts by itself, and it pauses when the browser tab is hidden. With loop=False it
stops at the last frame.
The ui reference
| Call | Draws | The function receives |
|---|---|---|
ui.slider(name, default, min, max, step=None, unit="", label=None) | A slider with its value and unit beside it | A number between min and max, on a step. An int when default, min, max and step are all whole numbers, otherwise a float. |
ui.select(name, options, default=None, label=None) | A drop-down | The value of the chosen option |
ui.checkbox(name, default=False, label=None) | A checkbox | True or False |
ui.player(name, start, stop, fps=5, loop=True, label=None) | A slider with Play and Pause | A whole frame number from start to stop |
@ui.panel(widget, ...) | The controls, then the function’s result | (a decorator) |
ui.table(rows, header=None) | A table | (a return value) |
ui.text(s) | A line of plain text | (a return value) |
Details that matter:
- name is the first argument of every widget. It must be unique within a panel. label is what the reader sees; it defaults to the name.
- step: without one, a slider of whole numbers moves by 1, and any other slider takes a round
step that gives 100 to 200 steps across its range. A value is always kept between
minandmaxand snapped to a step. - unit is only shown beside the value. The function receives a plain number, so write the
conversions yourself (
w * 1000for kN/m to N/m). - options of
ui.selectis a list of labels (["Steel", "Timber"], the value is the label itself) or of(label, value)pairs. Adictworks, but its order is not promised.defaultis a label or a value; without it the first option is chosen. A select needs two options or more. - fps of a player is at most 30. A frame waits for the last one, so the real rate can be lower.
- Return values: a Plotly figure from
plotly.graph_objects, astrorui.text(...)(always shown as text, never as HTML), a number,ui.table(...), or a list of these in the order they are drawn.Nonedraws nothing. Anything else is aTypeErrorthat names the type. - Numbers in a
ui.tableare written with six significant digits. Format them yourself ("%.2f" % M) to fix the decimals.
Several outputs, several panels
To drive two charts with the same slider, return both from one function: return [fig1, fig2].
A block can hold several panels, each with its own @ui.panel and its own controls. A widget given
to two panels is drawn in each of them, and the two copies do not move together. Moving one control
reruns only its own panel’s function.
Errors
- An error during the first call is a normal Python error: one red line naming the sheet line.
- An error after a move (a division by zero at one end of a slider, say) is shown in the panel, with its type. The panel recovers at the next value that works.
- A function that runs for more than 10 seconds is stopped. The panel says so, and it stays out of date until the sheet is calculated again (edit any line, or press calculate).
print()inside the panel function shows only on the first call. Return a string to show text that follows the controls.
Printing and exports
Print, PDF, Word and Excel cannot run Python. They show the panel at the values the controls were left at, without the controls, and a note under it, for example: “Interactive panel moment: Span = 10 m, Load = 12 kN/m. It is drawn in the browser; print and export show it at these values.” Text and tables are carried as they are. A chart is carried as a note naming it, as for any Plotly chart.
The values the controls were left at are kept while the tab is open, so a recalculation (an edit elsewhere in the sheet) starts the panel where you left it. They are not saved in the file: opening the file again starts from the defaults.
Limits
A panel cannot read the sheet, and the sheet cannot read the panel. Python runs before the
sheet’s quantity lines and cannot see them, and a slider’s value never reaches a quantity line.
A panel therefore holds its own data and inputs: write the section properties, loads and lengths
in the block. An export() from the block body works as in any block, but it is done once, before
any control moves; do not call export() in a panel function. When a value has to drive the
sheet’s calculation, use a sheet input instead (L: ? 6 m [2 .. 12 step 0.5]).
The numpy stand-in is small. The block runs on MicroPython with a light stand-in for numpy, not on full Python. The list of what works is in Which numpy and matplotlib. Things that surprise people:
numpy.reshape,vstack,hstackandsortraiseNotImplementedError.numpy.meshgrid,hypot,arctan2,outer,interp,polyfitandpolyvalwork, as doesmath.hypot.- A list literal of more than 16,000 numbers written out in the code is refused before it runs, with a hint to build the list in a loop or parse a text string. Shorter ones, even several thousand numbers, work.
np.linspaceand array arithmetic work, but plain lists and comprehensions are just as quick for the sizes a chart needs.
It runs only in the browser. The MCP server does not run Python blocks, so it cannot evaluate a sheet with a panel. Word and Excel get the snapshot described above.
Plotly comes from its CDN. A chart needs a connection the first time (the controls, tables and text work without one). Plotly is loaded only when the first result of a panel holds a chart, so a panel that returns a chart only after some move shows a note instead of the chart. Return a chart on the first call too.
The usual Python limits apply: 10 seconds per call, and an answer of at most 2 MB (a figure and its data) per move. See Python blocks.
Keeping it fast
The function runs on every move of a control, so keep in it only what depends on the controls. Work that does not, such as a grid, a stiffness matrix or a solved model, belongs in the block body, which runs once. The function can read the variables the block made before it.
# Precomputed surface
```python
import ui
import math
import plotly.graph_objects as go
xs = [-3 + 0.1 * i for i in range(61)]
base = [[math.sin(x) * math.cos(y) for x in xs] for y in xs]
k = ui.slider("k", 1.0, 0.1, 2.0, step=0.1, label="Scale")
@ui.panel(k)
def scaled(k):
Z = [[k * v for v in row] for row in base]
fig = go.Figure(go.Surface(x=xs, y=xs, z=Z))
fig.update_layout(height=420, scene=dict(zaxis=dict(range=[-2, 2])))
return fig
```
The sines and cosines of the 61 by 61 grid are worked out once; each move only multiplies.
- Keep charts to a few thousand points. The whole figure is sent on every move.
- Do not change globals in the function. A function that depends only on its arguments and on what the block computed before it gives the same picture for the same control values, whatever order the reader moved them in.
- Fix axis ranges (
yaxis_range,scene=dict(zaxis=dict(range=...))) so the chart does not jump while dragging.
Templates with inputs
Video: Templates with inputs
A template is a calculation that you fill in rather than edit. A few lines of the sheet are inputs: a number with its unit, a choice from a list, a group of radio buttons, a checkbox. Choose Input in the results bar and those lines become boxes, lists, buttons and ticks. Change one and the whole sheet recalculates. The same file is still an ordinary sheet: in Preview and in the report an input line reads like any other line.
A template is one .sheet file. There is nothing to install and nothing to configure: the inputs
are lines of text in the sheet.
An input is a line with a question mark
A quantity line gives a name a value: L: 6 m | span. Put a ? in front of the value and the
same line becomes an input, with that value as its default:
# Beam moment
L: ? 6 m | span
w: ? 12 kN/m | design load
M: w * L^2 / 8 -> kN*m | maximum moment
Everything else about the line is as for a quantity: the name is a plain name (Greek spellings
work as usual), the unit is written after the number, and the text after | is a note. Later
lines use L and w like any other quantity. In Preview the sheet reads L = 6 m span, with
the defaults. In Input mode 6 is a yellow box with m beside it and span after it. Change the
box to 8, press Enter, and the moment follows.
The default is a number with an optional unit (6 m, 12 kN/m, 0.9, 1230000 mm³). It is not
an expression: 2*3 m is an error on its line, and the message says what to write. Units may be
written with the superscript signs (mm³) as everywhere else in a sheet. The name can be written
either way too: phi: ? 0.9 is the input φ.
name = ? 6 m works as well as name: ? 6 m.
The kinds of input
| You write | You get | The name is |
|---|---|---|
L: ? 6 m | span | A box with the unit after it | The number typed, with the unit |
E: ? [Steel = 200 GPa, *Timber = 11 GPa] | material | A drop-down list | The value of the chosen option |
k: ? (Low = 1, High = 2) | load class | Radio buttons | The value of the chosen option |
ribs: ? on | stiffeners fitted | A checkbox | 1 when ticked, 0 when not |
L: ? 6 m [2 .. 12 step 0.5] | span | A slider with the box beside it | The number, kept between the bounds |
Sliders
Put bounds after the default and the box gets a slider:
# Beam moment
L: ? 6 m [2 .. 12 step 0.5] | span
w: ? 12 kN/m [2 .. 40 step 1] | design load
M: w * L^2 / 8 -> kN*m | maximum moment
[2 .. 12 step 0.5] is the smallest value, the largest value and, if you give one, the step the slider moves
in. The numbers are in the unit of the default (metres for 6 m). The default must lie between the bounds.
In Input mode the slider sits next to the box: drag it, use the arrow keys, or type a number, and the sheet
recalculates a moment after you stop moving. A number typed outside the bounds is not used; the box turns red
and says must be from 2 to 12. Without step the slider takes about a hundred steps across its range; a typed
number does not have to land on a step. Preview, Report, PDF and the Word and Excel exports show the number, as
they do for a plain input, so a sheet with sliders reads the same when it is printed. Two of the sample
templates, the beam check and the cantilever, use sliders for their span, length and loads.
Docked inputs
A slider is most use when you can see what it moves. In Input mode the Dock inputs button (a pin) in the results bar gathers every input of the sheet into one panel that stays put while the results scroll: at the left of the results when the pane is wide, in a strip above them when it is narrow or on a phone. Scroll the results to the plot, drag a slider in the panel, and the plot is drawn again as you drag. The panel holds the same values as the input lines (they are hidden while it is docked), with the same checks: a number typed outside the bounds is refused, with the message beside the box. The arrow in the panel’s header folds it to one line of values.
The panel is docked when a sheet has a slider, and not otherwise; your choice is kept until the browser tab is closed. A sheet without inputs has no panel. Nothing printed or exported shows it.
Drop-downs and radio buttons
A choice is a list of label = value entries between square brackets (a drop-down) or round
brackets (radio buttons). The label is what the reader sees. The value is a number with an
optional unit, and it is what the name becomes when that option is chosen.
- The option marked with
*is the one selected when the sheet opens. With no*, the first option is. - A label that contains a comma, an equals sign or a bracket goes in double quotes:
"Beam (A), long" = 1. - A choice needs at least two options, and each option needs a value.
- A drop-down, radio buttons and a checkbox show no name. Their note (the text after
|) becomes the label in front of the control. With no note the name is used.
Checkboxes
on or off (true and false also work) sets the starting state, and the name is 1 or 0.
That makes it a multiplier (sw * rho * A) or a test (if ribs == 1:).
A choice that picks several things at once
A choice gives one number. When a material has a modulus, a strength and a density, let the
choice give an index and look the rest up in tables written after it. The template below does this
with E_tab.mat, the entry of E_tab that mat points at:
mat: ? [Structural steel = 1, *Aluminium = 2, Timber = 3] | material
E_tab: [200 GPa, 70 GPa, 11 GPa] | modulus of elasticity
E: E_tab.mat -> GPa
if mat == 2: "The material is aluminium."
A new material is then one more option and one more entry in each table. The report shows the
number a choice stands for (mat = 3), so a line such as if mat == 3: "The material is timber."
tells the reader what it means. Most of the sample templates do this.
Grouping the inputs as a form
A run of input lines is drawn as one form: a block with a bar down its left edge. Put the inputs together under a heading, so that the heading titles the form. The run ends at the first line that is not an input (a line of prose, a calculation). A blank line inside the run does not end it.
## Inputs
L: ? 6 m | span
w: ? 12 kN/m | applied uniform load
mat: ? [Structural steel = 1, Aluminium = 2, Timber = 3] | material
sw: ? on | include the own weight of the beam
Preview and the report show the same block without the bar, and Show compiled shows plain Calcpad (the bar is not written). Format Document (Shift+Alt+F) lines the colons up.
Using the form
In the browser a template opens as Preview. Choose Input in the results bar (Preview, Unwrapped, Input, Report), or Input form on the Input/Output tab. Then:
- Each input line is a control. A box holds the number only; the unit stays beside it, so a number cannot be typed in the wrong unit. A box accepts digits, a decimal point and a sign.
- Consecutive input lines are drawn as one block, so the names, the boxes, the sliders, the units and the notes start at the same place on every row. The names are right aligned so the equals signs meet, a very long name is held to 40% of the width and wraps, and a text line, a heading or a blank line starts a new block. This is how the form looks only; the report, print and the exports are unchanged. (The docked panel, described above, is laid out on its own.)
- Type a value and press Enter, or leave the box, and the sheet recalculates. Lists, buttons and the checkbox act at once.
- The Insert panel says “Unavailable in input mode”: it acts on the source, which the form does not edit. Choose Preview to edit again.
- The bar has Report and Print PDF, which use the values you entered, Update defaults and Reset (they appear once you have entered a value), Save values (it appears once you have changed a value) and Exit input mode.
- Leaving input mode with values you did not save asks “Unsaved input values: save the values entered in the input form before exiting?” with Save, Don’t Save and Cancel.
| View | Entered values applied | #pre shown | #post shown |
|---|---|---|---|
| Preview | No (the defaults), unless Apply #UI Values in Preview is on in Settings | Yes | Yes |
| Input | Yes | Yes | No |
| Report | Yes | No | Yes |
The Word and Excel exports and Print PDF use the entered values. The Excel file lists the input variables on its Inputs sheet. The form itself has no Word export; the report is the document. See Exporting.
Saving the values
The values you type are held in the page, so typing never changes the file. Choose Save values
to keep them. It writes one comment line directly under the <!--sheet--> line:
<!--sheet-->
'<!--{"uiOverrides":{"L:1":"8"}}-->
The file is still a sheet. The next time it is opened and put in Input mode, or opened as a report, the saved values are applied again. Preview still shows the defaults written in the sheet. To change a default for good, edit the number in the sheet line.
A saved value belongs to the input’s name. Rename an input and the value saved under the old name is not used any more. Delete the comment line to go back to the defaults.
Keeping the source and the form the same
A value held in the form and the default written in the sheet can differ, and then the report uses one number while the source shows another. Three things deal with that:
- A mark at the end of the line. An input line whose entered value is not its default shows a faint
← form: 8after it in the editor, with the explanation when you point at it. It appears for held values and for saved ones, in Preview and in the editor too. - Update defaults (in the results bar) writes every entered value into the default of its line and forgets the
value:
L: ? 6 m | spanbecomesL: ? 8 m | span, a drop-down or a group of radio buttons moves its*to the chosen option, a checkbox becomesonoroff, and a slider keeps its bounds. A saved comment line is rewritten without the values that were written, and removed when none is left. The edit is one step of undo in the editor. A value that has no line to go to, such as one entered for a later pass of a#forloop, stays as entered. - Reset drops the entered values, held and saved, and the form shows the defaults in the source again.
To have the source always show what the calculation uses, turn on Keep Input Form Values in the Source in Settings (Editor tab). A value you enter is then written into its line at once instead of being held: there is nothing to save and no mark to see. A slider writes when you let go of it. The setting is off by default, because a sheet kept as a template with defaults for others to fill in is easier to hand over when the form never changes it.
What an input cannot do
- Numbers only. An input holds a number. There is no text box: a choice of names is a
drop-down. There is no minimum or maximum either, so check a range in the sheet:
if L > 30 m: "Span out of range". - No expression as a default.
2*3 mis an error. Write the number, or compute the value in a line after the input.
Known limits
Workarounds for behaviour that is to be fixed. This is the only list of them on this page.
- No two options may have the same value.
(Low = 1 m, High = 1 m)is an error on its line, because the form could not tell which option is chosen. Give each option its own value. - A name cannot contain a dot. A dot is the index operator (
E_tab.mat), soa.b: ? 5is not an input.
Worked template 1: a simply supported beam
Inputs: the span, the load, a section depth (drop-down), a material (drop-down), a deflection limit (radio buttons) and whether the beam’s own weight counts (checkbox). The beam is a doubly symmetric I-beam described by one depth, so the section is a drop-down of three depths. This is the sample Template: simply supported beam check in the Templates group of the Samples browser, and the text below is the file as shipped.
The inputs, six lines:
## Inputs
L: ? 6 m | span
w: ? 12 kN/m | applied uniform load
h: ? [200 mm deep = 200 mm, *300 mm deep = 300 mm, 400 mm deep = 400 mm] | I-beam section
mat: ? [Structural steel = 1, Aluminium = 2, Timber = 3] | material
limit: ? (L/250 = 250, L/360 = 360, L/500 = 500) | deflection limit
sw: ? on | include the own weight of the beam
Note that h is a drop-down whose values are lengths: the choice sets the section depth directly.
The deflection limit is a number, 250, 360 or 500, and a later line divides the span by it
(L / limit).
The whole sheet
<!--sheet-->
# Simply supported beam check
A template with inputs. Choose **Input** in the results bar to fill in the form; every change
recalculates the page. The beam is a doubly symmetric I-beam, so one depth $h$ describes it:
flange width $b = h/2$, flange thickness $t_f = h/20$ and web thickness $t_w = h/40$. The check
compares the bending stress $\sigma = M/Z$ with an allowable stress and the mid-span deflection
$\delta = 5 w L^4 / (384 E I)$ with a limit.
## Inputs
L: ? 6 m [2 .. 12 step 0.5] | span
w: ? 12 kN/m [2 .. 40 step 1] | applied uniform load
h: ? [200 mm deep = 200 mm, *300 mm deep = 300 mm, 400 mm deep = 400 mm] | I-beam section
mat: ? [Structural steel = 1, Aluminium = 2, Timber = 3] | material
limit: ? (L/250 = 250, L/360 = 360, L/500 = 500) | deflection limit
sw: ? on | include the own weight of the beam
## Material properties
The input above picks one entry of each table, so a new material is one more entry in each.
E_tab: [200 GPa, 70 GPa, 11 GPa] | modulus of elasticity
fa_tab: [165 MPa, 100 MPa, 12 MPa] | allowable bending stress
rho_tab: [7850 kg/m^3, 2700 kg/m^3, 500 kg/m^3] | density
E: E_tab.mat -> GPa
f_a: fa_tab.mat -> MPa
rho: rho_tab.mat -> kg/m^3
if mat == 1: "The material is structural steel."
if mat == 2: "The material is aluminium."
if mat == 3: "The material is timber."
## Section
b: h / 2 | flange width
t_f: h / 20 | flange thickness
t_w: h / 40 | web thickness
A: 2 * b * t_f + (h - 2 * t_f) * t_w -> cm^2 | area
I: (b * h^3 - (b - t_w) * (h - 2 * t_f)^3) / 12 -> cm^4 | second moment of area
Z: 2 * I / h -> cm^3 | elastic section modulus
## Load
g_acc: 9.81 m/s^2 | gravitational acceleration
w_sw: sw * rho * A * g_acc -> kN/m | own weight, when included
w_tot: w + w_sw | total uniform load
## Results
M_max: w_tot * L^2 / 8 -> kN*m | maximum bending moment, at mid-span
V_max: w_tot * L / 2 -> kN | maximum shear force, at the supports
sigma: M_max / Z -> MPa | maximum bending stress
delta: 5 * w_tot * L^4 / (384 * E * I) -> mm | mid-span deflection
delta_lim: L / limit -> mm | deflection limit
util_b: sigma / f_a | bending utilisation
util_d: delta / delta_lim | deflection utilisation
if util_b <= 1: "Bending: OK, the stress is within the allowable stress." else: "Bending: the stress exceeds the allowable stress, choose a deeper section or a stronger material."
if util_d <= 1: "Deflection: OK, within the limit." else: "Deflection: over the limit, choose a deeper section or a stiffer material."
## Moment diagram
M(x): w_tot * x * (L - x) / 2 -> kN*m | bending moment along the span
plot M(x * 1 m) / (1 kN*m) for x in 0..L / (1 m)
At the defaults (6 m, 12 kN/m, 300 mm deep, steel, L/250, own weight on):
| Quantity | Result |
|---|---|
Own weight w_sw and total load w_tot | 0.502 kN/m and 12.5 kN/m |
Section A, I, Z | 65.25 cm², 10376.4 cm⁴, 691.76 cm³ |
Moment M_max, shear V_max | 56.26 kN·m, 37.51 kN |
Stress σ against f_a | 81.33 MPa against 165 MPa, utilisation 0.493 |
Deflection δ against δ_lim | 10.17 mm against 24 mm, utilisation 0.424 |
| Messages | Bending: OK. Deflection: OK. |
What changing each input does (one change at a time from the defaults, unless the row says otherwise):
| Change | Result |
|---|---|
| Span 8 m | Moment 100.02 kN·m, stress 144.59 MPa (0.876), deflection 32.13 mm against a 32 mm limit. Bending: OK. Deflection: over the limit. |
| Span 8 m and 400 mm deep | Total load 12.89 kN/m, moment 103.15 kN·m, stress 62.9 MPa (0.381), deflection 10.48 mm (0.328). Both OK. |
| Timber | Moment 54.14 kN·m, stress 78.27 MPa against 12 MPa (6.52), deflection 177.89 mm (7.41). Both fail. |
| Limit L/500 and own weight off | Moment 54 kN·m, stress 78.06 MPa (0.473), deflection 9.76 mm against 12 mm (0.813). Both OK. |
The first row shows a deflection utilisation of 1 next to the message “over the limit”. The
value is 1.004, and two decimals show it as 1. The message tests the full number, not the
rounded one. For a closer look, raise the decimals in Settings.
The own-weight checkbox is a multiplier: w_sw: sw * rho * A * g_acc. With the box ticked it is
0.502 kN/m, unticked it is 0 and the total load is the applied load alone.
Worked template 2: a pad footing under a load and a moment
Eight inputs: the column load and moment, the footing’s width, length and thickness, the depth of its base, a soil (a drop-down of allowable bearing pressures) and a checkbox for the weight of the footing and the soil above it. This is Template: pad footing bearing pressure.
The whole sheet
<!--sheet-->
# Pad footing: bearing pressure check
A template with inputs. Choose **Input** in the results bar to fill in the form. A rectangular
pad footing $B \times L$ carries a vertical column load $N$ and a moment $M$ about the axis
parallel to $B$. The total vertical load $P$ adds the weight of the footing and of the soil above
it, the eccentricity is $e = M/P$ and, while $e \le L/6$ (no uplift), the largest bearing pressure is
$q_{max} = \frac{P}{B L}\left(1 + \frac{6e}{L}\right)$. Beyond that the pressure acts on part of the
base only, $q_{max} = \frac{2P}{3B(L/2 - e)}$. It is compared with an allowable bearing pressure.
## Inputs
N: ? 600 kN | vertical column load
M: ? 60 kN*m | column moment, in the direction of L
B: ? 2 m | footing width
L: ? 2.4 m | footing length, in the direction of the moment
t: ? 0.5 m | footing thickness
D_f: ? 1 m | depth of the base below the ground
q_a: ? [Soft clay = 80 kPa, Firm clay = 150 kPa, *Medium dense sand = 200 kPa, Dense gravel = 300 kPa] | soil, allowable bearing pressure
wts: ? on | include the weight of the footing and of the soil above it
## Constants
gamma_c: 24 kN/m^3 | unit weight of concrete
gamma_s: 18 kN/m^3 | unit weight of the soil above the footing
## Vertical load
W_f: wts * gamma_c * B * L * t -> kN | weight of the footing
W_s: wts * gamma_s * B * L * (D_f - t) -> kN | weight of the soil above the footing
P: N + W_f + W_s -> kN | total vertical load on the soil
## Bearing pressure
e: M / P -> m | eccentricity of the load
e_lim: L / 6 | the load stays inside the middle third while e is below this
q_avg: P / (B * L) -> kPa | average pressure
if e <= e_lim:
q_max: q_avg * (1 + 6 * e / L) -> kPa | largest pressure
q_min: q_avg * (1 - 6 * e / L) -> kPa | smallest pressure
The whole base stays in contact with the soil.
else:
q_max: 2 * P / (3 * B * (L / 2 - e)) -> kPa | largest pressure, partial contact
q_min: 0 kPa | smallest pressure
Part of the base lifts off the soil.
util: q_max / q_a | utilisation of the allowable bearing pressure
if util <= 1: "OK: the largest pressure is within the allowable bearing pressure." else: "Fails: the largest pressure exceeds the allowable bearing pressure. Enlarge the footing."
Two things in this sheet are new. The soil drop-down has an option marked *:
q_a: ? [Soft clay = 80 kPa, Firm clay = 150 kPa, *Medium dense sand = 200 kPa, Dense gravel = 300 kPa] | soil, allowable bearing pressure
so it opens on Medium dense sand, the third option. And the check has two branches. An if block
may hold quantity lines and prose, and the branch that applies is the one shown:
if e <= e_lim:
q_max: q_avg * (1 + 6 * e / L) -> kPa | largest pressure
...
The whole base stays in contact with the soil.
else:
q_max: 2 * P / (3 * B * (L / 2 - e)) -> kPa | largest pressure, partial contact
...
Part of the base lifts off the soil.
At the defaults (600 kN, 60 kN·m, 2 m by 2.4 m, 0.5 m thick, base 1 m down, medium dense sand, weights on):
| Quantity | Result |
|---|---|
Footing weight W_f, soil weight W_s | 57.6 kN, 43.2 kN |
Total vertical load P | 700.8 kN |
Eccentricity e against e_lim | 0.0856 m against 0.4 m, so the whole base is in contact |
| Average, largest, smallest pressure | 146 kPa, 177.25 kPa, 114.75 kPa |
| Utilisation | 0.886. OK. |
| Change | Result |
|---|---|
| Soft clay | Largest pressure unchanged, 177.25 kPa against 80 kPa: utilisation 2.22. Fails. |
| Moment 200 kN·m | e 0.285 m, largest 250.17 kPa, smallest 41.83 kPa, utilisation 1.25. Fails. |
| Moment 400 kN·m | e 0.571 m is beyond 0.4 m: “Part of the base lifts off the soil.” Largest 371.25 kPa, smallest 0 kPa, utilisation 1.86. Fails. |
| Weights off (checkbox) | P is 600 kN, e 0.1 m, largest 156.25 kPa, utilisation 0.781. OK. |
Worked template 3: a rectangular column
Seven inputs: the section, the length, the end conditions (a drop-down whose values are the effective length factors), a material (drop-down), the axial load and a factor of safety. This is Template: rectangular column slenderness. The sheet picks the buckling formula by slenderness: a short column crushes, an intermediate one uses the parabolic formula, a slender one the Euler formula.
Here one choice is the number the sheet needs, with no table in between:
k: ? [Pinned at both ends = 1, Fixed and pinned = 0.7, Fixed at both ends = 0.5, Fixed and free = 2] | end conditions
The whole sheet
<!--sheet-->
# Rectangular column: slenderness and buckling
A template with inputs. Choose **Input** in the results bar to fill in the form. A solid
rectangular column of length $L$ with an effective length factor $k$ has a slenderness
$\lambda = k L / r$, where $r = b_{min}/\sqrt{12}$ is the smallest radius of gyration. Above the
transition slenderness $\lambda_c = \pi \sqrt{2E/f_y}$ the column buckles elastically (Euler),
$\sigma_{cr} = \pi^2 E / \lambda^2$. Below it the parabolic (Johnson) formula applies,
$\sigma_{cr} = f_y \left(1 - f_y \lambda^2 / (4 \pi^2 E)\right)$. The load that is allowed is
$\sigma_{cr} A$ divided by a factor of safety.
## Inputs
b: ? 60 mm | section width
d: ? 100 mm | section depth
L: ? 2.4 m | column length
k: ? [Pinned at both ends = 1, Fixed and pinned = 0.7, Fixed at both ends = 0.5, Fixed and free = 2] | end conditions
mat: ? [Structural steel = 1, Aluminium = 2, Timber = 3] | material
N: ? 100 kN | axial load
FS: ? 2 | factor of safety
## Material properties
E_tab: [200 GPa, 70 GPa, 11 GPa] | modulus of elasticity
fy_tab: [250 MPa, 160 MPa, 24 MPa] | yield strength, or crushing strength for timber
E: E_tab.mat -> GPa
f_y: fy_tab.mat -> MPa
if mat == 1: "The material is structural steel."
if mat == 2: "The material is aluminium."
if mat == 3: "The material is timber."
## Section
A: b * d -> cm^2 | area
b_min: min(b, d) | smaller side
I_min: max(b, d) * b_min^3 / 12 -> cm^4 | smaller second moment of area
r: b_min / sqrt(12) -> mm | smallest radius of gyration
## Slenderness
L_e: k * L -> m | effective length
lambda: L_e / r | slenderness ratio
lambda_c: π * sqrt(2 * E / f_y) | transition slenderness
if lambda <= 50:
The column is short: crushing is likely to govern rather than buckling.
else if lambda <= lambda_c:
The column is intermediate: it buckles inelastically and the parabolic formula applies.
else:
The column is slender: it buckles elastically and the Euler formula applies.
## Buckling resistance
sigma_E: π^2 * E / lambda^2 -> MPa | elastic (Euler) buckling stress
P_E: π^2 * E * I_min / L_e^2 -> kN | elastic (Euler) buckling load
if lambda <= lambda_c:
sigma_cr: f_y * (1 - f_y * lambda^2 / (4 * π^2 * E)) -> MPa | critical stress, parabolic formula
else:
sigma_cr: sigma_E | critical stress, Euler formula
P_cr: sigma_cr * A -> kN | critical load
P_allow: P_cr / FS -> kN | allowed load
util: N / P_allow | utilisation
if util <= 1: "OK: the applied load is within the allowed load." else: "Fails: the applied load exceeds the allowed load. Enlarge the section, shorten the column or fix its ends."
At the defaults (60 mm by 100 mm, 2.4 m, pinned at both ends, steel, 100 kN, factor of safety 2):
| Quantity | Result |
|---|---|
| Area, smaller second moment, radius of gyration | 60 cm², 180 cm⁴, 17.32 mm |
Effective length L_e | 2.4 m |
Slenderness λ against λ_c | 138.56 against 125.66: “The column is slender” |
| Critical stress (Euler) and load | 102.81 MPa, 616.85 kN |
| Allowed load | 308.43 kN |
| Utilisation | 0.324. OK. |
| Change | Result |
|---|---|
| Fixed at both ends | L_e 1.2 m, λ 69.28: “The column is intermediate”, parabolic formula, critical stress 212 MPa, allowed load 636.01 kN, utilisation 0.157. |
| Fixed at both ends and 300 kN | Utilisation 0.472. OK. |
| Timber | λ_c drops to 95.12, still slender, critical stress 5.65 MPa, allowed load 16.96 kN, utilisation 5.9. Fails. |
Worked template 4: pipe flow
Eight inputs, with a flow rate in L/s, a pipe diameter and length, a rise in level, a sum of loss coefficients, a pipe material (a drop-down of roughnesses in mm), a water temperature (radio buttons that pick table entries) and a checkbox for the fittings. This is Template: pipe flow, Darcy-Weisbach. The flow is laminar or turbulent by its Reynolds number, and the sheet uses the matching friction factor.
The whole sheet
<!--sheet-->
# Pipe flow: friction loss and pump head
A template with inputs. Choose **Input** in the results bar to fill in the form. Water flows
through a full circular pipe of diameter $D$ and length $L_p$. The Darcy-Weisbach equation gives the
friction head loss $h_f = f \frac{L_p}{D}\frac{V^2}{2g}$. The friction factor is $f = 64/Re$ in laminar
flow and, in turbulent flow, the explicit Swamee-Jain formula
$f = 0.25 / \left[\log_{10}\left(\frac{\varepsilon}{3.7 D} + \frac{5.74}{Re^{0.9}}\right)\right]^2$.
Fittings add $h_m = K V^2 / 2g$.
## Inputs
Q: ? 25 L/s | flow rate
D: ? 150 mm | inside diameter of the pipe
L_p: ? 300 m | pipe length
dz: ? 5 m | rise in level from the inlet to the outlet
K_m: ? 2.5 | sum of the loss coefficients of the fittings
eps: ? [Drawn plastic = 0.0015 mm, *Commercial steel = 0.045 mm, Cast iron = 0.26 mm, Concrete = 1 mm] | pipe material, roughness
temp: ? (5 degrees C = 1, 20 degrees C = 2, 40 degrees C = 3) | water temperature
minor: ? on | include the fittings
## Water properties
rho_tab: [1000 kg/m^3, 998 kg/m^3, 992 kg/m^3] | density at 5, 20 and 40 degrees C
nu_tab: [0.00000152 m^2/s, 0.00000100 m^2/s, 0.00000066 m^2/s] | kinematic viscosity at 5, 20 and 40 degrees C
rho: rho_tab.temp -> kg/m^3
nu: nu_tab.temp -> m^2/s
g_acc: 9.81 m/s^2 | gravitational acceleration
if temp == 1: "The water is at 5 degrees C."
if temp == 2: "The water is at 20 degrees C."
if temp == 3: "The water is at 40 degrees C."
## Flow
A: π * D^2 / 4 -> cm^2 | flow area
V: Q / A -> m/s | mean velocity
Re: V * D / nu | Reynolds number
rr: eps / D | relative roughness
if Re < 2300:
The flow is laminar.
f: 64 / Re | friction factor, laminar
else:
The flow is turbulent.
f: 0.25 / (log(rr / 3.7 + 5.74 / Re^0.9))^2 | friction factor, Swamee-Jain
## Head loss
h_f: f * (L_p / D) * V^2 / (2 * g_acc) -> m | friction head loss
h_m: minor * K_m * V^2 / (2 * g_acc) -> m | head loss in the fittings, when included
h_L: h_f + h_m -> m | total head loss
H: dz + h_L -> m | head the pump must supply
dp: rho * g_acc * h_L -> kPa | pressure drop from losses
P_h: rho * g_acc * Q * H -> kW | hydraulic power
if V <= 3 m/s: "OK: the velocity is within the usual limit of 3 m/s." else: "High velocity: more than 3 m/s, consider a larger pipe."
Because the first radio option is selected when none is marked, the water starts at 5 degrees C.
At the defaults (25 L/s, 150 mm, 300 m, 5 m rise, K 2.5, commercial steel, 5 degrees C,
fittings on):
| Quantity | Result |
|---|---|
| Velocity, Reynolds number | 1.41 m/s, 139610: “The flow is turbulent.” |
| Friction factor | 0.0186 |
| Friction loss, fittings loss, total | 3.79 m, 0.255 m, 4.05 m |
Pump head H | 9.05 m |
| Pressure drop, hydraulic power | 39.72 kPa, 2.22 kW |
| Message | OK: the velocity is within the usual limit |
| Change | Result |
|---|---|
| Water at 20 degrees C (second radio button) | Total loss 3.86 m, H 8.86 m, pressure drop 37.8 kPa, power 2.17 kW. |
| Fittings off | Total loss 3.79 m, H 8.79 m, power 2.16 kW. |
| Diameter 200 mm | Velocity 0.796 m/s, total loss 1 m, H 6 m, power 1.47 kW. |
| Flow 60 L/s | Velocity 3.4 m/s: “High velocity: more than 3 m/s, consider a larger pipe.” |
| Flow 0.2 L/s | Reynolds number 1116.88: “The flow is laminar”, friction factor 0.0573. |
Worked template 5: a cantilever with a tip load
The fifth sample, Template: cantilever with a tip load, is the beam template’s close relative: length, tip load, a rectangular section, a material and a deflection limit, with the own-weight checkbox. It ends with a moment diagram.
The whole sheet
<!--sheet-->
# Cantilever with a load at the tip
A template with inputs. Choose **Input** in the results bar to fill in the form. A cantilever of
length $L$ with a solid rectangular section $b \times d$ carries a point load $P$ at the free end
and, if wanted, its own weight $w$. At the fixed end $M = P L + w L^2 / 2$ and
$V = P + w L$, and the tip deflection is $\delta = P L^3 / (3 E I) + w L^4 / (8 E I)$.
## Inputs
L: ? 2.5 m [0.5 .. 6 step 0.1] | length
P: ? 8 kN [1 .. 100 step 1] | point load at the free end
b: ? 100 mm | section width
d: ? 200 mm | section depth
mat: ? [Structural steel = 1, Aluminium = 2, Timber = 3] | material
limit: ? (L/90 = 90, L/180 = 180, L/360 = 360) | tip deflection limit
sw: ? on | include the own weight of the beam
## Material properties
E_tab: [200 GPa, 70 GPa, 11 GPa] | modulus of elasticity
fa_tab: [165 MPa, 100 MPa, 12 MPa] | allowable bending stress
rho_tab: [7850 kg/m^3, 2700 kg/m^3, 500 kg/m^3] | density
E: E_tab.mat -> GPa
f_a: fa_tab.mat -> MPa
rho: rho_tab.mat -> kg/m^3
if mat == 1: "The material is structural steel."
if mat == 2: "The material is aluminium."
if mat == 3: "The material is timber."
## Section
A: b * d -> cm^2 | area
I: b * d^3 / 12 -> cm^4 | second moment of area
Z: b * d^2 / 6 -> cm^3 | elastic section modulus
## Load
g_acc: 9.81 m/s^2 | gravitational acceleration
w: sw * rho * A * g_acc -> kN/m | own weight, when included
## Results at the fixed end and at the tip
M_max: P * L + w * L^2 / 2 -> kN*m | maximum bending moment, at the fixed end
V_max: P + w * L -> kN | maximum shear force, at the fixed end
sigma: M_max / Z -> MPa | maximum bending stress
delta: P * L^3 / (3 * E * I) + w * L^4 / (8 * E * I) -> mm | tip deflection
theta: P * L^2 / (2 * E * I) + w * L^3 / (6 * E * I) | tip rotation, in radians
delta_lim: L / limit -> mm | tip deflection limit
util_b: sigma / f_a | bending utilisation
util_d: delta / delta_lim | deflection utilisation
if util_b <= 1: "Bending: OK, the stress is within the allowable stress." else: "Bending: the stress exceeds the allowable stress, enlarge the section or change the material."
if util_d <= 1: "Deflection: OK, within the limit." else: "Deflection: over the limit, enlarge the section or change the material."
## Bending moment diagram
M(x): P * (L - x) + w * (L - x)^2 / 2 -> kN*m | bending moment at a distance x from the fixed end
plot M(x * 1 m) / (1 kN*m) for x in 0..L / (1 m)
At the defaults (2.5 m, 8 kN, 100 mm by 200 mm, steel, L/90, own weight on) the moment at the fixed end is 24.81 kN·m, the shear 11.85 kN, the bending stress 37.22 MPa (0.226) and the tip deflection 3.69 mm against a 27.78 mm limit (0.133). Both checks pass. Choose timber and the stress is 30.46 MPa against 12 MPa (2.54) and the tip deflection 57.47 mm (2.07): both fail.
Worked template 6: a retaining wall
The sixth sample, Template: retaining wall stability, checks a cantilever retaining wall (a stem on a base slab, one metre of wall) for overturning, sliding and bearing pressure under the base. Its inputs are the geometry, a surcharge on the fill, and the backfill:
## Inputs
H_s: ? 3 m | height of the stem above the base slab
B: ? 2.4 m | width of the base slab
t_b: ? 0.4 m | thickness of the base slab
t_s: ? 0.4 m | thickness of the stem
L_t: ? 0.6 m | length of the toe, in front of the stem
soil: ? (Loose sand = 28 °, *Medium sand = 32 °, Dense sand = 36 °) | backfill, friction angle
q_s: ? 10 kPa | surcharge on the fill, when it is on
sur: ? off | surcharge on the fill
Two things are new here. The radio group soil chooses a friction angle directly: its values
are angles (28 °), and a later line uses the chosen angle as a quantity (phi: soil). The
values carry the degree sign, which an input accepts like any other unit. The checkbox sur is
used as a multiplier, q: sur * q_s: ticked it is 1 and the surcharge counts, unticked it is 0.
The whole sheet
<!--sheet-->
# Retaining wall: sliding and overturning
A template with inputs. Choose **Input** in the results bar to fill in the form. A cantilever
retaining wall of concrete (a stem on a base slab) holds back a level fill; the sheet takes a strip of wall one metre long.
The active earth pressure is $K_a = \tan^2(45^\circ - \phi/2)$, acting on the vertical plane through
the heel, so the thrust is $P_a = \tfrac12 K_a \gamma H^2$ at $H/3$ above the underside of the base. A
surcharge $q$ on the fill adds $K_a q H$ at $H/2$ and its weight on the heel. The wall slides on a
base friction of $\tan(2\phi/3)$, and overturns about the toe. The soil in front of the toe is ignored.
## Inputs
H_s: ? 3 m | height of the stem above the base slab
B: ? 2.4 m | width of the base slab
t_b: ? 0.4 m | thickness of the base slab
t_s: ? 0.4 m | thickness of the stem
L_t: ? 0.6 m | length of the toe, in front of the stem
soil: ? (Loose sand = 28 °, *Medium sand = 32 °, Dense sand = 36 °) | backfill, friction angle
q_s: ? 10 kPa | surcharge on the fill, when it is on
sur: ? off | surcharge on the fill
## Constants
gamma_c: 24 kN/m^3 | unit weight of concrete
gamma_s: 18 kN/m^3 | unit weight of the fill
b_w: 1 m | length of wall in the strip
FS_min: 1.5 | required factor of safety, for sliding and for overturning
## Geometry
phi: soil | friction angle of the fill
H: H_s + t_b -> m | height of the thrust plane, above the underside of the base
L_h: B - L_t - t_s -> m | length of the heel, behind the stem
q: sur * q_s -> kPa | surcharge in use
## Earth pressure
K_a: tan(45 ° - phi / 2)^2 | active pressure coefficient
P_s: K_a * gamma_s * H^2 / 2 * b_w -> kN | thrust of the fill
P_q: K_a * q * H * b_w -> kN | thrust of the surcharge
P_h: P_s + P_q -> kN | total horizontal thrust
## Weights and their lever arms about the toe
W_stem: gamma_c * t_s * H_s * b_w -> kN | stem
x_stem: L_t + t_s / 2 -> m | its lever arm
W_base: gamma_c * B * t_b * b_w -> kN | base slab
x_base: B / 2 -> m | its lever arm
W_fill: gamma_s * L_h * H_s * b_w -> kN | fill on the heel
W_sur: q * L_h * b_w -> kN | surcharge on the heel
x_heel: B - L_h / 2 -> m | lever arm of the fill and the surcharge
W: W_stem + W_base + W_fill + W_sur -> kN | total vertical load
## Overturning
M_o: P_s * H / 3 + P_q * H / 2 -> kN*m | overturning moment about the toe
M_r: W_stem * x_stem + W_base * x_base + (W_fill + W_sur) * x_heel -> kN*m | resisting moment about the toe
FS_o: M_r / M_o | factor of safety against overturning
if FS_o >= FS_min: "Overturning: OK." else: "Overturning: the factor of safety is too low, widen the base."
## Sliding
mu: tan(2 * phi / 3) | friction coefficient of the base on the ground
R_h: mu * W -> kN | sliding resistance
FS_s: R_h / P_h | factor of safety against sliding
if FS_s >= FS_min: "Sliding: OK." else: "Sliding: the factor of safety is too low, widen the base or make it thicker."
## Bearing pressure under the base
x_r: (M_r - M_o) / W -> m | where the resultant crosses the base, from the toe
e: B / 2 - x_r -> m | eccentricity from the middle of the base
q_max: W / (B * b_w) * (1 + 6 * e / B) -> kPa | pressure at the toe
q_min: W / (B * b_w) * (1 - 6 * e / B) -> kPa | pressure at the heel
if abs(e) <= B / 6: "The resultant is inside the middle third: the whole base is in compression." else: "The resultant is outside the middle third: part of the base lifts off, and the pressures above no longer apply."
At the defaults (medium sand, no surcharge) the horizontal thrust is 31.97 kN and the vertical load 127.44 kN:
| Quantity | Result |
|---|---|
Active pressure coefficient K_a | 0.307 |
| Overturning moment, resisting moment | 36.23 kN·m, 179.21 kN·m |
Factor of safety against overturning FS_o | 4.95: “Overturning: OK.” |
Sliding resistance, friction coefficient mu | 49.77 kN, 0.391 |
Factor of safety against sliding FS_s | 1.56: “Sliding: OK.” |
| Pressure at the toe, at the heel | 63.46 kPa, 42.74 kPa |
| Message | The resultant is inside the middle third. |
| Change | Result |
|---|---|
| Surcharge ticked | FS_o 3.76, FS_s 1.3: “Sliding: the factor of safety is too low, widen the base or make it thicker.” |
| Loose sand | FS_o 4.21, FS_s 1.15: sliding fails. |
| Dense sand | FS_o 5.85, FS_s 2.1. Both pass. |
| Base 3 m wide | FS_o 7.79, FS_s 2.02. Both pass. |
Worked template 7: a pump and pipeline operating point
The seventh sample, Template: pump operating point, finds where a pump works. A pump lifts water through a pipeline to a higher tank. The pump gives less head as the flow grows, the pipeline needs more, and the pump runs where the two curves cross. The inputs are a choice of three pumps (radio buttons), the pipe diameter (a drop-down whose values are lengths), the pipe length, the static lift, and a checkbox for an aged, rougher pipe:
## Inputs
pump: ? (Small = 1, *Medium = 2, Large = 3) | pump
D: ? [100 mm = 100 mm, *150 mm = 150 mm, 200 mm = 200 mm] | pipe inside diameter
L_p: ? 400 m | pipe length
H_st: ? 15 m | static lift, from the water surface to the tank
aged: ? off | aged pipe (rougher: the friction factor is 0.030, not 0.018)
The pump is an index into two tables (H0_tab, Qmax_tab), as in the first template. What is new
is the output. The sheet solves the crossing in closed form, tabulates both curves with a vector
of flows and augment, and draws them with plot, so the form changes the numbers, the table and
the chart together.
The whole sheet
<!--sheet-->
# Pump and pipeline: operating point
A template with inputs. Choose **Input** in the results bar to fill in the form. A pump lifts water
through a pipeline to a higher tank. The pump delivers the head $H_p = H_0 \left(1 - (Q/Q_{max})^2\right)$
at the flow $Q$ (a shut-off head $H_0$ and a free delivery $Q_{max}$). The pipeline needs the head
$H_s = H_{st} + f \frac{L}{D}\frac{v^2}{2g}$, the static lift plus the friction loss with a constant friction
factor $f$. The pump runs where the two curves cross. The table and the plot follow the form.
## Inputs
pump: ? (Small = 1, *Medium = 2, Large = 3) | pump
D: ? [100 mm = 100 mm, *150 mm = 150 mm, 200 mm = 200 mm] | pipe inside diameter
L_p: ? 400 m | pipe length
H_st: ? 15 m | static lift, from the water surface to the tank
aged: ? off | aged pipe (rougher: the friction factor is 0.030, not 0.018)
## Pump curves
The input above picks one entry of each list.
H0_tab: [30 m, 40 m, 50 m] | shut-off head
Qmax_tab: [60 L/s, 75 L/s, 90 L/s] | free delivery
H_0: H0_tab.pump -> m
Q_max: Qmax_tab.pump -> L/s
if pump == 1: "The pump is the small one."
if pump == 2: "The pump is the medium one."
if pump == 3: "The pump is the large one."
## Pipeline
g_acc: 9.81 m/s^2 | gravitational acceleration
f: 0.018 + aged * 0.012 | friction factor
A: pi * D^2 / 4 -> m^2 | flow area
K: f * L_p / D / (2 * g_acc * A^2) -> s^2/m^5 | friction head per flow squared
## Operating point
The two curves cross where $H_0 - H_0 Q^2/Q_{max}^2 = H_{st} + K Q^2$, so
$Q^2 = (H_0 - H_{st}) / (K + H_0/Q_{max}^2)$.
H_net: H_0 - H_st -> m | head the pump has above the static lift
if H_net <= 0 m: "The pump cannot lift the water to the tank: choose a larger pump or lower the static lift."
Q_op: sqrt(max(H_net, 0 m) / (K + H_0 / Q_max^2)) -> L/s | flow at the operating point
H_op: H_0 * (1 - (Q_op / Q_max)^2) -> m | head at the operating point
v: Q_op / A -> m/s | velocity in the pipe
if v > 3 m/s: "The velocity is above 3 m/s: expect noise and wear, use a larger pipe." else: "The velocity is within 3 m/s."
## Table
Q_v: [0, 10, 20, 30, 40, 50, 60] * 1 L/s | flows in the table
H_pv: H_0 * (1 - (Q_v / Q_max)^2) -> m | pump head
H_sv: H_st + K * Q_v^2 -> m | head the pipeline needs
T: augment(Q_v / (1 L/s), H_pv / (1 m), H_sv / (1 m)) | columns: flow in L/s, pump head in m, pipeline head in m
## Curves
H_p(Q): H_0 * (1 - (Q / Q_max)^2) -> m | pump head at the flow Q
H_s(Q): H_st + K * Q^2 -> m | pipeline head at the flow Q
plot H_p(x * 1 L/s) / (1 m) as "pump", H_s(x * 1 L/s) / (1 m) as "pipeline" for x in 0..60
The same crossing, found numerically from the two curves:
if H_net > 0 m:
Q_num: solve H_p(Q) = H_s(Q) for Q in 0 L/s..Q_max -> L/s | flow where the pump head equals the pipeline head
At the defaults (medium pump, 150 mm, 400 m, 15 m lift, new pipe) the pump runs at 40.9 L/s and 28.1 m of head, with 2.31 m/s in the pipe. The table has seven rows, from 0 to 60 L/s: at 40 L/s the pump gives 28.62 m and the pipeline needs 27.53 m, and at 50 L/s the pump gives 22.22 m against 34.59 m, so the crossing lies between them.
| Change | Result |
|---|---|
| Small pump | 30.46 L/s at 22.27 m |
| Large pump | 49.99 L/s at 34.58 m, 2.83 m/s |
| Aged pipe | 35.21 L/s at 31.19 m |
| Diameter 100 mm | 19.37 L/s at 37.33 m, 2.47 m/s |
| Static lift 35 m | 18.29 L/s at 37.62 m |
| Small pump and static lift 35 m | “The pump cannot lift the water to the tank: choose a larger pump or lower the static lift.” The flow is 0. |
Share a template
A template is one text file. Save it (Ctrl+S) as a .sheet file and send that file, or paste the
text of the sheet. Whoever opens it gets the same form, in any browser, with nothing to install.
Once the app has been visited it runs offline too (see
Saving, opening and working offline). Nothing is sent to a server:
the numbers are worked out on the reader’s own computer.
- The values you saved with Save values travel with the file, so a template can be sent already filled in. Send the file without that comment line to send the defaults.
- Each person who opens it and saves values keeps their own numbers in their own copy.
Writing your own
- Write the calculation as an ordinary sheet and check it.
- Turn the quantities someone will want to change into inputs: put
?in front of the value. - Put them together under a heading (
## Inputs), so the form reads like a form. - Put the results below the inputs, with a note on every line.
- Where a result depends on a choice, use an index and tables (worked template 1), or let the choice be the number itself (worked template 3).
- Add a message for each check (
if util <= 1: "OK" else: "Fails"), so that the report says what the numbers mean. - Test it in Input mode, then in Report with the defaults. That is what a reader without the form sees.
The ribbon’s Input/Output tab inserts a starting line for each kind: Entry, Dropdown,
Radio and Checkbox write the ? form in a sheet. Data grid and More input forms
(labelled, vector, matrix and formula inputs) have no sheet form and insert #UI lines, marked
with >>. See Input forms with #UI.
Model bindings
A '<!--civilkit: bind L = path --> comment before an input can tie it to a quantity in a
structural model. The specification and the in-app marker exist; no model is connected yet, so
typed values are used.
Related calculators: Simply supported beam, Cantilever beam, Column buckling, Retaining wall stability, Pad footing bearing pressure, Pipe flow, Darcy-Weisbach, Pump operating point. More pages are in Calculators and guides.
Symbolic maths
Video: Symbolic maths for a beam deflection
The calculation engine is numeric: it gives you numbers. The Symbolic dialog gives you formulas. It rearranges an equation, differentiates, integrates, solves for the constants of integration and substitutes values, all exactly, with fractions kept as fractions and symbols kept as symbols. Then you put the result into the sheet and let the engine check it with numbers.
Open it from Functions > Symbolic on the ribbon. The module loads the first time you run something, and it works offline.
Using the dialog
- Type an expression, or an equation with
=. Write*for every product and^for powers. The functions aresin,cos,ln,expandsqrt; the constants arepiande. Enter runs it; Shift+Enter starts a new line. - Choose the operation:
| Operation | What it needs | What you get |
|---|---|---|
| Simplify | the expression | like terms collected, powers combined |
| Expand | the expression | products and powers of sums multiplied out |
| Factor | the expression | common factors, and polynomials in one variable |
| Differentiate | a variable, and an order (1 by default) | the derivative |
| Integrate | a variable, and for a definite integral both limits | an antiderivative (with no constant), or the value between the limits |
| Solve for | one variable for one equation (write =), or several variables separated by commas for a linear system whose equations are separated by ; or new lines | the solutions; a quadratic gives both roots |
| Substitute | values such as x = 2, b = 3*a | the exact result |
| Evaluate | a number for every variable | a decimal number to 12 digits |
-
The result is typeset (with KaTeX) and also shown as text, with a Copy button.
-
Insert into worksheet writes the result at the cursor:
- in a sheet: a display formula block (
$$ ... $$, typeset in the preview) or a quantity linename: expression; - in a Calcpad worksheet: a calculation line
name = expression, or a comment line.
A quantity line is calculated by the engine, so every symbol in it needs a value in the sheet. Use the formula block to keep a result in terms of symbols.
- in a sheet: a display formula block (
A worked derivation: the deflection of a simply supported beam
The beam has span L, uniform load w and stiffness EI. The bending moment at x is M(x) = w L x / 2 - w x² / 2, and the deflection y, taken in the direction of the load, satisfies EI y’’ = -M(x). These are the dialog’s results for each step (the inputs are in the first column).
| Step | Operation and input | Result |
|---|---|---|
| 1 | Integrate -(w*L*x/2 - w*x^2/2)/(E*I) for x | -L*w*x^2/(4*E*I) + w*x^3/(6*E*I) |
| 2 | Add a constant C1 yourself and Integrate again: -(w*L*x^2/4 - w*x^3/6)/(E*I) + C1 for x | -L*w*x^3/(12*E*I) + w*x^4/(24*E*I) + C1*x |
| 3 | Add C2. The supports give y(0) = 0 and y(L) = 0, so Solve for C1, C2 the equations C2 = 0; -L^4*w/(12*E*I) + L^4*w/(24*E*I) + C1*L + C2 = 0 | C1 = L^3*w/(24*E*I); C2 = 0 |
| 4 | Substitute x = L/2 into the curve -L*w*x^3/(12*E*I) + w*x^4/(24*E*I) + L^3*w*x/(24*E*I) | 5*L^4*w/(384*E*I) |
The midspan deflection is 5 w L⁴ / (384 E I). That is the formula to put in the sheet. The dialog
can also differentiate it (5*L^3*w/(96*E*I) with respect to L), or evaluate it for given
numbers: with w = 12, L = 6, E = 200 and I = 250 the result is 0.00405 (in consistent
units of your choice).
Putting the result into a sheet
In the sheet, write the derivation as prose and display formulas, then give the engine the numbers and check the formula against the curve:
## Step 4: midspan
Substituting $x = L/2$ into the curve and simplifying gives
$$y\left(\frac{L}{2}\right) = \frac{5 L^4 w}{384 E I}$$
## Numbers
w: 12 kN/m | design load
L: 6 m | span
E: 200 GPa | modulus of elasticity
I: 250000000 mm^4 | second moment of area
delta: 5 * w * L^4 / (384 * E * I) -> mm | midspan deflection from the formula
y(x): -L * w * x^3 / (12 * E * I) + w * x^4 / (24 * E * I) + L^3 * w * x / (24 * E * I) | the curve with its constants
y_mid: y(L / 2) -> mm | the curve at midspan
ratio: y_mid / delta | 1 when the formula and the curve agree
w = 12 kN/m design load
L = 6 m span
E = 200 GPa modulus of elasticity
I = 250000000 mm⁴ second moment of area
δ = 5·w·L⁴/(384·E·I) = 5 · 12 kN/m · (6 m)⁴ / (384 · 200 GPa · 250000000 mm⁴) = 4.05 mm
y_mid = y(L/2) = y(6 m / 2) = 4.05 mm the curve at midspan
ratio = y_mid / δ = 4.05 mm / 4.05 mm = 1
The two routes agree: the exact formula from the dialog and the curve with its constants give the same 4.05 mm. The sample Beam deflection derived symbolically (Samples, group Sheet syntax) is this sheet in full, with the deflection curve plotted:
L: 6 m
w: 12 kN/m
E: 200 GPa
I: 250000000 mm^4
y(x): -L * w * x^3 / (12 * E * I) + w * x^4 / (24 * E * I) + L^3 * w * x / (24 * E * I)
plot -y(x * 1 m) / (1 mm) for x in 0..6
(The plot divides by 1 mm to give the plot a plain number, and flips the sign so the beam sags
downward on the page.)
Limits
The algebra is exact rational arithmetic, so a result that does not fit in 128 bits is an error rather than a rounded guess, and a refusal is shown in words with the library’s own message (“Cannot integrate: power of a non-linear base.”). Nothing is guessed. The limits:
- no complex numbers;
- only
sin,cos,ln,expandsqrt; - integration covers a small class of integrands;
- solving covers a single equation of degree 1 or 2, and linear systems of up to four unknowns;
- symbols are treated as positive real numbers, so
sqrt(x^2)isx.
For anything else, use the numeric tools: $Root, $Area, $Slope, lsolve and friends.
Related pages: The beam deflection formula, derived. More pages are in Calculators and guides.
Importing worksheets
Video: Import an existing worksheet
The worksheet importer converts worksheet files from a spreadsheet-like calculation format, with
text, equations, plots and pictures placed freely on a page (files ending .xmcd and .mcdx), into
a new Calcpad worksheet that this engine calculates. It evaluates nothing itself: it only translates,
and then the one engine runs the result. Every number in the output is a number that was in the
source file.
Nothing is uploaded. The file is read and converted in the page, by a module that loads on first use.
How to import
Any one of:
- File > Import worksheet…
- the Import worksheet button on the Document tab
- File > Open… and pick the file
- drag the file onto the page (a dashed hint shows while you drag)
The converted worksheet opens as a new unsaved tab named after the file, with the extension .cpd.
Picture files from the source go into the library under /imported/<file name>/. Importing the same
file name again replaces that folder.
A dialog then says how the import went, for example:
Imported tank.xmcd: 18 of 21 regions converted live, 2 shown as static pictures, 1 need attention.
followed by a list of what did not convert, in plain words, by the number of regions affected (for example “calls to a function from an add-in we cannot run” or “embedded objects”). Two toggles re-run the import in the same tab:
- Pictures of unconverted regions (on by default): a region that cannot be converted is shown as a picture of the original, so the page still reads like the source.
- Show saved results as static values (off by default): places the values the source file saved where it could not compute them.
The dialog’s last line repeats that the file was read in this page and was not uploaded.
What converts
The importer follows the author’s page: it reads regions in reading order and writes Calcpad lines.
| In the source | In the result |
|---|---|
| Text, with heading styles, bold, italic, underline, sub and superscript, paragraph fonts, sizes and colours | Text lines. Fonts and sizes can be tidied away (see below). |
Definitions (x := ...), evaluations (x =), functions | Calcpad definitions and equation lines, with the source’s names, subscripts and Greek letters. |
| Units | The same units, converted to this engine’s names. A unit the engine does not know is reported. |
| Vectors, matrices and indexing | Vectors and matrices. The array origin is shifted to 1, with a note. |
| Sums, products, integrals, derivatives (supported forms) | The engine’s $Sum, $Product, $Area and slope commands. |
| Programs made of loops and conditions, early exits, grown arrays | Expression blocks. |
| Plots (x-y plots) | $Plot lines. A plot’s colours, markers and axis ranges may not carry over (a note says so). |
| Solve blocks of one or two unknowns | Solved here by iteration, and kept only if the equations hold at the answer; otherwise the value the file saved. |
| Statistics functions, complex numbers, simple text values (codes) | Converted. |
| Referenced worksheets | Their definitions are read in, when the file holds a copy. |
| Pictures | Embedded in the library. |
The author’s equations are shown as the author wrote them (stacked fractions, sums with bounds, subscripts, a transpose superscript), typeset as maths, and computed out of sight. The page reads like the source, and the Word export turns the typeset equations into Word equations.
What is frozen
Some values cannot be computed here, so the importer takes the number the source file saved and shows it as a literal marked frozen:
- values that came from an input component (a combo box, a list box, a text box): the stored selection becomes the value, and it does not follow a change of the input;
- a call into a function from an external library (an add-in) that is not available here, when the file saved a value;
- a table read from a data file, as the table the worksheet saved;
- a solve block whose iteration does not verify.
The dialog counts frozen values and says so.
What does not convert
Each gap is counted under a stable code and replaced by a placeholder: a typeset, not-calculated equation or a static picture of the original. The main ones:
- range variables that fall outside the supported uses, and programs outside the supported subset;
- solve blocks of more than two unknowns, other solvers, symbolic evaluation;
- derivative and integral forms the importer does not map, and some summation forms;
- plots that are not x-y plots, or that store binary items;
- embedded objects, components, worksheet references with no copy, add-in functions with no saved value;
- text values that are joined, measured or formatted (
concatand similar); - a region the source has switched off, and some page headers and footers.
A region that depends on a gap is reported as downstream of it, and the dialog ranks the missing features by the number of regions each blocks. A calculation that depends on an unconverted region shows that region’s names as undefined; read the dialog list first.
The importer is a work in progress. Plan on checking an imported worksheet against the source, line by line, before relying on it, as you would with a hand conversion.
After the import
- Tidy text (Document tab) removes imported fonts, sizes and colours from paragraphs and turns import markers into short notes. Equations are left alone.
- Text to Markdown tidies and then writes runs of simple paragraphs as Markdown, which you can then edit as rich text by double-clicking. See Editing.
- Save. The
.cpdrefers to the pictures by library path (imported/<name>/R12.svg). Pictures stay as long as the browser’s library does. A.cpdopened later from disk shows its pictures only while the library holds them; export to HTML or Word first for a self-contained file.
Limits
Input over 64 MiB, XML nested deeper than 256, a DTD, and pictures over 16 MiB each or 192 MiB in total are refused or skipped. Errors are messages, not crashes: “… is not a worksheet this importer reads”, “not well-formed XML”, “the file is a zip package that cannot be read”.
Related pages: Opening .xmcd and .mcdx files. More pages are in Calculators and guides.
Importing a spreadsheet
Import spreadsheet reads an Excel or CSV file and lets you pick cells from it and add them to a sheet as named quantities and tables. Use it for a schedule of loads, a list of member sizes or a column of test results that already lives in a spreadsheet.
What it does and does not do. The values are copied into the sheet as ordinary lines, so the sheet carries them and a report prints without the file. Formulas in the file are not recalculated and there is no live link back to the file: a formula cell gives the value the file stored for it (spreadsheet programs save one), and the calculation is done by your sheet from there. If the file changes, import the cells again. Nothing is uploaded; the file is read in the page.
How to import
Any one of:
- the Import spreadsheet button on the Document tab (next to Import worksheet)
- File > Import spreadsheet…
Choose a .xlsx, .xlsm, .csv or .tsv file. A panel opens over the page. It is not modal: you can
click in the editor to move the cursor between additions, and Close (or Esc) puts it away.
Open or create a sheet first. The lines are sheet lines, so adding into a Calcpad worksheet is refused with a message.
The panel
- Tabs along the top, one for each sheet of the workbook (a CSV has one).
- A read-only grid with column letters and row numbers. Formula cells are grey and italic, and hover (or the cell’s tooltip) shows the formula text. Constant cells are plain.
- Click a cell, or drag over a range, to select it. On a touch screen tap a cell, switch on Select range, then tap the far corner.
- An action bar under the grid shows the selection, a proposed name and unit you can edit, and the actions that fit the selection.
- Cells you have added turn green with their name, so you can see what is already used.
| Selection | Action | Writes |
|---|---|---|
| A constant number | Add as input | span: ? 6 m (the reader can change it) |
| A number or formula cell | Add as value | Mstar: 56.25 kN*m (the stored result) |
| A range of numbers | Add as table | a vector [1; 2; 3] or a matrix [1, 2; 3, 4] |
| A range with text | Add as table | a table of text for the report (not used in calculations) |
| Two columns, label then value | Add labelled rows | one quantity line for each row |
A formula cell cannot be an input, because its value is a result. A text cell has no number to add.
The lines go at the editor cursor: on the cursor’s line when it is blank, otherwise on the lines after
it. Above them goes a short source comment, for example <!-- loads.xlsx, Loads!B1 -->. It is an HTML
comment, so it shows in the editor and prints as nothing in the report.
Names and units
The name is guessed from the label to the left of the cell, or the header above it, and turned
into a sheet name (see Quantities): several words become camel case
(Design load is designLoad), Greek letters become their spellings (φ factor is phiFactor), a
leading digit gets an n, and a name that is a keyword gets a _. If the sheet already has the name,
a number is added (span2). Edit the name before you add if you want another.
The unit is taken from the label’s brackets (Length (m), Load [kN/m], Area (mm²) is mm^2), or
from a unit in the cell beside the value (a unit column), when it looks like a unit. Words in
brackets such as (optional) are not taken. A wrong or empty unit is easy to fix in the name and
unit boxes, or in the sheet afterwards.
The label becomes the note after the value (span: 6 m | Span).
Tables
A range of numbers becomes a vector (one row or column) or a matrix, with the unit on every
element. If the first row is text over numbers, it is treated as a header: the matrix holds the
numbers below, and the header names go in the source comment. Empty cells in the numbers read as 0.
A table is limited to 5,000 cells. Reach an element with A.(row, column) as for any matrix.
A range that has text in it is added as a plain table of the cells as shown, for the report only.
Labelled rows
Select a range of two columns: the labels, then the values (a third column may hold the units). Each row with a label and a number becomes one line, named from its label. Rows whose value is not a number are left out, and the status line says how many. Tick Rows as inputs to make the constant rows inputs.
Files and limits
- Excel:
.xlsxand.xlsm. Shared and inline strings, numbers, booleans and error values are read. Dates are shown as their serial numbers. Merged cells are ignored (each cell is shown where it is stored). Macros are never run. The old.xlsformat and password-protected workbooks are refused with a message; save as.xlsxor.csv. - CSV and TSV: quotes (and doubled quotes), line breaks inside quotes, a comma, semicolon or
tab delimiter found by itself, and a decimal comma when the delimiter is not a comma (
6,5). - Files over 5 MB, and workbooks with more than 200,000 cells, are refused. Save the part you need as a CSV.
- A damaged file shows a message and changes nothing.
- The grid shows 200 rows at a time (a button shows more) and the first 100 columns.
- Text cells cannot be used as values in calculations; only numbers and booleans (as 1 or 0).
Number format
Some languages write 1,5 where others write 1.5, and group digits as 1.000,5 or 1 000,5. CivilKit Calcs lets you choose how numbers are shown and typed. Your worksheets do not change: a sheet always keeps the decimal point, so a file reads the same on every machine.
Choosing a format
Open Settings (the gear at the right end of the top strip). Number format is on the General tab, under Language.
| Choice | Looks like |
|---|---|
| Automatic | follows the language of your browser |
| Point | 1,234.5 |
| Comma | 1.234,5 |
| Space and comma | 1 234,5 |
Group digits adds the thousands separator; it is off by default. The choice is remembered in this browser.
Add ?numfmt=comma to the address to try a format on one page without storing it (point, comma, space or
auto, and &numgroup=1 for digit groups).
What changes
Results in the preview, the report, print and PDF, and the HTML export, plus the equations and text of the Word export and the Report sheet of the Excel export. Excel’s variable sheets keep real numbers. Variable names, subscripts, exponents and units are never touched, and neither is text you wrote: a sentence that says “use 1.5 m” stays as typed.
L: 6.5 m
w: 12.5 kN/m
M: w * L^2 / 8 -> kN*m
L = 6.5 m
w = 12.5 kN/m
M = w·L² / 8 = 12.5 kN/m · (6.5 m)² / 8 = 66.02 kN·m
In the Comma format that reads L = 6,5 m and M = ... = 66,02 kN·m, while the sheet itself still says 6.5.
Typing numbers
In a comma format an input box shows 6,5 and accepts both 6,5 and 6.5. The value the engine and the saved values use is always 6.5. A slider moves the box as before, and a message such as “must be from 0,5 to 2,5” uses your format. In an input box a point is always a decimal point, so write 1234,5 or 1 234,5 rather than 1.234.
What does not change
Pasting into the editor is not converted, because a comma in a formula separates arguments. Plot axes, 3D views, Python output and spreadsheet-style grids keep the decimal point.
Exporting
Video: Export a report to Word, Excel and PDF
A calculated sheet leaves the page in four ways: a PDF through the print dialog, a Word document, an Excel workbook and standalone HTML. All of them are built in the page, from the same calculated report, so what you see is what you export. The Word and Excel writers load the first time you use them and work offline.
The Document tab has buttons for Print PDF, Word, Excel and Export…. The File menu has Print PDF…, Export… and Export Excel…. The Export dialog lists the views you can export (Report, Preview, Input form, Unwrapped), each with its own Save PDF, Save Word (not offered for the input form and the unwrapped listing) and Save HTML buttons, and a Plots list that downloads each plot as an image, or all of them as a ZIP.
Which view to export: Report is the usual choice. It applies the values entered in an input form,
hides #pre text and shows #post text. Preview shows what the results pane shows.
Page breaks
To start a new page at a point in the report, put a page break line there:
# Loads
w: 12 kN/m | design load
<div style="page-break-after:always"></div>
# Bending
L: 6 m
M: w * L^2 / 8 -> kN*m
Print PDF and Word both start “Bending” on a new page. You do not need to type the line:
- In a sheet, the + between two blocks has Page break at the end of its menu.
- The ribbon has Page break on the Document tab (Page group) and the Text Formatting tab. It inserts the line at the cursor.
The preview draws the break as a dashed line labelled “Page break”. The line is not printed and is
not in the Word file. A Calcpad worksheet (.cpd) writes the same thing as an HTML comment line,
'<div style="page-break-after:always"></div>, and the ribbon button inserts that form there.
Word also honours the other ways HTML forces a break on an element (page-break-before: always,
break-before: page, break-after: page). Excel has no pages, so the workbook ignores page breaks.
Page view
To see where the pages of a long report break without printing it, choose Pages in the results bar (Preview and Report). The results are laid out on sheets of the PDF’s paper size, with its margins drawn as a faint dashed box, a label “Page 2 of 5” on each sheet and the manual page breaks honoured. The page is the one the PDF settings describe (Settings, Export tab, or the document’s own PDF settings), so changing the paper size, the orientation or a margin changes the view at once. The sheets are always drawn in the light theme, as they print. On a narrow window the sheet is scaled to fit. The choice is kept.
A block that would run over the bottom margin moves to the top of the next page, a heading stays with the line after it, and a block taller than a page is left to run on. The browser keeps long paragraphs and tables in one piece less often than this does, so on the last line or two of a page the print dialog’s own preview has the last word. The view is on screen only: nothing about it is printed or exported.
Word
Word writes a .docx of the report:
- Equations are real Word equations (Office Math): fractions, subscripts, sums, matrices, units. In a test sheet with a handful of formulas the document held 21 equations.
- Headings, paragraphs, lists, links and tables keep their form. A Markdown pipe table gets rules.
- Plots and other drawings are pictures. A plot is stored as a PNG (the SVG is kept beside it, for versions of Word that read SVG).
- Pictures from the library are embedded.
- A formula typeset with LaTeX in a sheet appears as its TeX source in italics, not as a Word equation.
- An interactive Plotly chart cannot be carried. A paragraph stands where it was. A matplotlib figure from a Python block is carried as a picture.
The Word document has been checked in LibreOffice, not in Microsoft Word.
Excel
Excel writes a workbook that mirrors the calculation:
| Sheet | Holds |
|---|---|
| Report | The report in document order. Headings and text in merged cells; every equation a row with its description, name, expression, expression with the numbers put in, value and unit. Text tables are cell ranges. |
| Variables | Every variable in the order it was first assigned, with its last value and unit. |
| One sheet for each vector or matrix | Its elements, a row per row, with the unit. A variable’s row on Variables links to it. |
| Inputs | The variables set by input fields and #UI controls. |
| Plot data | The points of every plot, two columns per curve. |
A plot line or $Plot becomes a native Excel XY chart on the Report sheet at the place of the
plot, with its series pointing at the Plot data sheet, so you can edit the data and the chart redraws.
For a test sheet with one plot line the workbook held one chart and these sheets: Report,
Variables, K, F, u, Inputs and Plot data (K, F and u being a matrix and two vectors).
What the chart loses against the drawing: the faint fill under a curve, the exact fonts and grid style. Colour maps and other drawings are pictures. The cells hold calculated values with the expressions as text, not live Excel formulas.
The workbook opens in LibreOffice and a Python reader. It has not been tried in Microsoft Excel.
Print PDF opens the browser’s print dialog on the report. Choose “Save as PDF” as the destination. The page size, orientation and margins come from the PDF settings (Settings, Export tab; Document > Header and footer opens it there). Until you choose a paper size there, it follows the browser’s language: Letter in the United States, Canada, Mexico, the Philippines, Chile, Colombia, Venezuela and Costa Rica, and A4 everywhere else. A size you have chosen is kept. The printed page carries the browser’s own header and footer in place of title, date and page numbers; turn “Headers and footers” off in the print dialog if you do not want them.
The printed page is the report: the buttons under plots are not printed, and an interactive chart is printed as a still picture of it (draw the chart on the page first; one that was never drawn is replaced by a note).
HTML
Save HTML writes a standalone page with the report, its styles, fonts and pictures. An exported input form is static: it shows the controls, but nothing recalculates behind them.
Files a worksheet writes
#write and #append save matrices to files. The browser keeps the file in the library and
downloads it when its content changes. By default this happens when you make a report; the Export
dialog’s Write files choice and Write to Disk button change that.
From the command line
The command-line front end of the engine converts a Calcpad worksheet to HTML, Word or Excel:
Cli input.cpd output.xlsx. It is built from the same code. A sheet has to be compiled first
(Convert to Calcpad, or the sheet compiler), because the command line reads Calcpad.
Related pages: Export to Word, Excel and PDF, Calculations instead of spreadsheets. More pages are in Calculators and guides.
Editing
There are two places to edit: the source on the left and, in the results, the page itself.
What you can write
A sheet holds prose, quantity and input lines, conditions and loops, plots, Python blocks and
diagrams. The line kinds lists each one with its chapter. A
diagram is a fenced mermaid block of text that the results draw as boxes and arrows; see
Diagrams for a first example and the Diagrams chapter
for more.
The source editor
The editor colours a sheet by role (prose, quantity, block, raw Calcpad, plot). It underlines mistakes and lists them in the Errors dialog; the status bar at the bottom shows the error, warning and information counts.
| Action | How |
|---|---|
| Complete a name, function, unit or keyword | just type; Tab accepts the highlighted entry, Ctrl+Space opens the list by hand |
| Rename a name everywhere | F2, or the editor’s context menu, or the Variables tab (right-click a name) |
| Find a variable or function and its value | Ctrl+; (Cmd+; on a Mac) |
| Go to a name’s definition | F12, or hover to see the defining line and its Calcpad spelling |
| Find references | Shift+F12, or the editor’s context menu |
| Tidy the sheet | Shift+Alt+F (Format Document) |
| Wrap long lines | Alt+Z |
| Find | Ctrl+F (Cmd+F on a Mac) |
| Insert a symbol, function, unit or snippet | the Insert tab in the sidebar, or the ribbon |
Completion
The list opens as you type, in a worksheet and in a sheet alike, and offers what fits where the cursor is:
- Names defined above the cursor, with their last calculated value next to them
(
load = 12 kN). A name defined further down is not offered, and neither is the word you are typing. The parameters of the function you are writing on the current line are offered too. Greek letters, subscripts and primes work as in any name: typingσfindsσ_c. - Built-in functions, with their parameters and a one-line description. Pick one and Tab fills the
call with a placeholder for each argument. In a sheet the arguments are separated with commas, in
a worksheet with
;. The same list is what the function reference shows. - Units, only units, right after a number (
5 kofferskN,kg,kA), and after a unit and*or/(5kN*). A sheet offers units after->as well. A worksheet’s own custom units are in the list. #directives and$commands at the start of a line of a worksheet (#fooffers#for).- Block keywords and format markers at the start of a line of a sheet:
if,else,for,while,repeat,plot,>>, code fences forcalcpadandpython,$$, the input forms (input,dropdown,slider,radio,checkbox) and<!--sheet-->on the first line.
Nothing is offered where the text is not code: a text or comment line, after a quote mark, in a note
(after |), in a string, in a #markdown, #html or #python block, in sheet prose and
formulas, and after the ? of an input. The calculated values come from one calculation of the
whole worksheet (Python blocks are not run for it), so the first list after an edit may show the
value from a moment ago; the list never waits more than a quarter of a second for it.
Rename everywhere
Put the cursor on a variable, function or macro and press F2 (also in the editor’s context menu, and in the Variables tab: right-click a name and choose Rename Everywhere). A small box opens at the top of the editor. It says how many places and lines will change, marks every place in the text and shows the first changed lines as they will read. Enter (or the Rename button) applies it as one undo step; Esc cancels.
- Scope is respected. A function’s parameters, and the name bound inside
$Sum{ ... }, are renamed only on their own line; a macro’s parameters only inside its#defblock. Renaming a variablealeaves a parameteraalone, and the other way round. In a sheet the same holds for a function’s parameters and the variable of aplotline. - Only code is renamed. Comments and text lines, strings,
#markdownand#htmlblocks, and in a sheet prose, notes after|, headings,$...$formulas, and the unit after a number (3 psistays) are left as they are. A formula is typeset text, not a reference to a variable, so it is not renamed. - Inputs follow the name. A
?input (L = ?,L: ? 6 m) is an ordinary definition and is renamed with the name. - Python is left alone except for what it hands over. The names a Python block passes to the worksheet with
export(name=...)orexport("name", ...)are the worksheet’s variables, so they are renamed with the name (the box counts them). Any other Python code, which is not a reference to a worksheet variable, is never touched. - A name that would collide is refused, with the reason, and Rename stays off: a name that is not valid
(it starts with a letter and holds letters, digits,
_and primes), a keyword or built-in function or constant, a name already in use in the document or in an included file, and a name a parameter on a changed line would capture (or that would hide a variable used inside the function). A name that is also a unit is allowed, with a note. - A name defined in an
#included file cannot be renamed from here (only this document is edited).
The variable palette
Ctrl+; (Cmd+; on a Mac) opens a search box over every variable, function and macro of the document, each with
its last calculated value and unit and the line it is defined on. The key is not used by the browsers or by the
editor itself. Type to filter: letters in order are enough (sc finds sigma_c), and built-in functions are included
once you type something. Up and Down choose, Enter inserts the name at the caret (a function goes in as
name() with the caret between the brackets), Alt+Enter (or the arrow button on the row) goes to where it is
defined, Esc or the same key closes it. A tap on a row inserts it, so it works on a touch screen. The Variables tab
in the sidebar has the same names, with a search box that matches the name, the definition, the parameters
and the note.
The Insert tab has a search box that filters the whole library. In a sheet, entries that have no
sheet form (the data grid and the other #UI forms, $Map, directives) carry a >> mark and insert Calcpad text as >> lines.
The text toolbar
Select some words in a line of prose, or click into one, and a small toolbar appears above the line:
Style (Normal, Heading 1, 2 or 3), B, I, </> for code, Link, a bulleted list and a
numbered list. It does not appear on quantity lines, in code fences or inside a $$ formula, where
those would only add characters that mean something else. The same toolbar appears over the text in
the in-place rich-text editor.
Each button’s tooltip shows the Markdown it types (Bold: **text**, Link: [text](address),
Numbered list: 1. item), so you can learn the syntax and type it yourself next time.
- A button is a toggle: Bold on text that is already bold takes the
**off again, and a list button on a list takes the markers off. A button that is on is shown pressed. - With no selection, Bold wraps the word at the caret.
- Link wraps the selection as
[text](url)and selectsurl, ready for the address. - The edit is made in the source, in one undo step, and the editor keeps the focus.
- On a phone or tablet the floating bar stays away so it does not fight the system selection menu; the in-place editor keeps its fixed bar there.
In-place editing in the results
Edit a sheet where it stands, in the preview.
- Click a block (a quantity line, a plot line, a table, a formula, a paragraph) and an editor opens over it. Dragging to select text does not open it.
- Click away applies the change. Esc throws it away. Enter applies at once (Ctrl+Enter for prose, where Enter makes a new line).
- Input and calculation lines are one-line edits. A paragraph, a heading, a list or a table opens as rich text: a small toolbar over the text with bold, italic, heading levels, bullets, a table and its row and column controls. A line under the box says “Ctrl+Enter or click away to apply · Esc to cancel”.
- Everything you apply is written back to the source in one undo step. A paragraph or table you open and apply without changing keeps its exact original lines.
In a Calcpad worksheet, prose written as Markdown (a #markdown … #end markdown block) is edited
the same way, by double-clicking it. The worksheet importer’s Tidy and Markdown options write
this form (see Importing worksheets). To bring numbers from an Excel or CSV file into a sheet as inputs, values and tables, see Importing a spreadsheet.
What the rich-text editor writes is plain Markdown: **bold**, _italic_, ~x~ subscript, ^x^
superscript, ++x++ underline, - lists and pipe tables (no merged cells; a cell is one line).
It loads the first time you use it.
Insert between blocks
Move the pointer between two rendered blocks and a dashed line appears with a + in the middle. Click the + for a menu of blocks to insert there: Math line, Text, Heading, List, Table, Plot, Condition, Python or Page break (see Page breaks). The new block goes in front of the next block’s source line, indented like it, and its first word is left selected in the editor so you can type over it. On a touch screen the + stays hidden until you tap a block, and then shows only in the two gaps beside it.
Cut, copy and paste blocks
The block menu (the ⋮ grip at the left of a block) has Cut, Copy and Paste below. Copy puts the block’s source text on the system clipboard, so you can also paste it into another sheet or a chat. Cut does the same and then deletes the block, with an Undo toast. Paste below inserts the clipboard text after the block, with one blank line between, as a single undo step. If the browser will not let the page read the system clipboard, Paste uses the last block you copied or cut in this window. The + menu between blocks also lists Paste whenever there is something to paste.
Ctrl+Shift+K (Cmd+Shift+K on a Mac) deletes the block that holds the editor caret, with the same Undo toast. In a file that is not a sheet it keeps its usual meaning, delete line.
Turning a block off
Disable in the block menu comments a block out: it drops out of the preview and the calculation but stays in the sheet. A sheet has no multi-line comment, so each line of the block is wrapped in an HTML comment (the one comment the language has):
a: 2 m
<!-- b: a * 3 -->
A disabled block is not drawn at all, so it has no grip. To get it back, put the caret in it and press
Ctrl+Shift+/ (Cmd+Shift+/ on a Mac), which toggles Disable and Enable, or press Undo
right after disabling. Limits: every line is wrapped on its own, a blank line inside the block
becomes an empty comment so the block stays in one piece, and a --> inside a line is written as
--> while it is disabled and restored on Enable. Anything that used a disabled math line sees
an undefined name until it is enabled again.
Collapsing sections
Hover a heading in a sheet and a small arrow shows under its grip. Click it and every block under
the heading, up to the next heading of the same or a higher level, folds away; the heading shows
how many blocks are hidden. Click the arrow again to open the section. A folded ## section hides
only its own blocks, a folded # section hides its ## sub-sections too. The grip menu of a
heading also has Collapse all and Expand all.
Folding is only a view: the sheet text and the results do not change, and printing and exporting always include everything. Folds stay as you edit and when you switch between tabs. Headings are matched by level, text and how many headings with the same text come before them.
Sorting a table
Click a column heading of a table in the preview to sort its rows by that column: the first click
sorts ascending, the second descending, the third puts the rows back in the order of the source. An
arrow next to the heading shows which way it is sorted. A column of numbers sorts by value, even
with a unit after the number (2.5 kN comes before 10 kN); any other column sorts as text, with
A2 before A10. Empty cells stay at the bottom.
Sorting is only a view, like folding: the sheet text does not change, the sort stays as you edit, and printing and exporting show the rows as they are written. The headings are buttons, so Tab reaches them and Enter or Space sorts; on a phone, tap a heading. See Tables.
Reordering blocks
Drag a block’s grip up or down; a blue line shows where it will land, and the block goes there when you let go. Dragging a heading takes its whole section along: the heading and the blocks up to the next heading of the same or a higher level (folded blocks too). A section cannot be dropped inside itself. The move is one step in the editor’s history, and a toast offers Undo. A click on the grip, or a movement of under 6 pixels, still opens its menu. On a touch screen, tap a block to show its grip, then drag the grip.
Plot chips
Under each plot in the preview there is a row of chips: Log x, Log y, 1:1 (equal axis scale), Copy data, PNG and SVG. Copy data puts the plotted values on the clipboard as tab-separated text, ready for a spreadsheet. The 3D plots have Copy data and PNG only.
Sliders on inputs
Give a number input a range and Input mode shows a slider under its box:
L: ? 6 m [2 .. 12 step 0.5] | span
w: ? 12 kN/m [0 .. 30] | design load
M: w * L^2 / 8 -> kN*m | maximum moment
Dragging the slider (or using the arrow keys, Home and End) fills the box and recalculates the
results while you drag; typing in the box moves the slider. The numbers are in the unit of the
default, the slider stops at the minimum and maximum, and step is the size of one stop (without it,
about a hundredth of the range). A line without brackets has no slider. A typed value outside the bounds is refused with a message beside the box. On a phone the track is
taller so a finger can use it. See Templates with inputs.
The math keyboard
The Keyboard item in the status bar opens an on-screen math keyboard with tabs for numbers and
operators, functions, calculus and plots (sum, integral, root, parametric plot), matrices, capital
and lower-case letters, Greek letters and units. On a computer it is a panel you can drag by its title; on a touch screen it docks
at the bottom. A key or template inserts at the cursor of the editor, or of the in-place editor when
one is open. In a sheet, angles are degrees unless the sheet has a #rad line.
Convert a selection to a formula
Select an expression you wrote in a sentence, say w*L^2/8, and press Ctrl+Shift+E (Cmd+Shift+E on a
Mac), or choose Convert Selection to Formula in the editor’s right-click menu, or = Formula on the text
toolbar. In a sheet this
w: 12 kN/m
L: 6 m
The moment at midspan is w*L^2/8.
becomes
w: 12 kN/m
L: 6 m
The moment at midspan is w*L^2/8.
res1: w*L^2/8
The new line goes after the paragraph, and its name is selected: type a better one (Mmid) and it is
named. Where the selection lands:
- In text (prose, a note after
|, a Calcpad text line or comment): a line of its own after the paragraph. In a sheet it is a named line,res1: w*L^2/8; in a Calcpad worksheet a plain calculation line,w*L^2/8. If the selection is the whole line, the line itself becomes the formula. A selection written with its name,M = w*L^2/8, keeps that name, and$...$, backticks and a full stop around it are dropped. - In a calculation: the expression is pulled out to a named line above, and the selection becomes the
name:
M: w*L^2/8 -> kN*mturns intores1: w*L^2/8andM: res1 -> kN*m. Both copies ofres1are selected, so typing a name renames the two at once.
The new name is the first of res1, res2, … that the document does not use yet. The whole change is one
undo step. A selection that is not an expression on one line (plain words, a heading, a code fence, an
input’s default) is left alone and the editor says so. On a phone or tablet a = Formula button shows
under the selection instead of the toolbar.
The sidebar
The sidebar has three tabs: Insert, Contents (the outline of headings) and Variables. Settings, Export, Errors and Prettify open as dialogs from the ribbon (and Errors from the status bar); Esc closes them.
Phones and tablets
At 760 pixels wide or less, the app shows one pane at a time, switched from a bar along the bottom: Edit, Results and Insert. The ribbon starts folded; a tap on its open tab folds it again.
- A long press (half a second) on a rendered line, paragraph or table opens the same in-place editor as a click. Apply and Cancel stay on screen.
- The in-place editor stays visible when the on-screen keyboard opens, and its buttons stay above the bottom bar.
- A row of keys under the line editor offers what a phone keyboard hides:
^ * / ( ) = < > ≤ ≥ √ π ° | _ , ;and the common units (mm,m,kN,MPa,kN·m). A tap inserts at the cursor and keeps the keyboard open. The row scrolls sideways. - A plot’s hover toolbar is left out on a phone; pinch and drag still work.
- Python can need several times longer on a phone. The page offers the longer time limit when a block runs out of its ten seconds. See Python blocks.
The app can be installed to the home screen and works offline. See Saving, opening and working offline.
Embedding a calculator
An embed shows one sample sheet on another web page: its inputs as a small form and its results beside or under it. A reader changes an input and the results recalculate in their own browser, with the workings shown. The page Embed a calculator lists the calculators with a snippet to copy for each.
The embed address
An embed is the app’s address with embed=1 and the id of a sample:
<iframe src="https://civilkit.io/calcs/?embed=1&sample=template-simply-supported-beam"
width="100%" height="560" style="border:1px solid #ccc" loading="lazy"
title="Simply supported beam check: CivilKit Calcs" allow=""
sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"></iframe>
The id is the one the samples browser and the ?sample= links use. The embed shows no ribbon, no sidebar, no tabs
and no editor: a slim header with the sheet’s title and an Open in CivilKit Calcs link (it opens the same
sample in the full app in a new tab), the form and the results.
The form is drawn from the sheet’s input lines (see Templates with inputs): a number box, a
slider for a number with bounds (L: ? 6 m [2 .. 12 step 0.5]), a list, radio buttons or a checkbox. A typed number
outside the slider’s bounds is not used and the box says why. A sheet with no inputs at all gets its plain number
lines (L: 9.8 m | span) as inputs, so a worked example can still be tried.
| Option | Values | What it does |
|---|---|---|
sample | a sample id | The sheet to show (default: the simply supported beam template). |
theme | light, dark, auto | auto (the default) follows the reader’s system setting. |
mode | input, results, both | Only the form, only the results, or both (the default). |
hide | title | Leaves out the title (the Open link stays). |
embed | 1, edit | edit adds a small text editor below, for changing the sheet itself. |
allowpython | 1 | Lets the sheet’s Python blocks run (the reader is still asked first). |
Without allowpython=1 the Python blocks of a sheet are not run: the embed shows their code and a note, and the
results that need them are missing.
The loader script
Instead of writing the frame yourself, put a placeholder where it goes and load the script once:
<div data-civilkit-sample="template-pipe-flow-darcy" data-height="560" data-theme="auto"></div>
<script src="https://civilkit.io/calcs/embed.js" async></script>
The script (about 3 KB, no dependencies) turns each placeholder into the frame above, with the sandbox, and then
fits the frame’s height to its content as the reader works. It accepts data-theme, data-mode, data-hide,
data-height (the height before the content is measured) and data-title. For a copy of Calcs on your own host,
data-origin and data-path say where it lives (https://example.com and /calcs/); the script accepts height
messages only from that origin. Each message from the frame is also fired on the iframe as a civilkit event.
Talking to the embed
The embed and the page around it talk with postMessage. The embed answers only its parent page
(event.source === window.parent) and checks every value; the page should check that a message comes from
https://civilkit.io (or its own copy).
| Message | Direction | Meaning |
|---|---|---|
{type: 'civilkit-ready', sample, inputs} | embed to page | The form is built. inputs lists each input: name, kind (number, select, radio, check), label, unit, value, and min, max, step or options. |
{type: 'civilkit-results', sample, values} | embed to page | After each calculation. values maps each name to {value, unit, text}: a number where the value is one, and the text as shown. |
{type: 'civilkit-embed-height', height} | embed to page | The embed’s content height in pixels, after every layout change. |
{type: 'civilkit-error', errors} | embed to page | A civilkit-set was refused in full or in part, with the reasons. |
{type: 'civilkit-set', values: {L: 8}} | page to embed | Sets inputs by name, then calculates. |
{type: 'civilkit-get'} | page to embed | Sends the last results again. |
A value set from the page must name an input of the sheet. A number must be finite and, for a slider, within its
bounds; a choice must be one of its option values (or labels); a checkbox takes true, false, 1 or 0. The valid
values of a message are applied and the others are reported in one civilkit-error.
const frame = document.querySelector('iframe[src*="embed=1"]');
window.addEventListener('message', (e) => {
if (e.origin !== 'https://civilkit.io' || e.source !== frame.contentWindow) return;
if (e.data.type === 'civilkit-results') console.log(e.data.values.M_max.text);
});
// Once the frame says it is ready:
frame.contentWindow.postMessage({ type: 'civilkit-set', values: { L: 8, w: 20 } }, 'https://civilkit.io');
Privacy
The embed runs the same engine as the app, in the reader’s browser. It sends nothing to a server, sets no cookies, loads no analytics and stores nothing: the app’s own saved settings, files and open tabs are not changed by it. It does not register the app’s offline service worker either (a reader who already uses the app gets the embed from the same offline copy).
Using CivilKit Calcs from an AI assistant (MCP)
An AI assistant such as Claude can run your calculations in CivilKit Calcs through the public MCP server at
https://civilkit.io/mcp. MCP (the Model Context Protocol) is the standard way assistants
connect to tools. With the server added, an assistant can write a sheet, run it in the same engine as the app, read the values
and units back, check a hand calculation, convert units, and look things up in this guide, the function reference and the samples.
The server is read only and needs no account. It stores nothing: each request is calculated and answered, and that is all.
Adding the server
Claude Code, in a terminal:
claude mcp add --transport http civilkit-calcs https://civilkit.io/mcp
Claude Desktop and claude.ai: Settings > Connectors > Add custom connector, with the URL https://civilkit.io/mcp.
Other clients (Cursor, VS Code, and any client that takes a remote server): add an HTTP (Streamable HTTP) server with that URL. In a JSON configuration it usually looks like this:
{
"mcpServers": {
"civilkit-calcs": { "type": "http", "url": "https://civilkit.io/mcp" }
}
}
A client that runs only local servers can reach it through the mcp-remote bridge:
{"command": "npx", "args": ["-y", "mcp-remote", "https://civilkit.io/mcp"]}.
Opening https://civilkit.io/mcp in a browser shows a short page with the same instructions.
What the assistant can do
| Tool | What it does |
|---|---|
calcs_evaluate_sheet | Runs a sheet and returns each quantity (name, value, unit, the rendered line, its note and line number), the errors with their lines, and the calculation as text. Input lines (L: ? 6 m) can be given other values. |
calcs_evaluate_calcpad | The same for a Calcpad worksheet (.cpd text). |
calcs_check_hand_calc | Recomputes a calculation with real units and compares it with your answer, within a tolerance. |
calcs_convert_units | Converts a value: 25 kN/m^2 -> kPa. |
calcs_search_functions, calcs_function_help | The function, unit and command reference of the reference chapter. |
calcs_search_docs, calcs_get_guide_page | Search this guide and read a chapter. |
calcs_list_samples, calcs_get_sample | The sample sheets, with the link that opens each in the app. |
calcs_sheet_syntax | The full sheet syntax reference, so the assistant writes sheets that compile. |
There are also two prompts, check my hand calc and write a sheet, for clients that show prompts as commands.
Things to ask, for example:
- “Check my calculation: a 6 m simply supported beam with 12 kN/m, I got M = 56 kN·m.”
- “Write a CivilKit Calcs sheet for the bearing pressure under a 2 m square pad footing with 800 kN, and run it.”
- “Open the gable frame sample and tell me the thrust with a rigid ridge.”
The assistant gets the same numbers as the app. This sheet, run by calcs_evaluate_sheet, returns Mstar as 54 with the unit
kN*m, and its line as 4:
L: 6 m | span
w: 12 kN/m | design load
Mstar: w * L^2 / 8 -> kN*m | maximum bending moment
A sheet the assistant writes can be pasted into the app (File > New) to see it rendered, print it or export it.
Limits
The server is public, so it limits what it runs:
- A sheet or worksheet can be up to 64 KB, an expression up to 4 KB.
- Each address can make 120 requests and 30 calculations a minute.
- A calculation that runs longer than a few seconds is stopped. Loops with fixed bounds can make up to 200,000 passes.
- Python blocks,
#include,#read,#writeand#appendare not run: the server has no files and no network. Such a worksheet runs in the app, where everything stays in your browser. - Plots and diagrams are not drawn; the result is text and numbers.
Privacy
The server is stateless. What you send is calculated and answered; nothing is stored or logged, there are no cookies, accounts or sessions, and every request runs in a fresh copy of the engine. Requests are counted per address for the rate limit only. The app itself never sends your work anywhere: the MCP server is a separate service for assistants.
Samples tour
The Samples browser (File > Samples…, or the Resources tab) lists 151 worksheets, with groups, a search box and a preview. Opening a sample puts it in a new tab, where you can change it freely: nothing you do changes the original. A sample that has input fields carries an input form tag. The Samples browser never runs a sample’s Python; its preview shows the source, and opening the sample asks first.
Sheets
Written in the sheet format. They are listed first.
| Group | What is in it |
|---|---|
| Sheet syntax (15) | Beam bending, a short column, a floor-load table with vectors and matrices, a moment diagram with a plot, LaTeX prose, mixing with raw Calcpad and loops, beam and cantilever deflection, a three-span beam explorer with Python and Plotly, a beam deflection derived with the Symbolic dialog, polynomial roots, principal stresses, natural frequencies of a shear frame, principal axes of a section, and the thrust of a gable frame with a pinned or a rigid ridge. |
| Templates (7) | Sheets with input forms: a simply supported beam check, a cantilever with a tip load, rectangular column slenderness, a pad footing bearing pressure check, pipe flow, a retaining wall (sliding and overturning) and a pump and pipeline operating point. Each carries the input form tag. See Templates with inputs. |
| Plots and diagrams (16) | A plot gallery of implicit curves, functions and polylines on a grid, an animated beam with a moving load (Play, Pause, a slider), and fourteen sheets with a diagram drawn from text next to the numbers: a design check as a flow diagram, a load path, the design states of a beam, a review and sign-off sequence, a construction programme (Gantt chart), a dead load share (pie chart), a cost plan (treemap), a site risk matrix (quadrant chart), a bending moment chart (XY chart), the energy flow through a pump (Sankey), a footbridge brief (mind map), requirements traceability, concrete strength gain (timeline) and section shapes (class diagram). |
| 3D plots (5) | A plate deflection surface, a column interaction surface, a space frame in 3D lines, a mode-shape explorer with a dropdown, a 3D bar chart of footing reactions. |
| Physics (1) | A tennis ball in flight: drag, spin and the sideways force from spin, integrated in a Python block. |
Calcpad worksheets
The bundled worksheets are the CalcpadCE examples, with their input fields written as #UI, plus a
few of our own.
| Group | What is in it |
|---|---|
| Beams (26) | Cantilevers, propped cantilevers, simply supported and fully restrained beams under point, moment, uniform, linear and partial loads; deflection of a cantilever and of a simply supported beam; a continuous beam by the force method. |
| Reinforced concrete (27) | Bars and areas, bending and shear of rectangular and tee sections, columns under axial force and one or two-way bending, an interaction diagram, serviceability, two-way slab panels with every edge condition, punching shear, detailing for ductility. |
| Steel (3) | Section properties of I-sections: by formula, from a catalogue with a drawing, from an Excel catalogue. |
| Loads (4) | Snow, wind and footing-pad optimisation worksheets. |
| Frames (3) | Plane frames with prismatic and tapered members, and a multi-storey frame. |
| Dynamics (4) | Free vibrations of a tapered pole, with plain, Plotly and SVG animations; drop-weight impact on a beam. |
| Nonlinear (2) | A prestressed truss with material and geometric nonlinearity, and a nonlinear truss with an animation. |
| Soil mechanics (1) | Stress and deformation in soil. |
| Sections (1) | Properties of a built-up section. |
| Maths and plotting (31) | Getting started (calculating, functions and plots, unit conversion), matrices (creation, indexing, operators, structural and maths functions), interpolation, custom units (currency and information), numerical differentiation and integration, roots and systems of equations, Newton’s method with animation, a Monte Carlo estimate, elastic solutions and finite-element worksheets for deep beams and slabs. |
| Python (5) | A beam moment diagram with matplotlib, a function plot with matplotlib, a beam explorer with Plotly, a continuous beam with Python results in raw JavaScript Plotly, and a plane truss by the stiffness method. |
Good places to start:
- Getting Started: Calculating, Functions and Plots and Units and Conversion, to see the Calcpad language at its simplest.
- Template: simply supported beam check (the Templates group), to see an input form: press Input and change the span.
- Beam bending with real units (sheet) and Bending moment diagram (sheet), the shortest complete sheets.
- Design check as a flow diagram and the other sheets of the Plots and diagrams group, to see a diagram written as text next to the calculation it describes. See Diagrams.
- Matrix worksheets, for a tour of the vector and matrix functions.
- Beam Explorer: Plotly from Python, for the Python and Plotly route.
The samples that were written for other design practices apply rules specific to those practices. Read a sample as an example of the technique and check its assumptions before reusing a number.
Troubleshooting and FAQ
Reading an error
An error appears in the results where the line would, as a red paragraph, in the Errors dialog, and as an underline in the editor. For a sheet, the line number is the sheet line. Click the line number in the report to jump to the source.
| Message | Cause and fix |
|---|---|
Undefined variable or units: "x" | The name is not defined above this line, or it is misspelled, or a unit is misspelled. Names are case sensitive. A sheet renames some names (phi is φ); a >> line may use either spelling. |
Inconsistent units: "m + s" | You added or compared quantities of different dimensions. Fix the formula. |
Invalid units: "maximum" (or Invalid symbol: "#" on a heading) | The text is being read as a Calcpad worksheet, not as a sheet, so | means a unit conversion and # a directive. The <!--sheet--> marker is missing from the first line. Put it back. |
Cannot rewrite existing units: kip | A custom unit (.kip = ...) has the name of a built-in unit. Choose another name. |
The matrix has complex eigenvalues. | eigenvals, eigenvecs and eigen return real values only. Use ceigenvals and ceigenvecs. See Vectors and matrices. |
Inconsistent units: "unitless" and "m" in a plot | The plot variable carried a unit. Write plot f(x * 1 m) for x in 0..6. See Plots. |
#UI does not support expressions unless 'allowExpression' is true. | The value in a #UI line is not a plain number. Use allowExpression or move the formula into a sheet line. In a sheet, an input line with ? takes a number only: 2*3 m is an error on its line. See Input forms with #UI and Templates. |
The condition could not be evaluated, so the block is unresolved... | An #if or if condition has an error (usually an undefined name). The block runs no branch. |
Python was not run | You answered “Not now” to the Python question. The refusal is remembered until the Python code changes; edit it to be asked again. |
Sheet syntax: ... in red | The sheet compiler found a bad plot line, an unclosed $$ or similar. The marker is on that line. |
Things that go quietly wrong
- Angles. The default is degrees.
sin(π)is not zero in degrees mode. Put>> #radin the sheet when you work in radians and passπor radian values. A plot ofsin(x)over0..2*πin degrees mode is nearly flat. gis a gram. Onlyπandeare built in. Insert the gravity constant from the Insert tab (g = 9.80665m/s^2) before you usegas an acceleration.- A variable called
m,sorL. After a numbermis still the metre. A variable calledmis a variable when it stands alone. In Pythonexportnames, avoid names that are units. - Rounding. The result shows two decimals by default (Settings, Calculation, Decimals), and a number below
one keeps three significant figures (
0.163,0.0856). The number inside is full precision: a utilisation of 1.004 is shown as1, and a check on it (if util <= 1) still sees 1.004. - Every line of a sheet shows an error such as
Invalid symbol: "#". The first line of the file is not<!--sheet-->. Older versions wrote the comment of Save values above that line; the current one writes it under the marker. Delete the stray first line, or put the marker back as the first line. See Templates. - A drop-down opens showing the wrong option. In a raw
>> #UIline the default matches none of thevalues, so the first label is shown while the calculation uses the default. Make the default one of the values. A?line cannot do this. See the known limits in Input forms with #UI. - My saved values are not used. A saved value belongs to the input’s name. If the input was renamed, the old value is ignored. Preview always shows the defaults; use Input or Report.
Frequently asked questions
Is anything sent to a server? No calculation is. The page is static files and the engine runs in your browser. The only network requests are loading the app, and loading Plotly for an interactive chart.
Does it work offline? Yes, after one visit. See Saving.
Can I use my own Python packages? No. A small numpy, matplotlib and Plotly stand-in is built in, and what is missing raises a named error. See Python blocks.
How do I share a calculation? Send the .sheet or .cpd file, or export Word, Excel or PDF.
Can I move a sheet to the Calcpad language? Yes, with Convert to Calcpad. The other direction does not exist.
Why did the interactive chart disappear from my PDF? Print and export cannot run Plotly. Draw a static copy with matplotlib as well.
Is it free? Yes. It is open source under the MIT licence, and the page runs from static files. See Credits and licences.
Where do I report a problem? On the project’s issue tracker at https://github.com/mageaustralia/civilkit-calcs . Say what you typed, what you saw and what you expected.
Appendix: keyboard shortcuts
On a Mac use Cmd where this page says Ctrl. The Resources tab has a Shortcuts button that lists the main ones in the output panel.
| Shortcut | Action |
|---|---|
| Ctrl+S | Save |
| Ctrl+Shift+S | Save as |
| Ctrl+O | Open (the desktop app; a browser keeps its own Open command) |
| Ctrl+Alt+X | Calculate. F5 does the same in the desktop app; in a browser F5 reloads the page. |
| Ctrl+Z, Ctrl+Shift+Z | Undo, redo |
| Ctrl+F | Find in the editor |
| Ctrl+Shift+B | Show or hide the sidebar (the desktop app; in a browser use Resources > Sidebar) |
| Alt+Z | Wrap long lines |
| Ctrl+Shift+E | Convert the selected expression to a formula line (see Editing) |
| Shift+Alt+F | Format Document (tidy a sheet) |
| F12 | Go to the definition of the name under the cursor |
| Shift+F12 | Find references |
| F2 | Rename the variable, function or macro under the cursor everywhere in the worksheet (see Editing) |
| Ctrl+; | Variable palette: search every variable and function with its value. Enter inserts the name, Alt+Enter goes to its definition |
| Tab | Accept the highlighted completion (Enter makes a new line) |
| Ctrl+Space | Open the completion list by hand |
| Ctrl+B, Ctrl+I, Ctrl+U | Bold, italic, underline in text lines of a Calcpad worksheet |
| Enter, Ctrl+Enter | Apply an in-place edit (Ctrl+Enter for prose) |
| Esc | Cancel an in-place edit, or close a dialog |
| Enter, Shift+Enter | In the Symbolic dialog: run, new line |
Keys the browser keeps. In a browser the keys that browsers use themselves are left to the browser, so that the page never takes them: Ctrl+L, D, R, N, P, T, W, Q and J, Ctrl+0 to 9 (tab switching and zoom), Ctrl+plus and Ctrl+minus, and Ctrl+Shift+V. Menu commands such as New sheet are on the ribbon. Save (Ctrl+S) is the page’s own.
On a phone there are no shortcuts; see Editing.
Appendix: deviations from CalcpadCE
CivilKit Calcs reproduces CalcpadCE’s output exactly unless a behaviour is listed in the project’s
DEVIATIONS.md. Each entry there names the behaviour, why it differs and the test that pins it. This
page is a summary for users.
Behaviour that differs
| CalcpadCE | CivilKit Calcs | |
|---|---|---|
A failing #if condition | A condition that throws (a misspelled name) is false, so the #else branch runs without a word. | The block is left unresolved: no branch runs, and an error paragraph says why. |
| Plot loops | A plot grid with a NaN step never ends. | Grid loops stop after 100,000 lines. Finite grids are unchanged. |
| Scripts in a worksheet | Any <script> in a worksheet runs from any address. | Scripts run only from a library list (Settings, Advanced, Libraries), under a content security policy, with exact file addresses and integrity hashes. A script that is not on the list is replaced by a note naming its address. Scripts cannot send data anywhere. The print frame has no scripts. |
| C-style operators | The desktop app converts ==, !=, >=, <=, %%, &&, ||, <<, <* when it reads a file. | The browser does the same when it opens a worksheet. |
| Input fields | Many examples use the old name = ? {default} form. | The bundled samples are rewritten with #UI, and the editor offers a “Convert to #UI” quick fix. |
| Select, radio and checkbox | A select or radio that names a text box does nothing in the web front end. | It fills the text boxes it names and recalculates; the choice is carried into the Report, PDF and Word. |
| Radio and drop-down defaults | A radio group or drop-down marks its default by comparing text, so a default with a divided unit such as 25kN/m finds no option and opens with nothing chosen (a drop-down shows its first label). | The default is found by value: the division sign, middle dot, raised digits and ^ are compared as plain marks, and 1.0 equals 1. |
| Nested blocks | A loop nested in an expression block cannot update the enclosing block’s variable. | It can. |
| Units in arrays | A vector or matrix writes the unit on every element. | It writes the unit once after the bracket ([16; 12] ft). #settings {"unitPerElement": true} restores the old display. |
| Eigenvalues | eigenvals, eigenvecs and eigen take only a matrix of the symmetric type. | They take any square matrix; a symmetric literal no longer needs copy(A, symmetric(n), 1, 1). ceigenvals and ceigenvecs return complex eigenvalues and eigenvectors. |
| Markdown tables in Word | A table without the bordered class has no rules. | A Markdown pipe table is ruled. |
| Word export | SVG pictures are embedded alone. Numbered lists lose their numbers. | An SVG is also written as a PNG for readers that lack SVG. Ordered lists are numbered. Unknown elements keep their content. |
| Print header and footer | The server prints title, date and page numbers. | The browser prints; its own header and footer apply. |
#write | Overwrites on disk. | Keeps the file in the library and downloads it when its content changes. |
Additions
- The sheet format (Markdown prose,
name: valuelines, LaTeX): a front end to the Calcpad language that is not part of CalcpadCE. - The Excel export, with native charts.
- Python blocks, with matplotlib-style and Plotly-style plotting.
- The Symbolic dialog.
- The worksheet importer.
- Rich-text editing of Markdown prose in the results.
- Sheet inputs:
L: ? 6 mand its drop-down, radio and checkbox forms, which compile to#UI, and sliders with bounds (L: ? 6 m [2 .. 12 step 0.5]), for which#UItakesmin,maxandstep. - SI prefixes on every SI unit (
3 mN,5 µm,40 nF): CalcpadCE lists the prefixed units one by one and lacks many. - Folding sections and key results in the sheet format (
## Workings {collapse},{key},{key results}). - Model bindings: a comment that ties an input to a quantity of a structural model, with a marker in the report. No model is connected yet.
- A ribbon interface, a phone layout and an installable, offline app.
Not supported
Raster (PNG) plots (the web version draws SVG), the #ProjectPath and #LibraryPath roots (they are
accepted and ignored), compiled .cpdz worksheets, and step-by-step execution (#pause, #input).
Numerical differences
The platform’s maths library supplies sin, exp, pow and friends, where CalcpadCE uses the .NET
runtime’s, so the last printed digit of a result can differ. #write line endings are \n.
The full text, with the tests, is in DEVIATIONS.md.
Appendix: credits and licences
Credit
CivilKit Calcs is built on CalcpadCE, the MIT-licensed continuation of Calcpad by Nedelcho Ganchovski (Proektsoft) and contributors. The worksheet language, the editor’s language support (tokenizer, linter, prettifier, snippet library), the Word export path and the example worksheets all come from that work. This project reimplements the calculation engine, the editor services and the Word export in Rust and changes the web front end. It is not affiliated with the CalcpadCE authors.
The CalcpadCE version this work follows, and the commit its engine was ported from, are recorded in the
NOTICE file of the repository. The “About” button on the Resources tab shows the version of the app
you are running.
Licence
The project is under the MIT licence. The copyright is held by the CalcpadCE contributors, by Nedelcho
Ganchovski (2014 onwards) and by the CivilKit Calcs contributors for the changes and the Rust
reimplementation. The text is in the LICENSE file.
What the app includes
The licences of every package in the build are listed in THIRD_PARTY_LICENSES.md. None is outside
the MIT, Apache, BSD and ISC families. The ones that matter to a user:
| Component | Used for | Licence |
|---|---|---|
| CalcpadCE | The worksheet language, front end, samples | MIT |
| Monaco editor | The source editor | MIT |
| KaTeX | Typesetting LaTeX in sheets and the Symbolic dialog | MIT |
| MicroPython | The Python runtime of Python blocks | MIT |
| Plotly.js | Interactive charts (loaded from its CDN when needed) | MIT |
| jspreadsheet CE | The editable grid in input forms | MIT |
| Markdig (a port of part of) | Markdown in the engine | BSD 2-Clause |
| Fonts: JuliaMono, Jost, DejaVu | The editor and the report | their own licences, bundled with them |
Sources
- The app: https://civilkit.io/calcs/
- The code, the issue tracker and the changelog: https://github.com/mageaustralia/civilkit-calcs
- CalcpadCE: https://github.com/imartincei/CalcpadCE